CSP Fail

This site's CSP

A site that teaches Content Security Policy should be willing to show you its own. This is the exact header this page was served with, read back out of the response.

default-src 'none'; script-src 'nonce-JmBtMFw4P/zNnG/hucxahA=='; style-src 'self'; img-src 'self'; font-src 'self'; connect-src 'self'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'; report-to default; report-uri https://scotthelme.report-uri.com/r/d/csp/enforce

Reload the page. The nonce changes every time — that is the point of it.

Why each part

default-src 'none'

Start from nothing and add back only what the page needs. Every directive below is an explicit exception, which means anything I forget fails closed rather than open.

script-src 'nonce-…'

A fresh 128-bit nonce on every response, and nothing else. No host allowlist to bypass, because there is no host allowlist.

You may notice what is not here: 'strict-dynamic'. Step 6 recommends it, and it is the right answer for most real applications — because most real applications load scripts at runtime, and those scripts cannot carry a nonce. These three sites do not. Both scripts on every page are nonced in the HTML, nothing is inserted afterwards, and there is no host allowlist for the keyword to switch off.

So it would sit in the header doing nothing, which is precisely the dead weight the analyser flags in other people's policies. Put in what your site needs and nothing else — including when the thing you are leaving out is the one you recommend to everybody else.

style-src 'self'

One stylesheet, served from here. No inline styles anywhere on the site, so no 'unsafe-inline' and no need for a style nonce.

img-src 'self'

No data:. The favicon is a real SVG served from /favicon.svg rather than inlined as a data URI, which keeps this directive down to one source. data: is worth avoiding wherever you can: it is how an attacker inlines a whole payload into a URL, and once it is allowed for one resource type it is easy to leave allowed for others.

base-uri 'none'

Nothing on these sites uses a <base> tag, and leaving this unset would let an injected one redirect the nonced script above. See the reference page.

form-action 'none'

Both tools run in the browser and submit nothing, so no form on these sites should ever post anywhere. If one tries, it is not mine.

frame-ancestors 'none'

No reason for anyone to frame these pages.

report-uri and report-to

Every violation on these pages is reported, to a Report URI account, exactly as step 2 tells you to do. A site that spends ten steps arguing for report collection and collects nothing itself would not be worth reading.

The bit people miss

The header is only half of it. Every HTML response here also carries:

Cache-Control: no-store

Without that, a CDN would happily cache one response — nonce and all — and serve it to everyone for the length of the TTL. A per-response nonce would silently become a per-cache-entry nonce, and the policy would look perfect while protecting nothing. It is one of the four ways nonces break, and it is the one that catches careful people.

Think this policy is weaker than it looks? Paste it into the analyser — it grades its own site the same as anyone else's.