CSP Generator
Build a Content-Security-Policy directive by directive — with real nonce and hash sources, a Report-Only toggle and the server snippet for it.
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; object-src 'none'; base-uri 'self'; frame-ancestors 'none'
7 directives · 162 B
Downloads as plain text. The header name is on the same line as the value, so paste the value alone into a config that names the header for you.
Press ? for shortcuts
Do it offline:$
How to use it
- Start from the seeded policy, or import one you already serve — the importer reads a header value and fills the cockpit from it.
- Add directives from the picker and fill each source list: keywords arrive quoted, schemes end in a colon, wildcards lead.
- For inline code, paste the script body to get its sha256 source, or mint a demo nonce — the real one has to come from your server, per response.
- Turn Report-Only on while you find out what breaks, then turn it off once the reports stop arriving.
- Choose the output form, copy it into your server config, and watch for the first request it refuses.
Assemble a Content-Security-Policy one directive at a time, then take the line your server needs: response header, meta tag, nginx, Apache, Express or Caddy. Nonces and sha256 hashes are computed here in the browser. Nothing is uploaded, no address is fetched, and no policy is graded — this page writes the text and tells you what CSP Level 3 does with it.
How it works
`default-src` backs up the fetch directives and nothing else. Name a narrower one and the backstop stops applying there, so `script-src` beats `default-src` for scripts and `script-src-elem` beats `script-src` for `<script>` elements. Ten directives never consult it at all — `base-uri`, `form-action`, `frame-ancestors`, `sandbox`, `report-to`, `report-uri`, `upgrade-insecure-requests`, `block-all-mixed-content`, `require-trusted-types-for` and `trusted-types` — so omitting one leaves it unset.
Inline code runs only if the policy vouches for that exact piece of it. A nonce vouches by matching a random attribute your server puts on both the tag and the header, so it must be minted per response: repeat one and an injected tag can wear it too. A hash vouches by pinning the element's bytes, whitespace included — taken with SubtleCrypto here, printed in the `'sha256-…'` form.
`'strict-dynamic'` rewrites what the rest of that one directive means. Where a browser supports it, the host entries, scheme entries, `'self'` and `'unsafe-inline'` beside it grant nothing; trust propagates instead from a script you already vouched for to whatever it loads. Browsers without support read them normally, so they are marked inert here, never deleted.
Examples
default-src 'self'; script-src 'self' https://cdn.example.com; object-src 'none'; base-uri 'none'; frame-ancestors 'none'Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; object-src 'none'; base-uri 'none'; frame-ancestors 'none'A same-origin starting point with one CDN allowed for scripts. `object-src 'none'` and `base-uri 'none'` are written out rather than left to the backstop.
default-src 'self'; report-uri /csp-report; report-to csp-endpointadd_header Content-Security-Policy-Report-Only "default-src 'self'; report-to csp-endpoint; report-uri /csp-report" always;The same policy in Report-Only, as an nginx line. Both reporting directives are kept on purpose, and the emitted order follows the catalog, not the typing order.
doSomething();'sha256-RFWPLDbv2BY+rCkDzsE+0fr8ylGr2R2faWMhq4lfEQc='The hash source for a one-line inline script. Those 14 bytes are hashed exactly as pasted; add a newline and the answer changes.
default-src 'self'; script-src 'self' https://cdn.example.com; object-src 'none'; base-uri 'none'; frame-ancestors 'none'<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' https://cdn.example.com; object-src 'none'; base-uri 'none'">Edge case — the same policy as a meta tag loses `frame-ancestors`, which a meta-delivered copy ignores. The drop is reported, not silent.
default-src 'self'; script-src 'self'; script-src 'unsafe-inline'default-src 'self'; script-src 'self'Edge case — a repeated directive. The second copy is discarded whole, so the emitted policy is shorter than what was typed.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
Repeats are dropped, never merged
Only the earliest copy of a directive name survives; every later one is discarded intact, so splitting a long source list across two lines loses the second half.
What a meta tag cannot deliver
Framing rules, sandboxing and the reporting directives are ignored when the policy arrives in markup, and the tag has no Report-Only form. Anything in that set needs the response header.
`'none'` counts only on its own
Beside any other entry it is ignored rather than winning the argument, so a list of `'none'` plus a host permits the host.
Where a wildcard may stand
A `*` is allowed as a whole leading label or as the port, never mid-name. A trailing slash on a path matters too: it confines the match to a directory.
Common errors
There is no policy to read: the input is empty, or holds only whitespace and semicolons. A serialized CSP is one or more directives separated by `;` (CSP Level 3 §2.2.1). Start with a directive such as `default-src 'self'`.- What you get from an empty box, or from a pasted line that was nothing but separators.
`default_src` is not a directive name a browser will accept: CSP Level 3 §2.2.1 allows only ASCII letters, digits and `-`, and discards the whole directive when the name breaks that rule. Fix the spelling, or delete the segment.- A `_` where a `-` belongs. A browser throws the whole segment away, so the sources after it protect nothing.
`'self` opens with `'` and never closes it. CSP Level 3 §2.3.1 quotes keyword, nonce and hash sources on BOTH sides, so a browser cannot read this token and ignores it. Add the closing `'`.- Usually a hand-edited header that lost a character. The token is skipped; the directive still applies.
`self` is a CSP keyword written without quotes, so CSP Level 3 §2.3.1 reads it as a HOST source — a machine literally named "self" — and it matches nothing. Write `'self'` with the single quotes.- The classic. Nothing is malformed, so nothing complains at deploy time — the directive simply allows an imaginary machine.
`script-src` was already set earlier in this policy, so this second copy is ignored — CSP Level 3 §2.2.1 keeps the FIRST occurrence of a directive name and discards every later one, without merging them. Move the extra sources into the first `script-src`.- Two teams appending to one header. Whoever writes first wins.
There is no `<meta>` form of a Report-Only policy: CSP Level 3 §3.3 accepts only `Content-Security-Policy` in `http-equiv`, never `Content-Security-Policy-Report-Only`. Deliver Report-Only as a response header, or turn Report-Only off to see the meta tag.- Report-Only and the meta tag cannot be combined, so the tool refuses instead of printing a tag no browser would honour.
FAQ
Does this page check the policy my site is actually sending?
No, and it cannot: there is no address field in the tool, and nothing here reaches the network. It reads what you type or paste, reports what CSP Level 3 says a browser will do with it, and emits the text.
How often does a nonce have to change?
Every response. The value is a promise that only your server could have put it on that tag, so one that survives into a second response can be read once and replayed. Mint at least 128 random bits per response. The value shown here is a demo.
Should the policy go in a header or a meta tag?
Prefer the header. Markup delivery exists for cases where you cannot set one, and it costs framing control, sandboxing, the reporting directives and Report-Only mode. The meta output here names each removal.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Regenerate the policy from the cockpit as it stands.
- ⌘/Ctrl + S
- Download the emitted policy instead of saving the page.
- ⌘/Ctrl + C
- Copy the emitted output while nothing is selected.
- ⌘/Ctrl + Shift + C
- Copy the emitted output regardless of the selection.
- t
- Step to the next theme (single key; inert while typing).
- ? or ⌘/Ctrl + /
- Show this shortcut list.
- Esc
- Dismiss whichever overlay is on top.