Drupal Content Security Policy configuration

A practical guide to planning, rolling out and maintaining a Content-Security-Policy header on a Drupal site using the CSP module, starting in report-only mode.

On this page

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.

SettingWhen it fitsMaintenance cost
Report-only modeFirst rollout on any site, or a site with many third-party scripts nobody has inventoriedSomeone must review violation reports and decide each one before enforcing
Enforcing modeAfter report-only has run long enough that known legitimate sources are all allowedLow day to day, but new embeds or tools break until their sources are added
Nonce-based inline scriptsSites that must keep inline scripts from core, themes or modules and can make Drupal render noncesNeeds theme and module code to carry the nonce; cache and template changes must be tested
Hash-based inline scriptsA small, fixed set of inline scripts that rarely changeEvery change to an inline script alters its hash and needs a policy update
Reporting endpoint in a log or SIEMRegulated sites that need violation reports kept for review and evidenceEndpoint capacity, retention and triage ownership must be set up and kept running
Per-section allowances for embeds, analytics and admin toolsSites with video, maps, tag managers or a dashboard that only some pages loadEach allowance is a standing exception; review them when vendors or tags change
Header set in DrupalSites where the policy should vary by route, role or content, and the team owns the Drupal codebasePolicy lives beside code, so changes ship with releases but cached pages need care
Header set at the web server or CDNStatic-leaning sites, or teams where the edge already manages security headersPolicy 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.

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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.

  6. 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.

  7. 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-src and media-src, and a missing one shows up only as a blocked console message.
  • Avoid wildcard subdomains: an entry like *.example.com lets 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.

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.

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.