JWTs are rarely stolen by breaking cryptography.
They are stolen by running malicious JavaScript in the browser.
This is why Content Security Policy (CSP) is one of the most effective — and most misunderstood — defenses for protecting JWTs in modern web applications.
This blog explains how CSP protects JWT, how to configure it correctly, and how to avoid common mistakes.
Why CSP Matters for JWT Security
JWTs are bearer tokens.
If malicious JavaScript can execute, it can:
- Read JWTs from memory or storage
- Intercept
fetch/XMLHttpRequest - Steal
Authorizationheaders - Proxy authenticated API calls
CSP directly limits what JavaScript is allowed to run, where it can load from, and what it can access.
CSP does not protect JWTs by hiding them —
it protects them by preventing malicious code from running at all.
The JWT + Browser Threat Model
Modern JWT exposure typically comes from:
- XSS vulnerabilities
- Compromised third-party scripts
- Tag managers and analytics abuse
- Shadow integrations
- Browser extensions injecting scripts
Once JavaScript runs, JWT protection is lost.
CSP is your last line of defense.
Core CSP Directives That Protect JWT
1. script-src — The Most Important Directive
This controls which scripts are allowed to execute.
❌ Insecure
Content-Security-Policy: script-src *
✅ Secure (Allowlist-based)
Content-Security-Policy:
script-src 'self' https://cdn.yourdomain.com;
This prevents:
- Inline script injection
- Unauthorized third-party scripts
- Dynamic script loading from unknown domains
2. Block Inline Scripts ('unsafe-inline')
Inline scripts are the #1 enabler of XSS-based JWT theft.
❌ Dangerous
script-src 'self' 'unsafe-inline';
✅ Safer (Nonce-based)
script-src 'self' 'nonce-{{RANDOM}}';
Each request generates a unique nonce, and only scripts with that nonce can execute.
This makes injected scripts non-functional.
3. Use Nonces Instead of Hashes for SPAs
For modern SPAs:
Content-Security-Policy:
script-src 'self' 'nonce-abc123';
Benefits:
- Allows controlled inline initialization
- Prevents runtime injection
- Compatible with modern frameworks
Nonces are ideal when JWTs exist in memory.
4. Lock Down connect-src (Protect API Calls)
JWTs are often stolen by exfiltrating data.
Content-Security-Policy:
connect-src 'self' https://api.yourdomain.com;
This prevents:
- Sending tokens to attacker-controlled endpoints
- Silent exfiltration via fetch or WebSockets
Even if a script runs, it cannot leak tokens externally.
5. Restrict frame-ancestors
Prevents clickjacking and token abuse via embedded contexts.
Content-Security-Policy:
frame-ancestors 'none';
Critical for JWT-protected dashboards and admin panels.
6. Disallow Dangerous Execution Paths
Content-Security-Policy:
object-src 'none';
base-uri 'none';
This blocks legacy and obscure execution vectors often abused for injection.
CSP Alone Is Not Enough (But It’s Mandatory)
CSP significantly reduces JWT theft, but it must be combined with:
- Short-lived access tokens
- HttpOnly refresh tokens
- No JWTs in
localStorage - Strong backend validation
- Script integrity monitoring
CSP prevents execution — not logic flaws.
Common CSP Mistakes That Break JWT Security
- Using
'unsafe-inline' - Allowing wildcard domains
- Over-permissive
connect-src - Blindly trusting tag managers
- Never reviewing CSP violations
A CSP that allows everything is worse than no CSP — it creates false confidence.
How BreachFin Strengthens CSP for JWT Protection
CSP policies drift over time.
New scripts get added.
Third parties change behavior.
Inline code creeps back in.
BreachFin helps by:
- Monitoring script execution changes
- Detecting unauthorized client-side behavior
- Identifying CSP bypass risks
- Providing browser-side visibility aligned with PCI DSS 11.6.1
This ensures CSP continues protecting JWTs after deployment, not just on day one.
Final Takeaway
JWT security does not fail at cryptography.
It fails at JavaScript execution.
Content Security Policy:
- Reduces JWT attack surface
- Stops most token theft techniques
- Forces attackers to find much harder paths
If JWTs live in the browser,
CSP is not optional — it is foundational.
Strong JWT implementations require strong browser controls.
CSP is where that control starts.
