CSP doesn't prevent XSS injection itself — that remains escaping's job, covered in the previous lesson. Instead, it limits the damage a successful injection can do, by restricting which resource sources the browser will actually trust.
1Restricting Trusted Resource Sources
A Content-Security-Policy header declares, per resource type, which origins the browser should actually trust — script-src 'self' https://trusted-cdn.com means only scripts from the page's own origin or that specific trusted CDN are permitted to load and execute; scripts from any other source are blocked by the browser outright.
This creates a genuine second layer of defense: even if an XSS vulnerability somehow allows an attacker to inject <script src="https://evil.com/malware.js"> into the page (a failure of the escaping covered in the previous lesson), the browser still refuses to actually load and execute that script, since evil.com isn't a declared trusted source — significantly limiting the real-world damage a successful injection can cause.
2Delivering The Policy: Header Versus Meta Tag
CSP is most robustly delivered as an actual HTTP response header, configured at the server or CDN level — this applies the policy before any HTML parsing begins and supports the full range of CSP directives and reporting features.
A <meta http-equiv="Content-Security-Policy" content="..."> tag provides an HTML-level alternative for situations lacking direct server header configuration control, though it has some limitations (it can't be used for certain directives like frame-ancestors, and it only takes effect once that specific meta tag is parsed, slightly later than a true header would apply).
3Why unsafe-inline Undermines The Entire Point
By default, CSP blocks inline <script> blocks and inline event handler attributes (onclick="...") — a genuinely powerful protection, since the vast majority of real-world XSS injections take exactly this inline form. Adding 'unsafe-inline' to a script-src directive removes precisely this protection, permitting any inline script to execute, including one an attacker successfully injects.
This directive commonly appears in real CSP configurations because migrating an existing codebase away from inline scripts and handlers takes real refactoring effort — but its presence should be understood as a significant, deliberate weakening of the policy's core script-injection protection, worth treating as a temporary migration step rather than a permanent configuration.
4Step-by-Step Breakdown
A Safety Net For When Escaping Fails. Escaping, covered in the previous lesson, is the primary XSS defense — but defense-in-depth means having a backup layer for when a mistake slips through. Content Security Policy is exactly that: an HTTP header telling the browser which sources of scripts and other resources it should actually trust, limiting damage even if malicious content gets injected.
CSP Restricts Trusted Resource Sources. A Content-Security-Policy header declares which origins are allowed to supply scripts, styles, images, and other resource types — content from anywhere else is blocked by the browser, even if it somehow got injected into the page's HTML.
What CSP Actually Restricts. If an XSS vulnerability somehow allows an attacker to inject <script src="https://evil.com/malware.js">, what does a correctly configured CSP do?
- →It prevents the injection from happening in the first place, replacing the need for escaping
- →The browser refuses to actually load/execute that script, since evil.com isn't a declared trusted source
- →It has no effect once injection has already occurred
Delivered Via HTTP Header Or Meta Tag. CSP is most commonly and robustly set via an actual HTTP response header (Content-Security-Policy: ...), configured at the server or CDN level — though a <meta http-equiv="Content-Security-Policy"> tag in the HTML itself is also supported for cases without direct server header control.
CSP Delivery Mechanisms. What are the two ways a Content Security Policy can be delivered to the browser?
- →A cookie value and a JavaScript global variable
- →An HTTP response header (preferred) or a <meta http-equiv> tag
- →Only an HTTP header; there's no HTML-level alternative
unsafe-inline Undermines The Whole Protection. Allowing 'unsafe-inline' in a script-src directive permits any inline <script> block or inline event handler to execute, including ones an attacker might inject — largely defeating CSP's core protection against script injection, which is exactly why it's called 'unsafe'.
The unsafe-inline Directive. Why does including 'unsafe-inline' in a script-src directive significantly weaken CSP's core protection?
- →It doesn't actually weaken anything meaningfully
- →It permits any inline script block to execute, including ones an attacker might successfully inject
- →It only affects image loading, unrelated to scripts
CSP Mastered. You now understand CSP as a defense-in-depth backup to the escaping covered in the previous lesson — restricting trusted resource sources, delivered via HTTP header or meta tag, and why the unsafe-inline directive should be avoided since it undermines the entire protection.
Add A Content Security Policy. A meta CSP tag restricts which sources scripts and other resources may load from.
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)
1CSP Has No Direct Accessibility Dimension But Protects Against Injected Content That Could Actively Disrupt Assistive Technology
A blocked malicious script can't hijack focus, inject fake dialogs, or otherwise interfere with a page's accessibility, indirectly protecting the experience CSP-covered pages provide to assistive technology users.
SEO Implications
- 1
A Correctly Configured CSP Is Increasingly Referenced As A Security Best-Practice Signal In Technical SEO Audits
While not a direct ranking factor, CSP presence and quality are commonly checked in comprehensive technical security/SEO audits as part of overall site trustworthiness assessment.
Best Practices
Configure CSP As An HTTP Header Rather Than A Meta Tag Whenever Server-Level Control Is Available
It applies earlier, supports the full directive set, and is generally considered the more robust, complete delivery mechanism.
Avoid 'unsafe-inline' In script-src, Treating Its Presence As A Signal Of Incomplete Migration Rather Than A Stable End State
It removes CSP's core protection against the most common real-world XSS injection pattern, significantly reducing the policy's actual protective value.
Frequent Bugs
A security audit flags a site's CSP as providing minimal real protection despite being present.
Check for 'unsafe-inline' in script-src; if present, plan a migration to remove inline scripts/handlers and eliminate this directive.
A CSP configured via meta tag doesn't seem to block certain resource types as expected.
Some directives (like frame-ancestors) aren't supported via meta tag at all; switch to an HTTP header for full directive support.
Real-World Examples
A Reasonably Strict Production CSP Header
A site's CSP restricting scripts and styles to trusted, explicitly declared origins, without unsafe-inline.
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted-cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;