Trusted Types
Why it matters CSP blocks injected script tags. But many modern bugs live inside your own JavaScript: a line such as box.innerHTML = comment turns text from a visitor into live HTML. That is the DOM-based injection from Module 10 (Lesson 59), and it happens after the page has loaded. Trusted Types makes the browser refuse those dangerous lines unless the value went through a check you wrote.
Imagine a factory where only parts with an inspection stamp may go onto the assembly line. Nobody can bolt on a random part found in the car park, even by accident. Trusted Types adds that stamp to the strings your code feeds into dangerous places.
DOM: short for Document Object Model, the live tree of elements the browser builds from a page, which JavaScript can read and change.
Sink: a place in the DOM where a string becomes code or markup. Examples: element.innerHTML, outerHTML, insertAdjacentHTML, document.write, iframe.srcdoc, eval and string arguments to setTimeout, and script.src.
Trusted Types: a browser feature, switched on by CSP, under which those sinks accept only special objects (TrustedHTML, TrustedScript, TrustedScriptURL) made by a policy, a small function you write and name. A plain string assigned to a sink throws an error instead of running.
Switching it on
Content-Security-Policy: require-trusted-types-for 'script'; trusted-types commentsrequire-trusted-types-for 'script': enforce it on all script-related sinks.trusted-types comments: the only policy name your code may create. An injected script cannot register a policy of its own under another name.trusted-types 'none'forbids creating any.
Using it in your code
// The one, reviewed place that turns text into HTML.
const commentsPolicy = trustedTypes.createPolicy("comments", {
createHTML: (text) => escapeHtml(text), // or a well-tested sanitiser
});
box.innerHTML = comment; // throws TypeError: blocked
box.innerHTML = commentsPolicy.createHTML(comment); // allowed, escaped
box.textContent = comment; // not a sink at all: always fineThe big win is for reviewers. Instead of hunting every innerHTML in a large codebase, you review the few policy functions. If they are safe, the browser enforces that everything else goes through them.
A policy named default is special: the browser calls it automatically whenever a plain string reaches a sink. It is useful while migrating old code, but it is also a place where mistakes hide, so keep it strict and log what passes through.
Support and rollout
Trusted Types is supported in all major engines: Chromium-based browsers, Safari 26 and Firefox 148 (checked October 2026). Visitors on older browsers simply do not get the extra check, so keep escaping and keep your nonce-based CSP. Code can test for it with if (window.trustedTypes).
Roll it out like any policy: send require-trusted-types-for 'script' in a Content-Security-Policy-Report-Only header first. Every string that reaches a sink is reported, showing you exactly which lines need a policy or, better, a switch to textContent.
A common misconception: "Trusted Types sanitises HTML for me". It does not clean anything. It forces strings through your policy. A policy that returns its input unchanged (createHTML: s => s) passes the check and protects nothing.
Recap
- DOM injection happens in your own JavaScript at sinks such as
innerHTML; script-tag rules alone do not catch it. require-trusted-types-for 'script'makes sinks refuse plain strings;trusted-types NAMElimits which policies may exist.- Review the few policy functions instead of every sink, and prefer
textContentwhere you can. - Supported in all major engines (checked October 2026); roll out in report-only first.
This lesson is locked
Lessons open one at a time. Finish the previous lesson to unlock this one.