Content Security Policy: a practical CSP rollout guide
Content Security Policy limits XSS impact. Learn Report-Only rollout, nonces, strict-dynamic, reporting and how to enforce a production CSP safely.
- AUTHOR
- Karol Rapacz / Penetration Tester (OSCP, PNPT)
- PUBLISHED
- 9 July 2026
- READING TIME
- 11 min read
- TOPIC
- AppSec
Content Security Policy (CSP) lets a browser restrict where a page loads and executes scripts, styles, frames and other resources. A strong policy reduces the impact of some XSS flaws, but the W3C CSP Level 3 specification defines it as defence in depth—not a replacement for output encoding and safe data handling.
The common failure modes are an aggressive header that breaks production or a permissive policy full of unsafe-inline and wildcards that satisfies a scanner while blocking little.
Start with Content-Security-Policy-Report-Only
Report-Only observes violations without blocking resources. Run it on representative traffic for several weeks and separate true dependencies from browser extensions, scanners and noise.
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'; report-to csp-endpoint
default-src is a fallback, but define important directives explicitly. object-src 'none' disables legacy plugins, base-uri constrains the document base URL, and frame-ancestors controls who may embed the page.
Prefer nonces over unsafe-inline
The server generates a random nonce for each response and includes it in the header and trusted <script> tags. The browser executes only scripts with that value.
Content-Security-Policy: script-src 'nonce-RANDOM' 'strict-dynamic'; object-src 'none'; base-uri 'none'
The nonce must be unpredictable, single-use and server-generated. Never keep it in static configuration or cache it across users. Templates must not attach a nonce to attacker-controlled markup.
strict-dynamic allows a trusted script to load additional scripts without a long host allowlist. It still requires control of the loader and compatibility testing.
Directives to design deliberately
script-src, withscript-src-elemandscript-src-attrfor precision;style-src, avoiding broadunsafe-inlinewhere possible;img-src, addingdata:only when required;connect-srcfor APIs, WebSockets and telemetry;frame-srcfor allowed embeds;frame-ancestorsagainst clickjacking;form-actionfor form destinations;object-src 'none'and a constrainedbase-uri;upgrade-insecure-requestsduring a controlled HTTPS migration.
CSP reports need triage
A report identifies the document, blocked directive, source and context. Aggregate events, minimise personal data and define retention. A spike involving a new domain may indicate an application release, injected content or a user extension.
Turn important patterns into regression tests. The pipeline should exercise login, payment, uploads, embedded widgets and analytics under the candidate policy.
Safe rollout sequence
- Inventory scripts, styles, frames, APIs and third parties.
- Enable Report-Only with a cautious baseline.
- Remove inline JavaScript and
evalwhere possible. - Add nonces or hashes for remaining trusted scripts.
- Restrict sources to specific schemes and hosts.
- Test all roles and critical journeys.
- Move to enforcement in controlled stages.
- Keep reporting and alert on new violation patterns.
CSP complements HTTP security headers and application testing, but it does not remove the XSS root cause. Encode output for its context first, then use policy to contain residual failure.
Nonces, hashes and strict-dynamic
A nonce must be random and new for every response; it cannot be a template constant or client-supplied value. A hash suits immutable inline code, but every content change requires a policy update. strict-dynamic lets a trusted script load dependencies, but requires a deliberate bootstrap model and browser-compatibility plan.
CSP reports contain addresses and context, so treat them as telemetry with retention and access controls. Group violations by directive, document and blocked source, filter extension noise, and test login, payments and integrations before moving from Report-Only to enforcement. CSP limits XSS impact; it does not replace output encoding.
Sources: W3C CSP Level 3, OWASP CSP Cheat Sheet, MDN CSP.


