Trusted Types Intro
Trusted Types lock dangerous DOM sinks to typed values — policy design, CSP require-trusted-types-for, and DOM XSS.
- browser
- trusted-types
- xss
- csp
- security
Trusted Types redesign dangerous DOM sinks so you can’t assign raw strings to innerHTML, script.src, and friends without going through a policy that returns typed objects. Paired with CSP, it turns many DOM XSS bugs into hard failures at the assignment site.
Docs: MDN Trusted Types, web.dev Trusted Types, W3C Trusted Types.
The problem
el.innerHTML = userInput; // string → HTML parser → XSS
Frameworks reduce accidents; plugins and dangerouslySetInnerHTML bring them back. Trusted Types make the sink type-safe at runtime:
el.innerHTML = userInput; // TypeError under enforced Trusted Types
CSP enablement
Content-Security-Policy: require-trusted-types-for 'script'; trusted-types myPolicy default
require-trusted-types-for 'script'— enforce for script-related sinks (and related).trusted-types …— allowlist policy names;defaultpolicy optional.
Roll out with report-only / violation reports first — same discipline as CSP.
Creating a policy
const policy = trustedTypes.createPolicy('myPolicy', {
createHTML: (input) => DOMPurify.sanitize(input),
createScript: () => {
throw new Error('inline scripts blocked');
},
createScriptURL: (url) => {
const u = new URL(url, location.origin);
if (u.origin !== location.origin) throw new Error('bad script url');
return u.toString();
},
});
el.innerHTML = policy.createHTML(userHtml);
script.src = policy.createScriptURL('/app.js');
Policies are the only place sanitization/allowlisting should live — keep them few and reviewed.
Sinks covered (illustrative)
Element.innerHTML/outerHTMLDocument.writesetTimeout(string)/setInterval(string)script.src,iframe.srcdoc(as specified)- Various DOM APIs listed in the spec
Exact sink list evolves — test target browsers.
Framework notes
React 19+ and other libraries increasingly produce Trusted Types-compatible values when policies exist. You may still need a default policy for third-party widgets that assign strings.
trustedTypes.createPolicy('default', {
createHTML: (s) => DOMPurify.sanitize(s),
});
Default policies are powerful and dangerous — treat like a global sanitizer.
Limitations
Trusted Types don’t fix URL-based XSS alone (javascript: hrefs), CSS injection, or backend HTML injection into initial documents. Stack with sanitization, CSP nonces, and cookie flags — XSS, CSP.
Interview out-loud
“Trusted Types make dangerous sinks reject raw strings unless a named policy creates HTML/script/URL types. I enable require-trusted-types-for via CSP, centralize sanitization in createHTML, and lock createScriptURL to known origins.”
Rollout sequence
- Inventory sinks (
innerHTML, etc.). - Add report-only CSP for Trusted Types.
- Introduce policies; fix violations.
- Enforce on a canary.
- Remove default-policy crutches that reintroduce string sinks globally.
Track violation reports like CSP — volume spikes mean a new feature bypassed the policy.
Related
Further depth
Teams often under-invest in this topic until an incident or CWV regression. Schedule a one-hour drill: reproduce the failure mode in DevTools, list the top three mitigations for your stack, and file tickets with owners. Revisit after the next major feature that touches networking, rendering, auth, or third parties — those are the moments regressions land. Keep primary documentation links in the runbook so on-call is not searching chat history at 2am.
Concrete artifacts to leave behind: a short architecture note, a CI assertion or header snapshot, and a dashboard panel (lab or field) that would have caught the last bug. Teaching the rest of the team the mental model matters as much as the one-line fix.
Further reading
Related guides
- Content-Type and MIME SniffingWhy Content-Type matters, how MIME sniffing works, X-Content-Type-Options: nosniff, and XSS-ish pitfalls.
- CORS Explained for FrontendWhy the browser blocks cross-origin responses, what Access-Control-* headers mean, preflight, credentials, and how to fix real frontend errors.
- Cross-Origin Embedder PolicyCOEP require-corp / credentialless: cross-origin isolation, SharedArrayBuffer, and embedding requirements.
- Cross-Origin Opener PolicyCOOP same-origin and same-origin-allow-popups: sever window.opener, process isolation, and OAuth popups.
- Feature Policy Legacy NotesFeature-Policy renamed to Permissions-Policy: migration notes, old header syntax, and what still matters.