Free tool, runs in your browser
Build and check a Content-Security-Policy
Edit every directive, add the origins popular services need with one click, or paste the policy you already have and see what is weak. Export it as a header, for Next.js, Vercel, Netlify, Cloudflare Pages, nginx or a meta tag.
HTTP response header
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'; form-action 'self'; base-uri 'self'; object-src 'none'; upgrade-insecure-requestsReport-only logs violations in the browser console without blocking anything. Switch to Enforce once the console is quiet.
Everything runs in your browser. Nothing you type or paste is sent anywhere.
Need HSTS, nosniff, Referrer-Policy and Permissions-Policy as well? Use the security headers generator and paste this policy in place of its CSP.
Policy review
No issues found by these checks.
What a Content-Security-Policy does
A Content-Security-Policy tells the browser which sources your page may load scripts, styles, images, frames and network connections from. If an attacker manages to inject a script tag into your page, a good policy stops the browser from running it or from sending data to the attacker's server.
It is a second line of defence against cross-site scripting (XSS). It does not fix the bug that let the script in, and it does nothing for problems on the server such as open database rules or missing access checks.
| Check in this tool | Why it matters |
|---|---|
| 'unsafe-inline' in script-src without a nonce or hash | Injected inline scripts run, which cancels most of the XSS protection |
| 'unsafe-eval' in script-src | Strings can be turned into code with eval() or new Function() |
| * or https: or data: in script-src | Scripts can load from hosts an attacker controls |
| object-src not 'none' | Plugin content can sidestep script rules |
| Missing base-uri | An injected <base> tag can redirect your relative script URLs |
| Missing frame-ancestors | Other sites can frame your page for clickjacking |
| Missing default-src | Every directive you did not list is unrestricted |
Roll it out without breaking your app
- 1Start with the starter policy, then add a preset for each service you use: payments, analytics, fonts, embeds, error tracking.
- 2Keep the Report-only toggle on and deploy to a staging copy. Report-only logs what would be blocked without blocking it.
- 3Open every important page, sign in, pay, upload. Read the browser console for violations and add only the origins you recognise.
- 4When the console is quiet, switch to Enforce. Keep watching reports for a few days after launch.
Nonces, 'strict-dynamic' and frameworks
The strongest policies allow scripts by nonce rather than by host: the server generates a random value for every response, adds it to the header as 'nonce-…', and puts the same value on each script tag. With 'strict-dynamic', scripts loaded by a trusted script are trusted too, and supporting browsers ignore host lists and 'unsafe-inline'.
A nonce must be new on every response. A value hardcoded into your config gives no protection, because an attacker can read it and reuse it. Frameworks such as Next.js can generate one per request in server code; static hosts cannot, so on a static site use hashes or a host allowlist instead.
Check what your site sends
Read the live policy from a terminal, then paste it into Analyse mode. Only run this against a site you own.
curl -sI https://your-app.example | grep -i content-security-policyFrequently asked questions
Is my policy sent anywhere?
No. Building, parsing and analysing all happen in your browser. Nothing you type or paste is sent, stored or logged.
How is this different from the security headers generator?
The security headers generator sets several headers at once with a simple CSP. This builder is only for Content-Security-Policy and goes deeper: every directive, service presets, report endpoints and an analyser for an existing policy.
Why is 'unsafe-inline' allowed in style-src in the starter policy?
Many UI libraries and frameworks inject inline styles, and blocking them breaks layouts. Inline styles carry far less risk than inline scripts. Remove it if your app works without it.
Can I use a meta tag instead of a header?
Partly. Browsers ignore frame-ancestors, report-uri, report-to and sandbox in a meta tag, and report-only mode is not available there. A response header is better whenever your host lets you set one.
Does a CSP make my app secure?
No single header does. A CSP limits the damage of script injection. Database rules, secret handling and server-side authorization matter more, and a CSP cannot fix any of them.