Content-Security-Policy Explained
How CSP restricts what a browser is allowed to load, and why it's one of the most effective defenses against XSS.
Core Concept
Content-Security-Policy is an HTTP response header that tells the browser exactly which sources of content — scripts, styles, images, fonts — are allowed to load on a page.
It acts as a second line of defense against cross-site scripting, since even if malicious script gets injected into a page, CSP can prevent it from executing or exfiltrating data.
Core CSP Directives
A CSP policy is built from a set of directives, each controlling a different resource type.
- script-src — controls allowed JavaScript sources
- style-src — controls allowed CSS sources
- img-src — controls allowed image sources
- connect-src — controls allowed fetch/XHR/WebSocket targets
Default-src Fallback
The default-src directive acts as a fallback for any resource type not explicitly specified, making it a useful baseline restriction.
Common Implementation Pitfalls
CSP is powerful but notoriously easy to misconfigure in ways that either break functionality or weaken protection.
- unsafe-inline permitted out of convenience, defeating much of CSP's XSS protection
- Overly broad wildcards like script-src *
- Forgetting third-party analytics or ad scripts, breaking functionality
Nonces and Hashes for Inline Scripts
Modern CSP implementations avoid unsafe-inline by using cryptographic nonces or content hashes to allowlist specific inline scripts.
A nonce is a random value generated per page load and included both in the CSP header and the script tag — only scripts with a matching nonce are permitted to run.
Per-Request Nonces
Because nonces must be unique per page load, they can't be guessed or reused by an attacker injecting their own script tag.
Report-Only Mode for Safe Rollout
CSP supports a report-only mode that logs violations without actually blocking content, making it safer to roll out incrementally.
- Content-Security-Policy-Report-Only header for testing
- report-uri or report-to directives to collect violation data
- Gradual tightening once violation reports are clean
Real-World Implementation
CSP deployment is now a standard security hardening step across serious web applications.
- Financial and authentication pages enforcing strict CSP
- Report-only rollouts on complex legacy applications
- Automated CSP violation monitoring integrated into alerting
A well-tuned CSP meaningfully reduces the impact of an XSS vulnerability even when the underlying injection flaw hasn't been fully fixed yet.
Common Mistakes to Avoid
A few common mistakes weaken CSP's effectiveness even when it's technically deployed.
- Including unsafe-inline for convenience, defeating much of CSP's XSS protection.
- Using overly broad wildcards like script-src * instead of specific allowlisted origins.
- Forgetting third-party analytics or ad scripts, breaking functionality after deployment.
- Skipping report-only mode and enforcing a strict policy without prior testing.
- Failing to update the policy as new third-party integrations are added over time.
- Overlooking the frame-src directive when only configuring script and style sources.
- Assuming a report-only policy provides real protection while testing.
- Failing to update CSP when adding a new third-party integration to the site.
- Overlooking the strict-dynamic keyword, which simplifies CSP for modern script loading patterns.
- Assuming CSP reporting endpoints require no rate limiting of their own.
- Failing to review third-party CSP violation reports for signs of browser extension interference.
- Overlooking that some browser extensions inject content that can trigger CSP violations unrelated to the site.
Best Practices Checklist
These practices lead to a genuinely effective, well-maintained CSP.
- Deploy in report-only mode first to discover legitimate resource usage before enforcing.
- Use nonces or hashes for inline scripts instead of unsafe-inline.
- Allowlist specific trusted origins rather than relying on broad wildcards.
- Monitor CSP violation reports continuously, not just during initial rollout.
- Update the policy deliberately whenever a new third-party integration is added.
- Configure frame-src explicitly alongside script and style directives for complete coverage.
- Treat report-only mode strictly as a testing phase, not a substitute for enforcement.
- Update CSP configuration as part of the standard checklist for adding new integrations.
- Consider strict-dynamic for simplifying CSP configuration with modern script loading patterns.
- Apply rate limiting to CSP reporting endpoints to avoid being overwhelmed by report volume.
- Review violation reports for patterns suggesting browser extension interference rather than real issues.
- Filter known extension-related noise when reviewing CSP violation reports for genuine issues.
Frequently Asked Questions
Frequently asked questions about Content-Security-Policy.
Does CSP prevent XSS vulnerabilities from existing?
No — it limits what an injected script is allowed to do once it's on the page, acting as a second line of defense rather than a fix for the underlying flaw.
Why is unsafe-inline considered risky in a CSP?
It significantly weakens XSS protection by allowing any inline script to execute, defeating much of what CSP is designed to prevent.
What's the safer alternative to unsafe-inline for scripts?
Using per-page nonces or content hashes allowlists specific inline scripts without opening the door to all inline script execution.
How should a CSP be rolled out safely?
Starting in report-only mode lets you discover legitimate resource usage and violations before enforcing a policy that might break the site.
What does the default-src directive do?
It acts as a fallback for any resource type not explicitly specified by a more specific directive, providing a useful baseline restriction.
Does CSP cover iframes as well as scripts and styles?
Yes, through the frame-src directive, which is easy to overlook if a policy only addresses script and style sources.
Does report-only mode actually block anything?
No — it only logs violations, providing zero actual protection until the policy is switched to full enforcement.
Should CSP be revisited when adding a new third-party script?
Yes — any new integration needs to be reflected in the policy, or it risks being silently blocked or breaking the CSP's protective value.
What does strict-dynamic do in a CSP policy?
It simplifies script authorization by trusting scripts loaded by an already-trusted script, reducing the need to allowlist every individual source explicitly.
Can browser extensions trigger false CSP violation reports?
Yes — some extensions inject content that can trigger violations unrelated to the site's own code, worth filtering out during report review.
Can browser extensions cause false CSP violation reports?
Yes — some inject content that triggers violations unrelated to the actual site code, worth filtering out during report review.
Analyze Security Headers
Run a security headers scan to see a domain's current Content-Security-Policy configuration.
Launch Tool →