Trusted Types

Trusted Types is a Web Security API that helps prevent DOM-based XSS by requiring dangerous DOM injection sinks to receive values produced by approved policies. With CSP enforcement, application code cannot directly pass ordinary strings to protected sinks.

DOM-based XSS occurs when attacker-controlled data reaches an injection sink that interprets the data as HTML, JavaScript, or a script URL. Examples include `innerHTML`, `document.write()`, executable script content, and script `src` values. Trusted Types introduces typed objects so security-sensitive data must pass through an explicit transformation step before reaching such sinks.

A `TrustedTypePolicy` defines how strings become trusted values. The principal types are `TrustedHTML`, `TrustedScript`, and `TrustedScriptURL`. For HTML, the policy normally delegates to a well-tested sanitizer such as DOMPurify; Trusted Types itself does not perform sanitization.

Creating a policy alone does not force the rest of the application to use it. CSP enforcement with `require-trusted-types-for 'script'` makes protected sinks reject ordinary strings when no applicable default policy supplies a trusted value. The separate `trusted-types` CSP directive can restrict which policy names application code is allowed to create, reducing the number of places that can establish trust.

For a frontend engineer, the key design question is where trust is established. Keep untrusted data as strings, perform validation or sanitization inside narrowly scoped policies, and pass only the resulting trusted type to the sink. Prefer APIs such as `textContent` when the intended result is plain text rather than markup.

Key points

Interview questions

What problem does Trusted Types solve?

Trusted Types addresses DOM-based XSS caused by unsafe strings reaching injection sinks. It introduces special trusted values that are produced by application-defined policies. With CSP enforcement, protected sinks can reject ordinary strings, forcing security-sensitive data through those policies. This makes the places where untrusted data becomes trusted easier to identify and review.

How would you safely use Trusted Types with `innerHTML`?

First, create a narrowly scoped policy whose `createHTML` implementation sanitizes the supplied HTML with a suitable sanitizer. Then call that policy with the untrusted string and assign the resulting `TrustedHTML` value to `innerHTML`. In production, enable `require-trusted-types-for 'script'` so direct string assignments to protected sinks are rejected. The policy should have a small, auditable surface and should not blindly return its input.

What is the difference between `trusted-types` and `require-trusted-types-for` in CSP?

`require-trusted-types-for 'script'` controls enforcement at applicable injection sinks, requiring trusted values rather than ordinary strings when no default policy handles the conversion. The `trusted-types` directive controls which policy names application code is permitted to create. They solve different parts of the problem: one protects sink usage, while the other constrains the trust-creation mechanism. Using both provides a stronger and more auditable boundary.

Why isn't a Trusted Types policy automatically secure?

Trusted Types does not know whether a policy's transformation is actually safe. A policy can be implemented incorrectly, including one that simply returns attacker-controlled input. The security boundary therefore depends on the policy implementation and on restricting which code can create policies. Senior-level design should minimize the number of policies, keep transformations auditable, and combine Trusted Types with appropriate sanitization and other CSP controls.

How would you migrate a legacy frontend that uses `innerHTML` extensively?

I would first inventory the protected sinks and classify each use by whether it genuinely needs HTML, executable script, or a script URL. Then I would replace unnecessary HTML insertion with safer DOM APIs and introduce narrowly scoped policies for legitimate dynamic markup, backed by an established sanitizer. I would deploy enforcement after remediation, using reporting and staged rollout where appropriate to discover remaining violations. Finally, I would restrict policy creation with the `trusted-types` directive and continuously review policy code.