require-trusted-types-for
require-trusted-types-for 'script' makes the dangerous DOM sinks - innerHTML, outerHTML, document.write, script.src, eval - reject plain strings. Only a TrustedHTML, TrustedScript or TrustedScriptURL produced by a policy is accepted.
This is the strongest anti-XSS measure CSP offers, and the only one that addresses DOM XSS rather than injected markup. It works by shrinking the number of places a string can become code to a handful of reviewable policy functions.
It is one half of a pair: this directive enforces the sinks, and trusted-types controls which policies may exist.
Syntax
Section titled “Syntax”Content-Security-Policy: require-trusted-types-for 'script';What it controls
Section titled “What it controls”- Assignments to DOM XSS injection sinks, such as
Element.innerHTML. - Values passed to script-URL sinks, such as
HTMLScriptElement.src.
Fallback
Section titled “Fallback”require-trusted-types-for has no fallback. default-src does not enable it, and without it the trusted-types directive enforces nothing at the sinks.
Recommended value
Section titled “Recommended value”Content-Security-Policy: require-trusted-types-for 'script'; trusted-types default'script'is the only defined value. The interesting configuration is in thetrusted-typesdirective next to it.- Roll it out in report-only first. The violations name the sink and the first 40 characters of the offending value, which is enough to find the code - and there will be more of them than you expect, because third-party libraries use these sinks freely.
Examples
Section titled “Examples”Allowed
Section titled “Allowed”A value that went through a policy:
const policy = trustedTypes.createPolicy("default", { createHTML: (input) => DOMPurify.sanitize(input),});el.innerHTML = policy.createHTML(untrusted);Blocked
Section titled “Blocked”A plain string - throws a TypeError and reports:
el.innerHTML = untrusted;Browser support
Section titled “Browser support”- Baseline 2026: newly available. It works across the latest versions of every major browser as of February 2026; for years before that it was Chromium-only.
- In a browser without support the directive is ignored, so the code still has to be correct without it. Treat Trusted Types as defence in depth on top of a strict
script-src, not as a replacement for one.
In a HeaderHawk report
Section titled “In a HeaderHawk report”| Field | Value |
|---|---|
violatedDirective |
require-trusted-types-for |
effectiveDirective |
require-trusted-types-for |
blockedUri |
trusted-types-sink |
| Issue title | require-trusted-types-for sink Element innerHTML |
blockedUriis the literal stringtrusted-types-sink; there is no URL. Thesamplecarries the sink name followed by the first 40 characters of the value, and browsers include it for Trusted Types violations without needing'report-sample'.- There is no host to group on, so issues are grouped by the sink name - the half of the
samplebefore the|. One issue per sink the page assigns to, whatever it assigned. Grouping on the whole sample would instead open a fresh issue for every distinct value, which forel.innerHTML = userContentis every page view.
Related directives
Section titled “Related directives”Getting reports for this directive
Section titled “Getting reports for this directive”Point your policy’s report-uri at your site’s HeaderHawk endpoint and the violations above arrive in the dashboard, grouped as described. The Quick Start sets that up in five minutes, and the integration guides cover the header syntax for each platform.