How to Fix a Missing Content-Security-Policy Header
If your audit flagged a missing Content-Security-Policy, you're in good company — it's the single most common serious gap we see. CSP is also the strongest defence you have against cross-site scripting (XSS), so it's worth getting right.
What CSP actually does
A Content-Security-Policy header tells the browser which sources of content are allowed to load and run on your page. If an attacker manages to inject a <script> tag, a good CSP simply refuses to execute it — the injection becomes inert. Without CSP, the browser trusts whatever ends up in the DOM.
Don't enforce on day one
The mistake that scares people away from CSP is shipping a strict policy straight to production and watching half the site stop working. Avoid that. Start in report-only mode, which logs violations without blocking anything:
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
Let that run for a few days, collect the violation reports, and you'll see exactly which third-party sources (analytics, fonts, CDNs) your site legitimately needs.
A sane starting policy
Once you know your real dependencies, enforce a policy built around them. A reasonable baseline for a typical site:
Content-Security-Policy:
default-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline';
img-src 'self' data:;
object-src 'none';
base-uri 'self';
frame-ancestors 'none'
A few notes:
object-src 'none'andbase-uri 'self'close off two commonly forgotten injection vectors.frame-ancestors 'none'also handles clickjacking, so you may not need a separateX-Frame-Optionsheader.- Avoid
'unsafe-inline'onscript-src. If you have inline scripts, move them to files or use a nonce.
Using nonces for inline scripts
If you can't remove inline scripts, generate a random nonce per request and reference it:
Content-Security-Policy: script-src 'self' 'nonce-r4nd0m';
<script nonce="r4nd0m">/* allowed */</script>
The browser only runs inline scripts carrying the matching nonce, so injected scripts — which won't know the nonce — are blocked.
Where to set it
Set the header at your web server or framework so it applies everywhere:
# nginx
add_header Content-Security-Policy "default-src 'self'; object-src 'none'; base-uri 'self'" always;
# Apache
Header always set Content-Security-Policy "default-src 'self'; object-src 'none'; base-uri 'self'"
Verify
Re-run your audit after deploying. A passing result means CSP is present without 'unsafe-inline' or 'unsafe-eval' on scripts — the configuration that actually stops XSS rather than just looking like it does.
More guides
HSTS Explained — Stop SSL Stripping with Strict-Transport-Security
HTTPS alone doesn't stop downgrade attacks. HSTS does. Here's what the header means and how to deploy it safely.
Securing Cookies — HttpOnly, Secure, and SameSite Explained
Three small flags turn a leaky cookie into a hardened one. Here's what Secure, HttpOnly and SameSite do and how to set them.