Drupal Content Security Policy configuration: what the CSP module does and when you need it
A security review or audit has flagged a missing Content-Security-Policy header, or your team has just added third-party scripts for analytics, chat or video and needs to control what the browser will load. The CSP module for Drupal sets a Content-Security-Policy response header that tells the browser which sources of scripts, styles, images, frames and other resources the page may use, and it reports or blocks anything outside that list. Drupal core does not ship a complete CSP policy by default, so the header only exists once you configure it. The CSP module is a contributed project licensed under GPL-2.0-or-later, and it is installed and maintained like any other contributed code, which means its release status should be checked before adoption.
A policy cannot be copied from a template. It has to be designed against what the site actually loads: its own theme assets, inline scripts added by modules, fonts, embedded video, tag manager containers, consent banners and any administrative tools used by editors. Each allowance widens what an attacker could abuse if injection occurs, so the list should be short and each entry should have an owner who can say why it is there. Before writing the policy, export a list of every external host the site calls in a normal browser session, including pages with forms and logged-in admin pages, and confirm which of them are required. Your web server or CDN may also set headers, so confirm where the header is produced to avoid two conflicting values.
A Content-Security-Policy complements updates, input handling and access control. It limits the damage of script injection and some data exfiltration, but it does not fix a vulnerable module, a broken access check or an unsafe text format. Keep core and contributed code current through the security advisory process, and treat the CSP as one layer among several. The companion sections on security headers and configuration review cover the wider header set and release checks that should run alongside this work.
Which CSP module settings fit which site type
This table compares the main Content-Security-Policy choices for a Drupal site: rollout mode, how inline scripts are allowed, where reports go, how embeds and tools get allowances, and whether the header is set in Drupal or at the edge. Read each row against your site type, then check the option names on the CSP module project page before writing them into a plan.
| Setting | When it fits | Maintenance cost |
|---|---|---|
| Report-only mode | First rollout on any site, or a site with many third-party scripts nobody has inventoried | Someone must review violation reports and decide each one before enforcing |
| Enforcing mode | After report-only has run long enough that known legitimate sources are all allowed | Low day to day, but new embeds or tools break until their sources are added |
| Nonce-based inline scripts | Sites that must keep inline scripts from core, themes or modules and can make Drupal render nonces | Needs theme and module code to carry the nonce; cache and template changes must be tested |
| Hash-based inline scripts | A small, fixed set of inline scripts that rarely change | Every change to an inline script alters its hash and needs a policy update |
| Reporting endpoint in a log or SIEM | Regulated sites that need violation reports kept for review and evidence | Endpoint capacity, retention and triage ownership must be set up and kept running |
| Per-section allowances for embeds, analytics and admin tools | Sites with video, maps, tag managers or a dashboard that only some pages load | Each allowance is a standing exception; review them when vendors or tags change |
| Header set in Drupal | Sites where the policy should vary by route, role or content, and the team owns the Drupal codebase | Policy lives beside code, so changes ship with releases but cached pages need care |
| Header set at the web server or CDN | Static-leaning sites, or teams where the edge already manages security headers | Policy is easy to miss during Drupal changes; nonces are harder to supply from the edge |
How to roll out CSP in report-only mode before enforcing
This sequence takes a Drupal site from an unknown set of scripts, styles and frames to a Content-Security-Policy that is enforced, with a documented allowlist and a tested way back. Each step produces evidence that the policy matches what the site actually loads.
Inventory third-party resources and inline code
Before any header is set, the team lists every origin and code path the site relies on. Developers review custom themes and modules for inline scripts and styles, and the content team lists embeds such as video players, maps, forms and social widgets. Analytics, tag managers, chat widgets and fonts are recorded separately because they often load further resources. The inventory is done when every page template and editor-facing feature has an owner and a documented list of origins, so that no allowance is added later on guesswork.
Install and configure the CSP module in report-only mode
The team installs the contributed Content Security Policy module through Composer like any other project dependency, then configures a policy in report-only mode so browsers log violations without blocking anything. The policy starts from the inventory, and a reporting endpoint is set so violation reports reach a location the team reads. Confirm the exact module settings, including how report-only and enforced policies are selected and where reports are stored or forwarded, against the module's Drupal.org project page and the installed version. The step is complete when a test page sends a deliberately blocked request and the report appears at the endpoint.
Collect and triage violation reports on staging
Testers walk every template, content type and editor workflow on staging with the browser console open and reports collecting. Each report is classified as a missing allowance, an inline script that needs refactoring, a browser extension noise item, or a genuine unexpected load that should be investigated. Engineers record the blocked directive, the source file and the page where it occurred. The step closes when every report from the test pass has a classification and an owner, and the list of open items is small enough to review in one meeting.
Repeat collection on production traffic
Staging rarely reproduces every real user path, so report-only mode is kept running on production after the staging pass. The team reviews reports on a regular schedule, filters out known browser extension noise, and looks for new origins that appear after content or marketing changes. Reports are grouped by page and directive so that a single change, such as a new tag manager container, shows up as one item. The step is done when several review cycles pass without new unclassified origins, which the team confirms against its own traffic volume and schedule.
Add allowances for embeds, analytics and admin tools
Each approved origin is added to the policy with the narrowest directive that covers it, such as script sources for analytics, frame sources for video embeds and connect sources for APIs. Admin tools, including Drupal's toolbar, Views UI and any Gin or Claro theme assets, are tested and allowed deliberately rather than by broadening the policy for the whole site. Inline scripts that cannot be removed are handled with nonces or hashes where the module supports them, and this approach is confirmed with the developers. The step is complete when the policy is updated, a new staging pass produces no reports for approved features, and each allowance has a recorded reason.
Test editor and admin paths before enforcing
Editors and administrators run their real tasks in report-only mode: creating and previewing content, using media libraries, managing menus, running configuration imports and using any custom forms or AI tools in use. These paths often load scripts that public pages never touch, so they are tested by the people who use them, using accounts with the same roles as production. Any remaining violations are fixed or allowed before enforcement. The step closes with a signed-off checklist from the content and site administration owners showing each path was exercised with no blocking expected.
Switch to enforcement with a rollback plan
The team switches the header from report-only to enforced mode during a planned change window, with the previous report-only header and configuration saved so it can be restored quickly. The rollback steps are written down: who can revert the setting, where the change is made in configuration or deployment tooling, and how the team confirms the revert worked. Reports continue to be watched for the first days after the switch. The step is complete when enforcement has run through a full review cycle without an unplanned block, and the rollback procedure has been tested once on staging.
Allowances for embeds, analytics and admin tools
Embedded video and map providers usually load a frame from their own domain and then fetch scripts, styles, images and media from several more hosts. Because the frame is a separate document, the main concern is the frame-src directive, which controls which origins a page may embed in iframes. Most providers also need img-src for thumbnails and media-src where video files are streamed, and some need connect-src for player API calls.
- Name the exact origin: allow the specific host the provider publishes, such as the player or embed domain, rather than a parent domain with a wildcard.
- Check each directive separately: a video embed often needs
frame-src,img-srcandmedia-src, and a missing one shows up only as a blocked console message. - Avoid wildcard subdomains: an entry like
*.example.comlets any subdomain a third party or attacker controls load content into your pages. - Limit the embed to the templates that use it: where the platform allows, scope the allowance to the content types or pages that embed the provider instead of the whole site.
- Confirm the provider's current host list: embed providers change domains and add CDN hosts, so ask the vendor for the list and recheck it after updates.
After each change, load a page with each embed type in a browser, confirm the player or map renders, and review the console and the CSP report endpoint for blocked resources from the same host.
Analytics platforms and tag managers are the highest-risk allowance because they load scripts that can run any code the vendor or its partners later publish. Each tag added through a tag manager can introduce new hosts, so the policy must be tied to a reviewed list of tags rather than to the tag manager alone. Typical directives are script-src for the loader, connect-src for beacons and measurement calls, and img-src for pixel requests.
- Allow the loader, not the whole tag library: list the script host the analytics product requires and avoid allowing general-purpose script CDNs.
- Use nonces or hashes where possible: a tag manager that injects inline snippets may need a nonce, and the Drupal CSP module and the platform's documentation should be checked for supported options.
- Treat `unsafe-inline` and `unsafe-eval` as exceptions: if a vendor requires them, record the reason, the owner and a review date.
- Review each new tag: require a change request that lists the new hosts, the data collected and the consent basis before the CSP is extended.
- Align with consent handling: a tag that loads before consent is recorded should be blocked by policy, not only by a banner.
After each change, confirm the tag fires in a test browser, check the network panel for requests to every host you allowed, and verify that blocked hosts stay blocked when consent is withheld. Ask your vendor to confirm which hosts their current tag set uses.
Administrative interfaces such as Views UI, the CKEditor toolbar, and Layout Builder rely on JavaScript, inline styles and sometimes third-party assets. Those components were built for trusted users, and a policy written for anonymous visitors can break them in ways that look like application bugs. The safer approach is to scope relaxed rules to administrative paths or roles where the platform supports it, and to keep public pages on a stricter policy.
- Separate the policy by path or role: where you can, apply the relaxed policy only to administrative routes so anonymous pages keep the strict rules.
- Expect inline styles: editor and layout tools often set inline styles, so
style-srcmay need a documented allowance on admin paths only. - Avoid `unsafe-eval` for convenience: if a tool fails under the policy, identify the specific script before widening the rule.
- Document why each exception exists: record the tool, the directive, the role affected and the owner who approved it.
- Limit editor-supplied embeds: CKEditor embeds that accept arbitrary HTML widen the attack surface, so restrict who can use them and which formats allow them.
After each change, test every administrative workflow an editor uses, including saving a view, editing a text field with the toolbar and rearranging a layout, and confirm that public pages still show the stricter header.
Security and operational risks of a CSP rollout
A Content-Security-Policy header protects a Drupal site only while it stays accurate. The risks below share one root cause: the policy drifts away from what the site actually loads, either because it is loosened to stop breakage or because nobody updates it when code changes. Each card names the mitigation and the release check that keeps it in place.
Overly broad allowances
Adding unsafe-inline, unsafe-eval or wildcard hosts such as https: to silence violations removes most of the protection the header was meant to give. A policy that allows any script source will not stop injected code from running. During the report-only phase, group reports by directive and blocked host, and require a written reason for each new source before it enters the enforced policy. Review the directive list at every release, since a single broad entry added during a rushed fix often outlives the incident.
Inline script breakage in contributed modules
Contributed modules and themes sometimes inject inline scripts or styles that the policy blocks, which breaks menus, forms or admin screens. Before enforcing, test each module that renders JavaScript on the public and admin paths, and list the nonce or hash requirements it creates. Prefer fixes that move scripts into attached libraries over broad inline allowances. Confirm the patch status of any module you need to change, because a local patch to contributed code must be re-applied after every update.
Report volume flooding logs
A report-only policy sends a browser report for every violation, and ad blockers, browser extensions and third-party tags can generate large volumes quickly. Without limits, reports fill the database or log pipeline and hide the violations that matter. Route reports to a dedicated endpoint or log channel, filter known noise such as browser extension origins, and set a retention period that your log policy allows. Confirm with your logging team how reports are stored and who may read them, since reports can contain URLs with personal data.
Policy drift from new modules and tags
Each new module, Google Tag Manager container, chat widget or embed can require a new source, and the policy falls behind unless the change is tracked. Drift shows up as a steady stream of blocked resources after a release, or as teams adding exceptions in production. Keep the policy in version-controlled configuration, add a CSP review to the merge request template for any change that adds a script, frame or font source, and run an automated check on the staging site that compares loaded hosts with the allowed list.
Conflicts with CDN and web server headers
The module, the web server and a CDN or reverse proxy can each set a Content-Security-Policy header. Browsers apply every policy they receive, so a stricter header from one layer can block resources that the Drupal policy allows, and a second header can silently replace the one you tested. Decide which layer owns the header, remove duplicates at the others, and verify the final response headers from outside the network after each change to the web server or CDN. Confirm the behavior of your specific CDN before relying on it.
Missing checks in the release pipeline
A CSP that is correct on the day of launch can break after a core or contributed update, a theme change or a configuration import. Add the policy to the release checklist: confirm the response header on the staging build, run the browser console and report endpoint checks on key pages, and block the release when new violations appear on critical flows such as login, checkout or content editing. Assign one owner for the policy so that changes are approved, not made ad hoc.
Keeping a Drupal CSP maintainable through upgrades and new modules
The policy only stays correct if it lives in version control and has a named owner. Keep the CSP settings from the CSP module in configuration that is exported with the rest of the site, so every change to a directive, a source allowance or a report-only setting goes through a commit and a review. Store the reporting endpoint and the enforce or report-only switch with the same care, because a change to either can silently turn a working policy into a blocker or a blind spot. Assign one person as the owner of the policy and a second as their backup, and make that owner the only route for allowance requests. Each request should name the script, frame or connection it needs, the page or feature that uses it, the business reason and the review date, so that a request does not become a permanent exception by default.
Review the policy at each Drupal update. Bugfix releases arrive on the first Wednesday of each month and security releases on the third Wednesday, according to the Drupal core release schedule, so plan a short CSP check in the same cycle as your patch window. After each update, compare the violation reports against the previous period, look for new inline scripts or styles introduced by core or a contributed theme, and confirm that the policy still matches what the front end loads. Core and contributed updates are the most likely source of new violations, so treat a new violation after an update as a change to investigate, not as noise to suppress. Record what you checked in the release notes so auditors and the next owner can see the decision trail.
Add CSP review to the intake process for every new contributed module, theme and third-party library. Before installation, ask what scripts, styles, fonts, frames or external endpoints the module adds, whether it injects inline code, and whether it loads assets from a CDN. Test the module in report-only mode on a staging copy and record the allowances it needs before it reaches production. Decide whether the module's needs fit the policy or whether the feature should wait. Confirm with each vendor and project maintainer how their code handles inline scripts, since this varies between projects and releases, and document the answer in the module's intake record.
Limits to confirm in your environment before committing
A Content Security Policy only works if the module, the Drupal version, the theme and the hosting path all cooperate. The cards below list the points to confirm before you commit to a policy, since each one can change whether the header is emitted, enforced or even accurate.
CSP module release and Drupal compatibility
Check the current release of the Content Security Policy module on its Drupal.org project page and confirm it supports the Drupal core version you run or plan to run. Module compatibility lags core releases, so a version that works today may not survive your next core upgrade. Ask the module maintainers or your partner to confirm the supported core range in writing, and record the version in your build so upgrades can be tested against it.
Inline scripts from themes and modules
Inline <script> blocks and style attributes emitted by your theme or contributed modules are the most common reason an enforced policy breaks pages. Audit rendered pages in report-only mode and list every inline source. Decide whether each one can move to an external file, receive a nonce, or needs a documented hash allowance before you enforce.
Caching and reverse proxy effects
A header set by Drupal is only as reliable as the path it travels. Confirm that your reverse proxy, CDN and page cache pass the header through unchanged, and that cached pages do not carry a nonce or policy from another request. If nonces are used, check that the cache layer varies or bypasses them correctly. Headers added at the web server or CDN can also duplicate or conflict with module-set headers.
Browser support expectations
Confirm which browsers your users run, including any managed or older devices, and test the directives you plan to use against them. Some directives and reporting features are not supported equally across engines. Write down the browser matrix you accept, and treat anything outside it as a documented exception rather than an untested assumption.
Drupal version support window
Drupal 10 reaches end of life on December 9, 2026, according to the core release schedule. A policy tuned to a version that leaves support during your rollout creates rework and an unpatched platform. Confirm your target core version, the planned upgrade date, and whether the CSP module will be supported on that version before you commit to a long enforcement timeline.
PHP runtime support
Confirm that the PHP runtime on your application servers matches the requirement of your Drupal version. Drupal 10 requires PHP 8.1 or later, Drupal 11 requires PHP 8.3 or later, and Drupal 12 requires PHP 8.5 or later. Older PHP runtimes are not supported, so a header configuration tested on an unsupported runtime does not give you a valid baseline.
Questions buyers ask about Drupal CSP configuration
What drives the cost of a Content Security Policy rollout on Drupal?
The cost is driven mostly by how many script, style, frame and connect sources the site loads and how many of them are first-party code. Each third-party embed, analytics tag, chat widget, payment form or admin tool needs its origin reviewed, its behavior tested, and an allowance written and justified. Sites with inline scripts, legacy theme code or many contributed modules that inject markup usually need more analysis and refactoring before enforcement is safe. Ask any quote to itemize discovery, report-only analysis, policy changes in code or configuration, cross-browser and functional testing, and handover documentation. Ongoing review of new embeds is a recurring cost that many teams underestimate.
How long does it take to roll out a CSP on a Drupal site?
Duration depends on the number of distinct origins the site uses, how much inline script and style exists, and how many people must sign off on each change. Report-only mode needs enough real traffic and page coverage to surface violations across templates, logged-in views and admin pages, so the observation window is set by traffic patterns rather than by the work itself. Teams with few third-party services and clean templates move faster. Sites with many embeds, multiple domains or content editors who insert markup by hand take longer. Ask for a written plan with phases, exit criteria for moving from report-only to enforcement, and the owner of each decision.
What does the work need from our developers, content owners and analytics owners?
Developers must provide access to the theme, the Drupal configuration, the web server or CDN where headers may be set, and a non-production environment that mirrors production. They make the decisions on inline scripts and move them into files where feasible. Content owners need to confirm which embeds editors actually use, such as video, maps, social posts or forms, because each one needs an allowance. Analytics and marketing owners must list every tag, pixel and consent tool, including who added it and what data it sends. Without these inputs, report-only results are hard to interpret and enforcement breaks features in production.
Can an internal team configure CSP on Drupal without outside help?
Yes, an internal team with Drupal and front-end skills can do it, provided it has time to read violation reports, change templates and test widgets across browsers. The hard part is rarely the header itself. It is deciding which origins are legitimate, refactoring inline code, and keeping the policy current as editors and vendors add features. Teams that lack a security engineer or that run several sites often find the review cycle is where progress stalls. A partner can take on the analysis and documentation, or run a fixed-scope rollout while your team keeps ownership. Either way, agree in writing who approves each allowance.
Does a Content Security Policy replace Security Kit or Drupal updates?
No. A Content Security Policy is one control among several. The Security Kit module covers a wider set of HTTP security headers and related mitigations, and it should be reviewed alongside the CSP so the two do not conflict. Neither one fixes vulnerabilities in Drupal core or contributed modules. Drupal core and contributed projects publish security advisories, and the Drupal Security Team uses a Wednesday security release window, so patching remains necessary. A CSP limits what injected or unexpected script can do in the browser, which reduces impact but does not remove the flaw. Treat it as defense in depth and keep a patch process in place.
What does ongoing upkeep of a Drupal CSP look like?
Upkeep is recurring work. Someone must review violation reports, decide whether each new source is legitimate, and update the policy before a feature ships. Every new embed, analytics tag, module upgrade or theme change can add a source or an inline script, so the policy should be part of the release checklist. Plan periodic reviews of the allowance list to remove retired vendors, and retest after Drupal core or major contributed module upgrades. Ask any retainer or internal plan to define who receives reports, how often the list is reviewed and where the policy is documented.
Why should a CSP start in report-only mode, and how long should it stay there?
Report-only mode sends violations to a reporting endpoint without blocking anything, so you learn what the site loads before users see breakage. It is the safe starting point for almost every Drupal site with third-party code. The length of time in report-only mode depends on coverage, not a fixed number of days: you should exit only after the reports you review are explained, the important pages have been exercised, and the remaining violations are either fixed or allowed on purpose. Confirm with your engineers which reporting endpoint and log retention you will use before starting.
What should we check before accepting a CSP quote?
Check that the written scope names the pages and templates covered, the report-only observation plan, the exit criteria for enforcement, and the browsers and features tested. Confirm who owns each allowance and who signs off on new third-party origins. Ask whether the work includes refactoring inline scripts, setting headers at the web server or CDN, and handover documentation for your team. Confirm the reporting endpoint, where logs are stored and who can read them. Any figure or duration in the quote should be traceable to these items, not a general estimate.
How DeployOpen scopes and delivers a Drupal CSP configuration
Every Drupal CSP engagement starts with a fixed scope agreed in writing before any work begins. DeployOpen does not publish a price list, so the quote follows from that document. The scope should name the Drupal site or sites, the web server or CDN that will send the header, the third-party domains the site already uses, the admin tools that need allowances, and the environments in scope. It should also state what is deliberately excluded, such as a rewrite of the front-end build or a review of custom JavaScript beyond what the policy needs to allow. Ask for the scope to list deliverables (an inventory, a report-only policy, an enforcing policy, a runbook) and the acceptance checks for each one, so the quote can be compared line by line with an internal estimate.
Delivery follows the same order as the rollout described above. The first phase is an inventory of every script, style, font, frame, image and connect source the site loads, collected from the rendered pages inside the client's own infrastructure, including staging and any non-production copies that editors use. The second phase is a report-only policy with reports sent to an endpoint the client controls, followed by triage of violations with the client's developers and content owners. Work is carried out in the client's cloud accounts, data centers or air-gapped networks, so no site traffic or violation reports leave the client's environment unless the client chooses that. Confirm where reports will be stored, who can read them, and how long they are kept before the work starts.
Optional retainers cover what happens after the first enforcing release, because CSP allowances drift as editors add embeds, marketing teams add tags and modules change. A retainer can cover policy reviews after planned releases, re-running the inventory, reviewing new third-party sources and keeping the test suite that checks key pages current. DeployOpen does not make claims about audit outcomes, certifications or compliance results from a CSP configuration. Where an assessment is needed, the client's auditor or certification body makes that judgment, and DeployOpen supplies the configuration, change records and evidence the assessment requires. Ask any provider, including DeployOpen, to confirm in writing which of these items are included in the fixed scope and which are priced as a retainer.

