Creating a Trusted Types policy does not automatically block every DOM string. In supporting browsers, an enforced CSP require-trusted-types-for 'script' directive can reject ordinary strings at specified injection sinks and require trusted values. The Trusted Types specification and CSP Level 3 define the model; web.dev’s specialist guide covers adoption.

Conceptual flow of input passing through a policy and sanitization before a protected DOM sink

Conceptual illustration, not a security test or UI capture.

Match the type to the sink

TrustedHTML is for HTML sinks, TrustedScript for specified script sinks, and TrustedScriptURL for script URL sinks. The CSP token 'script' does not mean every DOM method is blocked. Check the specification and target browser for the actual sink group. When markup is unnecessary, prefer a text-only API such as textContent.

A policy name does not certify safety

trustedTypes.createPolicy lets application code provide transformation functions. The browser does not prove that the function sanitizes its input. A policy that returns the original string does not make it safe just because the result is wrapped as TrustedHTML. Use a reviewed sanitizer and restrict tags, attributes, and URL schemes to the feature’s needs.

Enforce versus report

require-trusted-types-for enforces trusted values at covered sinks. The trusted-types directive restricts policy names that may be created. Report-only mode helps observe violations; it does not block the values. Collect reports to find legacy sinks, validate policies and browser behavior, then move to enforcement deliberately.

Keep it one layer of defense

Trusted Types reduces one DOM XSS attack surface; it does not replace input validation, context-aware output handling, safe DOM APIs, or other CSP controls. Do not assume identical enforcement in browsers without support. Review policy creation and sensitive sinks centrally, and keep policy allowlists narrow.

Roll it out through existing code

Start in a reporting or non-enforcing phase and inventory sinks that still receive strings. Trace each call path to distinguish user input, server data, and trusted templates. At each type boundary, verify that the policy calls a real sanitizer; restrict policy names with the CSP allowlist. A default policy can help observe or temporarily bridge missed conversions, but a broad pass-through policy weakens the purpose of enforcement.

After enforcement, check both supported and older browsers and confirm that rejected sinks do not break user tasks. Review each policy’s allowed markup, URL schemes, and failure behavior. Do not label all inputs safe just because a policy returned a TrustedHTML value. Automatically retrying rejected input as permissive HTML can create a new bypass path.

Sources