What Is Content Security Policy?
Content Security Policy (CSP) is an HTTP response header that instructs browsers about which resources they're allowed to load on a given page. By explicitly whitelisting trusted sources for scripts, styles, images, and fonts, CSP prevents Cross-Site Scripting (XSS) attacks — one of the most common and dangerous web vulnerabilities.
Even if an attacker manages to inject malicious JavaScript into your page, a properly configured CSP will prevent the browser from executing it.
How CSP Works
You deliver a CSP via the Content-Security-Policy HTTP header (or a <meta> tag, though the header is preferred). The policy consists of directives, each controlling a different resource type:
script-src— Controls where JavaScript can be loaded fromstyle-src— Controls stylesheet sourcesimg-src— Controls image sourcesconnect-src— Controls fetch/XHR/WebSocket destinationsfont-src— Controls web font sourcesframe-src— Controls iframe sourcesdefault-src— Fallback for any directive not explicitly set
A Starter CSP Header
Here's a minimal but meaningful CSP for a site that only loads resources from its own domain:
Content-Security-Policy:
default-src 'self';
script-src 'self';
style-src 'self';
img-src 'self' data:;
font-src 'self';
object-src 'none';
base-uri 'self';
form-action 'self';
This blocks all inline scripts, eval(), and any resource loading from external domains. It's strict — but that's the point.
Handling Real-World Complexity
Most production sites load resources from CDNs, analytics providers, and third-party services. Here's how to handle common scenarios:
Allowing a CDN
script-src 'self' https://cdn.example.com;
Using Nonces for Inline Scripts
If you need inline scripts (common in frameworks), use a cryptographically random nonce generated server-side per request:
script-src 'self' 'nonce-rAnd0mV4lu3';
Then on your <script> tag:
<script nonce="rAnd0mV4lu3">...</script>
Any injected script without the correct nonce will be blocked, even if it uses inline code.
Using Hashes for Static Inline Scripts
For inline scripts that don't change, you can provide a SHA-256 hash instead:
script-src 'self' 'sha256-abc123...=';
Report-Only Mode: Your Safety Net
Deploying a new CSP cold can break your site. Use report-only mode first to see what would be blocked without actually blocking anything:
Content-Security-Policy-Report-Only:
default-src 'self';
report-uri /csp-violation-endpoint;
Violations are sent to your reporting endpoint as JSON objects, letting you audit and fix issues before switching to enforcement mode.
CSP Pitfalls to Avoid
- Don't use
'unsafe-inline'— This negates most of CSP's XSS protection. Refactor to nonces instead. - Don't use
'unsafe-eval'— Disables protection against eval()-based attacks. Avoid dynamic code execution. - Don't use wildcard sources (
*) for script-src — Wildcards allow any external script, defeating the purpose. - Don't forget
object-src 'none'— Flash and plugin-based vectors are still relevant in legacy environments.
Testing Your CSP
Several tools can help you evaluate and improve your CSP:
- Google's CSP Evaluator (
csp-evaluator.withgoogle.com) — Analyzes your policy for weaknesses - Mozilla Observatory (
observatory.mozilla.org) — Full security header scan including CSP grading - Browser DevTools — The Console tab shows CSP violation messages in real time
- Report URI (
report-uri.com) — Managed CSP reporting and analytics
A well-tuned CSP is one of the highest-value security investments you can make. Start in report-only mode, iterate on your policy, then enforce. Your users' browsers will do the heavy lifting.