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.
const policy = trustedTypes.createPolicy('app', {
createHTML: (s) => DOMPurify.sanitize(s),
});
// now this is the ONLY way to feed innerHTML:
el.innerHTML = policy.createHTML(userInput);
Content-Security-Policy: require-trusted-types-for 'script'; trusted-types app dompurify;
Element.innerHTML / outerHTML → TrustedHTMLElement.insertAdjacentHTML() → TrustedHTMLdocument.write() / writeln() → TrustedHTMLsetHTMLUnsafe() / parseHTMLUnsafe() → TrustedHTMLscript.src / .text → TrustedScript(URL)eval() / new Function() → TrustedScriptiframe.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.