// Header: Content-Security-Policy: require-trusted-types-for 'script'; trusted-types sanitize
const policy = trustedTypes.createPolicy("sanitize", {
createHTML: (input) => DOMPurify.sanitize(input),
});
el.innerHTML = userHtml; // throws: a plain string is rejected
el.innerHTML = policy.createHTML(userHtml); // allowed: a TrustedHTML object
Trusted Types is a browser feature that makes the dangerous DOM sinks reject plain strings. You turn it on with the CSP directive require-trusted-types-for 'script'.
Once it is on, sinks like innerHTML, eval and a script element's src only accept special objects:
TrustedHTMLfor HTML sinksTrustedScriptfor code sinksTrustedScriptURLfor script URLs
Only a policy can create these objects. You create a policy with trustedTypes.createPolicy(name, rules). The trusted-types directive lists which policy names may exist.
Why this helps: without Trusted Types, any line in your app or its libraries could pass user data to innerHTML. With them, every dangerous write must go through a few small policies. Those are easy to review, and one of them can call DOMPurify. A forgotten innerHTML now throws an error instead of becoming a security bug.
To adopt it:
- Start with
Content-Security-Policy-Report-Onlyto find every place that breaks. - A policy named
defaultcatches old code that still assigns strings.
Support started in Chromium-based browsers. Check MDN for current support in other browsers. Browsers without support ignore the directive, so keep your other XSS defences too.
- Trusted Types make sinks like
innerHTMLreject plain strings. - You turn them on with the CSP directive
require-trusted-types-for 'script'. - Only policies made with
trustedTypes.createPolicycan create trusted values. - All dangerous writes then go through a few policies that are easy to review.
- Roll it out in report-only mode first, and keep other defences for browsers without support.