CSP Generator
Build a Content-Security-Policy that is worth deploying — starting in report-only.
What you provide
Result
PASSReport-only policy generated
The nonce placeholder has to be replaced with a fresh random value on every response and repeated on each script tag — a static nonce is no better than allowing inline script, since an attacker can read it from the page. Report-only is the right way to start: the policy is evaluated and violations reported without anything being blocked, so you find out what the site actually loads before breaking it. Run it for a fortnight, read the reports, then switch the header name.
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' 'nonce-{RANDOM}' 'strict-dynamic'; style-src 'self'; img-src 'self' data:; object-src 'none'; base-uri 'self'; frame-ancestors 'none'; form-action 'self'; upgrade-insecure-requests- Directives
- 9
- Script policy
- nonce + strict-dynamic
- Mode
- report-only
- Clickjacking
- frame-ancestors 'none'
What this cannot tell you
- Calculated in your browser. Nothing you enter is uploaded or logged.
- A policy is only as good as what it allows. Choosing unsafe-inline for scripts removes most of the protection, and the generator says so rather than quietly emitting it.
- The nonce placeholder must be replaced with a fresh random value on every response, generated server-side. A static nonce is no better than allowing inline script.
- Cannot see what your site actually loads. Report-only mode is how you find that out, and it is the default here for that reason.
- A policy is one layer. It reduces the impact of injected content and does nothing about the injection itself — output encoding and input validation are still the fix.
Take this with you
How this calculation works
Pick how strict each resource type should be and the header is assembled with a locked-down default: same-origin by default, no plugins, no framing, and forms restricted to your own origin. The script directive is where a policy is won or lost. A nonce with strict-dynamic lets you allow the scripts you deliberately include while blocking anything injected into the page — which is the entire point. Choosing unsafe-inline instead allows exactly what a policy exists to stop, and the tool says so rather than emitting it quietly. The default is report-only, because you cannot know what a real site loads until the browser tells you.
What the results mean
- Report-only
- The policy is evaluated and violations reported, and nothing is blocked. The right way to start: you find out what breaks before it breaks.
- Nonce
- A random value generated per response and repeated on each script tag you trust. It must change every time — a fixed nonce can be read from the page and reused.
- strict-dynamic
- Lets a trusted script load further scripts without listing every domain. It is what makes a nonce policy practical on a real site.
- 'unsafe-inline'
- Allows any inline script to run — including the one an attacker injected. It makes the script directive close to decorative.
- frame-ancestors
- Stops your pages being framed by another site, which is what clickjacking needs. It supersedes the older X-Frame-Options header.
Common problems and fixes
- The policy broke my site
- That is why report-only exists. Switch the header name back, collect violations for a fortnight, and add what is genuinely needed before enforcing.
- Inline event handlers stopped working
- onclick attributes are inline script and no nonce can cover them. Move them to addEventListener — the migration is the main cost of adopting a policy and it is a one-off.
- Third-party tags need unsafe-inline
- Many vendors say so and fewer need it. strict-dynamic covers most tag managers, because the trusted loader inherits the trust. Check before weakening the whole policy for one vendor.
- Reports are flooded with browser-extension noise
- Extensions inject into pages and generate violations you cannot fix. Filter them by source rather than loosening the policy.
Frequently asked questions
What does Content-Security-Policy actually protect against?
Mainly cross-site scripting. It tells the browser which sources of script, style and other content are legitimate, so a script injected into your page — through a comment field, a vulnerable dependency, a compromised third-party tag — does not run. It also restricts framing, form targets and plugin content. It is damage limitation rather than prevention: the injection still happened, and the policy stopped it being useful.
Why is 'unsafe-inline' a problem?
Because a browser cannot tell an inline script you wrote from one an attacker injected — both are simply inline script in the page. Allowing it therefore allows precisely the thing the policy is for. A nonce solves it properly: only scripts carrying the current response's random value run, and an attacker injecting content cannot know it in advance.
Should I start with report-only?
Yes, on any site that already exists. Real sites load things nobody remembers adding, and an enforcing policy written from imagination breaks something on day one. Report-only tells you what is actually there, at no risk, and switching to enforcing afterwards is a one-word change.
Put this on your own site
Free to embed, no attribution required beyond the source link the frame carries itself. It runs entirely in your visitor's browser, sets no cookies and loads no third-party script.
<iframe src="https://runthetests.com/embed/csp-generator/" width="100%" height="560" style="border:1px solid #e5e5e5;border-radius:8px" title="CSP Generator" loading="lazy"></iframe>
Preview it at https://runthetests.com/embed/csp-generator/. Embedded pages are marked noindex, so yours stays the canonical copy — not this one.
More in WebSec
- Cookie Security CheckAudit Set-Cookie headers for Secure, HttpOnly and SameSite.
- Password Policy GeneratorWrite a password policy that reflects current guidance, not 2005.
- Permissions-Policy BuilderBuild a Permissions-Policy header that constrains the third-party code you did not write.
- security.txt CheckerCheck a security.txt file against RFC 9116, including the expiry that makes it valid.
- SRI Hash GeneratorGenerate a Subresource Integrity hash for a script or stylesheet.