Free CSP generator
Build a Content-Security-Policy header directive by directive, then paste an existing one to see what it is missing. Both the builder and the checker run on your device in plain JavaScript. Your policy names your CDNs and API hosts, and none of it is sent to a server.
Strict locks everything down with default-src 'none' and a nonce, then allows each content type back on. It is the policy you want to end up with.
default-srcFallback for every fetch directive you do not set explicitly.
script-srcWhere JavaScript may be loaded from, and whether inline script runs.
style-srcWhere stylesheets may be loaded from, and whether inline style is allowed.
img-srcWhere images may be loaded from. Add data: for inline SVG and base64 images.
connect-srcEndpoints that fetch, XHR, WebSocket, and EventSource may talk to.
font-srcWhere web fonts may be loaded from.
frame-srcWhich origins your page may embed in an iframe.
frame-ancestorsWho may embed your page. This is the modern replacement for X-Frame-Options.
form-actionWhere a form on your page is allowed to submit.
base-uriRestricts the <base> tag, which an injected element can otherwise use to hijack relative URLs.
object-srcPlugins such as Flash and Java. Almost every site should set this to none.
block-all-mixed-content is deprecated and upgrade-insecure-requests replaces it. Keep it only if you still support browsers that ignore the upgrade.
generated in your browserThis value is a placeholder to show the shape of the header. Your server must generate a fresh nonce for every response and put the same value on the matching script tags.
Content-Security-Policy: default-src 'none'; script-src 'self' 'nonce-GENERATED_PER_RESPONSE' 'strict-dynamic'; style-src 'self'; img-src 'self' data:; connect-src 'self'; font-src 'self'; frame-src 'none'; frame-ancestors 'none'; form-action 'self'; base-uri 'none'; object-src 'none'; upgrade-insecure-requests
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'self' 'nonce-GENERATED_PER_RESPONSE' 'strict-dynamic'; style-src 'self'; img-src 'self' data:; connect-src 'self'; font-src 'self'; frame-src 'none'; frame-ancestors 'none'; form-action 'self'; base-uri 'none'; object-src 'none'; upgrade-insecure-requests">
add_header Content-Security-Policy "default-src 'none'; script-src 'self' 'nonce-GENERATED_PER_RESPONSE' 'strict-dynamic'; style-src 'self'; img-src 'self' data:; connect-src 'self'; font-src 'self'; frame-src 'none'; frame-ancestors 'none'; form-action 'self'; base-uri 'none'; object-src 'none'; upgrade-insecure-requests" always;
Header always set Content-Security-Policy "default-src 'none'; script-src 'self' 'nonce-GENERATED_PER_RESPONSE' 'strict-dynamic'; style-src 'self'; img-src 'self' data:; connect-src 'self'; font-src 'self'; frame-src 'none'; frame-ancestors 'none'; form-action 'self'; base-uri 'none'; object-src 'none'; upgrade-insecure-requests"
Copied to clipboard
How the CSP generator works
Set your sources
Start from the strict preset, then allow back the hosts your site really loads script, style, images, and API calls from.
Take the snippet
The header is assembled as you toggle, with copy-ready forms for the HTTP header, the meta tag, Nginx, and Apache. Deploy it report-only first.
Check what you have
Paste a live policy into the Check tab and every weak source and missing directive comes back ranked by severity with the fix.
Private by design: nothing leaves your browser
A Content Security Policy is a map of your infrastructure. It names your CDN, your API hosts, your payment provider, and every analytics vendor you have ever bolted on. That is a useful document for an attacker and it should not be uploaded to a stranger's server to be linted:
100% client-side
Building the header and parsing a pasted one are plain string operations in JavaScript. The nonce comes from crypto.getRandomValues, your browser's own secure generator. No network request carries your policy.
Nothing stored or logged
There is no account and no analytics on what you paste. Reload the page and the policy is gone from memory.
Your site is never fetched
The checker reads only the text you paste. It never requests your domain, so nothing about the check appears in your access logs or your WAF.
What a good policy does
script-srcis where the security lives. A nonce or a hash on your inline scripts is what actually stops injected script from running.object-src 'none'andbase-uri 'none'close two attack paths that cost you nothing, because almost no site uses either feature.frame-ancestorsis what stops clickjacking, and it does not inherit fromdefault-src, so leaving it out leaves you open.- Report-only mode lets you watch what a policy would break for a week or two before it breaks anything.
Built for developers and security-conscious teams
Anyone shipping a header that decides which code the browser will run on their site. BlockSurvey takes the same position on research data with zero-knowledge surveys, where responses are encrypted before they ever reach a server.
Frontend developers
Work out which directive is blocking your bundle, and get a policy that survives a script loader without falling back to 'unsafe-inline'.
Security & IT teams
Grade the CSP on a site you are reviewing, and hand the owner a finding list with a concrete fix rather than a score.
Teams heading into an audit
A CSP shows up in SOC 2 and pentest reports. Build one, ship it report-only, and close the finding before the assessor opens it.
Building something that handles sensitive data?
BlockSurvey runs on zero-knowledge surveys, so the responses you collect are never sold or mined. Responses are encrypted on the respondent's device, so the server stores nothing readable.
More free privacy tools
Browse all privacy toolsThese tools run in your browser because that is how we build everything. The same idea, applied to research: privacy-first surveys with end-to-end encryption.