← The ten steps · Step 10 of 10 · 5 minutes
Ship it
Everything from the last nine steps, on one page, in the order you should do it.
The policy
Content-Security-Policy-Report-Only:
default-src 'self';
script-src 'nonce-{RANDOM}' 'strict-dynamic';
style-src 'self';
img-src 'self';
connect-src 'self';
object-src 'none';
base-uri 'none';
form-action 'self';
frame-ancestors 'none';
report-uri <your endpoint>
{RANDOM} is at least 128 bits from your platform's secure random source, generated fresh
on every response, placed on every script tag you render. The response carrying it must be
Cache-Control: no-store.
The order
- Report-only, strict, everywhere. It cannot break anything, so there is no reason to roll it out gradually.
- Wait a week. A full business cycle, including the traffic you do not think about.
- Triage. Discard extension noise. Everything left is a real finding.
- Fix by nonce-ing, not by allowlisting. Widen
img-src,style-srcandconnect-srcas needed; resist wideningscript-src. - Enforce. Move the policy to
Content-Security-Policyand put your next tightening into report-only behind it.
What to watch afterwards
- Report volume over time. A spike means someone shipped something. That is worth knowing the same day.
- New origins. Every one is a third party that appeared on your site without going through you.
- The length of
script-src. If it only ever grows, the policy is decaying. - Your nonce. Two curls, occasionally. Caching layers get added by people who do not know what a nonce is.
How you know you are done
You are not, and that is the correct state. A CSP is not a project with an end date; it is a control that reflects what your site loads, and your site changes. "Done" looks like: an enforced strict policy, a report-only policy one notch tighter behind it, reports going somewhere a human occasionally reads, and someone who notices when the volume changes.
If you only do three things
- Deploy
Content-Security-Policy-Report-Onlytoday. It cannot break anything. - Add
base-uri 'none'; form-action 'self'; frame-ancestors 'none'; object-src 'none'. Four lines, four real attacks, no rollout required. - Get the reports somewhere you will actually look.
The last thing
A policy you cannot see is a policy you cannot trust. Reports are what turn CSP from a header you wrote once into a control that tells you when your site changes underneath you. Send them to Report URI, which sponsors this site, or run your own endpoint — a violation report is a JSON POST and a few dozen lines of code. What matters is that they go somewhere.
Where to go next
Check your policy →
Paste what you have now and see what the analyser makes of it.
When something breaks →
Paste the console error and get the explanation and the fix.
Directive reference →
The detail behind each directive, one page at a time.
Watch it work →
Live demos on the Report URI demo site: script injection, Magecart, form hijacking and XSS, each with the policy off and on.