What does it do?
CSP is an allowlist for browsers. When your server returns a Content-Security-Policy header, the browser uses it to decide what each page is permitted to load and execute. You list the directives (script-src, style-src, img-src, connect-src and so on) and the origins each directive permits. Anything outside that list is blocked before it ever runs.
A handful of directives do most of the work. script-src controls which JavaScript can run. frame-ancestors controls who can embed your site in an iframe, which is how you stop clickjacking. form-action controls where form submissions are allowed to go, which is how you stop a hijacked form posting credentials to an attacker. base-uri controls the base href, which is how you stop a single injected <base> tag redirecting every relative link on the page.
The reason this matters is that cross-site scripting is the single most common web vulnerability in real breaches. If an attacker manages to inject a <script>tag into your page (through a comment field, a poorly sanitised search box, a third-party widget gone rogue), CSP is the wall that stops it executing. Without CSP the browser will happily run anything it sees inside your origin's page.
Why it matters
Picture a Melbourne e-commerce business running a Magento storefront with a few third-party widgets: a chat tool, a live currency widget, a heatmap script. One of those third-party providers is breached and serves malicious JavaScript from its CDN. The script silently rewrites every checkout form to post a copy of card details to an attacker-controlled domain. Visa Common Point of Purchase alerts surface six weeks later. With a CSP that names exactly the script origins the site needs, plus a connect-srcdirective locking outbound connections to the store's own backend and the payment processor, the rogue script would have been refused by every visiting browser the moment it tried to load.
CSP is also one of the few defences that buys you time during an active incident. If you discover a compromised dependency at three in the morning, tightening the CSP is a five-minute change at the CDN edge and applies to every visitor on the next request. Other layers (rotating credentials, redeploying code, contacting the third party) all take longer. A working CSP is the one lever you can pull immediately to stop the bleed.
How to set it up
The right way to roll out CSP is in report-only mode first, then promote to enforcing. Two response headers, never both enforcing at the same time.
- A starter policy for a typical small business site:
Content-Security-Policy-Report-Only:
default-src 'self';
script-src 'self' https://www.googletagmanager.com 'nonce-{RANDOM}';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
connect-src 'self' https://www.google-analytics.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
report-to csp-endpoint- Deploy the report-only header for a week, watch the report stream, and fix every legitimate violation by adding the origin to the matching directive.
- Replace inline scripts with nonced or hashed scripts wherever possible.
unsafe-inlinein script-src is what makes most CSPs useless. - Once the report stream is quiet, switch the header name from
Content-Security-Policy-Report-OnlytoContent-Security-Policy. - Keep the report endpoint running, since legitimate violations will surface from time to time.
Test by deliberately injecting a benign console.log inline and confirming the browser refuses to run it. Most browsers will show a clear CSP error in the DevTools console.
Common mistakes
- Including
unsafe-inlineinscript-src. It defeats almost the entire point of CSP. - Setting
default-src *as a way to silence the report stream. That is not a policy; that is no policy. - Forgetting
frame-ancestors, which is what actually stops your site being embedded in an attacker's page. - Going straight to enforcing without report-only. Real production sites break in surprising ways the first time CSP is applied.
How AttackEdge checks it
The AttackEdge scan reads the CSP header on every detected host, parses it, and flags missing directives, dangerously permissive ones (unsafe-inline in script-src, wildcard origins), and missing report endpoints. Full methodology on /what-we-check alongside the rest of the security-header coverage including HSTS.