What is a Content Security Policy (CSP)?
A Content Security Policy (CSP) is a strict HTTP response header that serves as a secondary defense layer against Cross-Site Scripting (XSS) and data injection attacks. It allows website administrators to declare exactly which dynamic resources (JavaScript, CSS, Images, Fonts) are allowed to load and execute on a given page.
Without a CSP, browsers operate on the "Same Origin Policy" but ultimately assume that any script delivered within the DOM is safe to execute. If an attacker manages to inject a malicious script (e.g., via a compromised comment section), the browser will execute it, leading to stolen session cookies or hijacked accounts. A properly configured CSP blocks this unauthorized code execution entirely.
The Critical Danger of 'unsafe-inline'
The most common mistake developers make is deploying a CSP that contains 'unsafe-inline' inside the script-src directive. This is usually done to make legacy plugins or inline onclick="" HTML handlers work.
This completely invalidates the security of the CSP. As demonstrated in our [Bypass Sim] tab, if an attacker injects a malicious <script>alert(1)</script> tag, 'unsafe-inline' explicitly tells the browser that inline tags are allowed to execute. To achieve an "A+" security grade in our Evaluator, you must extract all inline JavaScript into external `.js` files, or use cryptographic Nonces.
CSP Level 3: 'strict-dynamic'
Historically, developers built CSPs using huge domain whitelists (e.g., script-src https://cdn.example.com https://api.google.com). Maintaining these lists is a nightmare, and they are prone to bypasses.
CSP Level 3 introduces 'strict-dynamic'. This paradigm shifts away from domain whitelisting entirely. Instead, you cryptographically sign your initial root scripts with a dynamic 'nonce-xyz123'. The 'strict-dynamic' directive tells the browser: "If a script has a valid nonce, trust it. Furthermore, automatically trust any new scripts that this trusted script dynamically creates and injects." This makes deploying strict CSPs significantly easier for modern Single Page Applications (SPAs).
The Anatomy of a JSONP CDN Bypass
If your CSP relies on domain whitelists, you might whitelist a popular CDN like ajax.googleapis.com. Our Security Evaluator will flag this as a High risk, and our Red Team Simulator will generate the exact exploit payload for it. Why is it dangerous?
Attackers can bypass the CSP by requesting outdated JSONP endpoints hosted on those CDNs. By injecting a script tag pointing to a JSONP endpoint with a malicious callback parameter (e.g., <script src="https://ajax.googleapis.com/ajax/services/feed/find?v=1.0&q=a&callback=alert(1)">), the CDN will dynamically generate a valid JavaScript file containing the attacker's payload. Since the CDN is explicitly whitelisted in your CSP, the browser executes the payload.
AngularJS & DOM-based Bypasses
Even if an attacker cannot find a JSONP endpoint on a whitelisted CDN, they can often find an outdated version of AngularJS or Vue.js hosted on that same CDN (e.g., cdnjs.cloudflare.com).
If the attacker injects a script tag to load Angular from the trusted CDN, they can then inject HTML that uses Angular's template binding to execute arbitrary JavaScript (e.g., <div ng-app>{{$on.constructor('alert(1)')()}}</div>). This bypasses the CSP because the actual execution is performed by the trusted Angular library, not a raw script tag.
Implementing Nonces at Scale
Check our [Nonce Arch] tab for implementation snippets. To securely deploy a nonce-based CSP at scale:
- Generate per-request: The nonce MUST be generated dynamically on the server for every single HTTP request. Never hardcode or cache a nonce.
- Cryptographic Randomness: Use a secure PRNG (like Node's
crypto.randomBytes()or PHP'srandom_bytes()) and Base64 encode it. - HTML Injection: Pass the nonce from your controller to your templating engine (EJS, Blade, Twig) and inject it into the
nonce=""attribute of your script tags.