1 · A DOM-XSS sink under Trusted Types

DOM-XSS happens when untrusted data flows into a dangerous sink like el.innerHTML = …. Trusted Types makes those sinks reject plain strings: a value must be a TrustedHTML object minted by a registered policy. Choose an enforcement mode and how the value reaches the sink. safe lab Payloads are analyzed in an inert <template> and previewed in a scripts-off sandbox iframe — nothing executes.

The line that runs

      
What ends up in the DOM (scripts-off preview)

2 · Your policy & the headers

Define a policy (sanitize inside it)
const policy = trustedTypes.createPolicy('app', {
  createHTML: (s) => DOMPurify.sanitize(s),
});

// now this is the ONLY way to feed innerHTML:
el.innerHTML = policy.createHTML(userInput);
The CSP that enforces it
Content-Security-Policy:
  require-trusted-types-for 'script';
  trusted-types app dompurify;
Sinks guarded by Trusted Types
  • Element.innerHTML / outerHTML → TrustedHTML
  • Element.insertAdjacentHTML() → TrustedHTML
  • document.write() / writeln() → TrustedHTML
  • setHTMLUnsafe() / parseHTMLUnsafe() → TrustedHTML
  • script.src / .text → TrustedScript(URL)
  • eval() / new Function() → TrustedScript
  • iframe.srcdoc, .setAttribute('on…') → trusted value

With enforce on, every one of these throws a TypeError when handed a raw string — you can't forget to sanitize, because the browser refuses the unsafe assignment.