
How to stop DOM-based XSS before it reaches your JWTs
Most client-side breaches don’t rely on classic reflected XSS.
They exploit DOM-based XSS — the kind that happens entirely inside the browser at runtime, often through trusted scripts.
Trusted Types is one of the most powerful (and underused) browser defenses for stopping these attacks at the source.
This blog explains what Trusted Types are, why they matter, and how they protect JWTs and sessions in real applications.
The Real Problem: Dangerous DOM Sinks
Modern JavaScript frameworks frequently interact with the DOM using APIs like:
innerHTMLouterHTMLdocument.writeinsertAdjacentHTMLeval/new Function
These are called DOM sinks.
If attacker-controlled data reaches these sinks, malicious JavaScript executes — even with strong CSP in place.
That execution is enough to:
- Read JWTs from memory
- Hook
fetch/ XHR - Observe authenticated actions
- Exfiltrate sensitive data
Why CSP Alone Is Not Enough
CSP helps, but it has limits:
- Trusted scripts can still inject unsafe HTML
- Inline execution may be required by frameworks
- Third-party libraries can introduce new sinks
- CSP violations often go unnoticed
CSP blocks where scripts load from.
Trusted Types control what data is allowed to execute.
They solve a different problem.
What Trusted Types Actually Do
Trusted Types enforce a simple rule:
Only explicitly trusted, validated content may reach dangerous DOM sinks.
Instead of allowing raw strings, the browser requires:
- A TrustedHTML
- TrustedScript
- or TrustedScriptURL object
Anything else is rejected at runtime.
No string → no execution.
How Trusted Types Stop DOM XSS
Without Trusted Types:
element.innerHTML = userInput;
With Trusted Types enforced:
element.innerHTML = userInput; // ❌ blocked by browser
Only content created through an approved policy can be used:
const policy = trustedTypes.createPolicy("default", {
createHTML: (input) => sanitize(input)
});
element.innerHTML = policy.createHTML(userInput); // ✅ allowed
Malicious input never reaches execution.
Why This Matters for JWT and Session Security
DOM XSS is one of the most reliable ways to steal tokens because:
- It runs inside authenticated sessions
- It bypasses backend controls
- It executes after MFA
- It blends into trusted application logic
Trusted Types prevent:
- Token theft via DOM injection
- Script hooking via unsafe HTML
- Runtime execution abuse inside trusted pages
This is post-authentication protection, not just input validation.
How Trusted Types Work With CSP
Trusted Types are enforced via CSP:
Content-Security-Policy:
require-trusted-types-for 'script';
trusted-types default;
This tells the browser:
- Block unsafe DOM injection
- Enforce Trusted Types globally
- Fail closed if unsafe code appears
This is one of the few browser defenses that fails loudly instead of silently.
Common Mistakes When Adopting Trusted Types
- Thinking it’s only for XSS testing
Trusted Types are a runtime control, not a dev-only feature. - Allowing broad fallback policies
This defeats the purpose. - Ignoring third-party scripts
Trusted Types often reveal hidden risk in dependencies. - Not monitoring violations
Violations are early-warning signals — not noise.
Why Trusted Types Are a Security Multiplier
Trusted Types:
- Reduce XSS blast radius
- Harden framework behavior
- Protect JWTs indirectly but effectively
- Complement CSP and SRI
- Expose risky code paths early
They turn unknown DOM behavior into detectable failures.
How BreachFin Complements Trusted Types
Trusted Types block unsafe execution.
BreachFin tells you what tried to break the rules.
BreachFin provides:
- Visibility into runtime execution attempts
- Detection of DOM manipulation anomalies
- Insight into script behavior drift
- Context for CSP and Trusted Types violations
This bridges prevention with detection.
Why This Matters for Compliance
DOM XSS and client-side injection directly impact:
- PCI DSS 4.0 client-side tamper detection
- Session integrity
- Data protection obligations
Trusted Types provide strong preventive control.
BreachFin provides continuous validation that it stays effective.
Auditors care about both.
Final Takeaway
If CSP controls where code comes from,
Trusted Types control what code is allowed to execute.
In modern, JavaScript-heavy applications:
- DOM XSS is the most reliable attack path
- Token theft happens post-authentication
- Runtime defenses matter more than static checks
Trusted Types stop entire classes of client-side attacks —
and when combined with runtime visibility, they turn silent failures into visible signals.
That is modern browser security done right.
