Introduction
Modern React applications usually escape rendered values automatically, which removes many common cross-site scripting (XSS) risks. However, a production application can still interact with browser APIs that handle HTML, URLs, scripts, or other potentially dangerous values.
This becomes more important when an application uses:
dangerouslySetInnerHTMLThird-party libraries
Client-side HTML transformations
Browser APIs that accept HTML strings
Content Security Policy (CSP)
Trusted Types
React 19.3 improves the framework's integration with browser Trusted Types. React now supports Trusted Types values for relevant DOM operations, and the React team documents CSP and Trusted Types as part of the security improvements around the React 19.3 release. (react.dev)
Trusted Types are a browser security mechanism designed to prevent DOM-based XSS by requiring dangerous DOM sinks to receive approved trusted values instead of arbitrary strings.
The important distinction is that Trusted Types do not replace React's escaping. They add another security boundary around browser APIs that can interpret strings as executable or unsafe content.
What Are Trusted Types?
Trusted Types are a browser security feature that can restrict certain DOM APIs from accepting ordinary strings.
Without Trusted Types:
element.innerHTML = userInput;
can become dangerous if userInput contains executable markup.
With a Trusted Types policy, the application can instead establish a controlled transformation:
Untrusted Input
|
v
Validation / Sanitization
|
v
Trusted Type
|
v
Dangerous DOM Sink
The browser then enforces the policy.
The goal is to prevent application code from accidentally sending untrusted strings directly to sensitive DOM APIs.
What Is a DOM Sink?
A DOM sink is an API that consumes a value in a way that can create executable or otherwise security-sensitive browser content.
A common example is:
element.innerHTML = value;
Other browser APIs can also be sensitive depending on the value being supplied.
The security problem is:
User Input
|
v
String
|
v
Dangerous DOM API
|
v
XSS
Trusted Types changes the boundary:
User Input
|
v
Sanitizer / Policy
|
v
TrustedHTML
|
v
DOM API
What Is CSP?
Content Security Policy is an HTTP security mechanism that lets a website tell the browser which types of content and execution are allowed.
A CSP header might contain:
Content-Security-Policy: default-src 'self'
CSP can also enable Trusted Types enforcement.
A policy can include directives such as:
Content-Security-Policy:
require-trusted-types-for 'script';
trusted-types my-policy;
The first directive tells the browser to require Trusted Types for supported script-related DOM sinks.
The second restricts which Trusted Types policies can be created.
The exact CSP should be designed around the application's resources and deployment model rather than copied blindly.
Why React Needs Trusted Types
React already protects normal JSX interpolation.
For example:
function Welcome({ name }) {
return <h1>Hello, {name}</h1>;
}
If:
name = "<img src=x onerror=alert(1)>"
React does not interpret the value as HTML.
It treats the value as text.
The risk is higher when developers intentionally bypass normal escaping:
function Content({ html }) {
return (
<div
dangerouslySetInnerHTML={{ __html: html }}
/>
);
}
This API exists for legitimate use cases, but the application is now responsible for ensuring that the HTML is safe.
Trusted Types can add browser-enforced protection around this boundary.
React 19.3 and Trusted Types
React 19.3 improves Trusted Types integration so that Trusted Types values can be passed through relevant React APIs without React unnecessarily converting them back into ordinary strings. The React 19.3 announcement also notes that React no longer stringifies Trusted Types values for relevant DOM operations. (react.dev)
The practical architecture is:
React Component
|
v
Trusted Value
|
v
React DOM
|
v
Browser Trusted Types Enforcement
This is useful when an application has a security policy requiring Trusted Types.
A Basic Trusted Types Policy
The browser API can create a policy:
const policy = trustedTypes.createPolicy("app", {
createHTML(value) {
return DOMPurify.sanitize(value);
}
});
Then:
const trustedHtml = policy.createHTML(untrustedHtml);
The important part is the sanitizer.
Trusted Types do not make arbitrary input safe automatically.
A policy that simply returns the input:
createHTML(value) {
return value;
}
does not provide meaningful sanitization.
The policy should enforce the application's security rules.
Using Trusted HTML With React
A component can receive a trusted value:
function ArticleContent({ content }) {
return (
<div
dangerouslySetInnerHTML={{
__html: content
}}
/>
);
}
The security architecture becomes:
External HTML
|
v
Sanitization
|
v
TrustedHTML
|
v
React
|
v
DOM
The type itself is not the sanitizer.
The policy that creates the trusted value is where the security decision is made.
Do Not Sanitize in the Wrong Place
A common mistake is to sanitize some data at the point where it enters the application and then assume it will always remain safe.
Data can change later.
For example:
Database
|
v
API
|
v
React
|
v
DOM
If the application stores HTML and later displays it, the rendering boundary still needs to be considered.
The correct architecture depends on what the data represents.
For user-generated HTML, establish a clear rule:
Input
|
v
Validation
|
v
Sanitization
|
v
Trusted Representation
|
v
Rendering
Do not rely on an undocumented assumption that "this field is already safe."
CSP and Trusted Types Work Together
Trusted Types are most useful when enforced through CSP.
A simplified policy might look like:
Content-Security-Policy:
require-trusted-types-for 'script';
trusted-types app;
The browser then restricts supported dangerous sinks.
Conceptually:
React Application
|
v
DOM Sink
|
v
Trusted Types Check
|
+---- TrustedHTML ---> Allowed
|
+---- String --------> Blocked
This turns a security rule into browser-enforced behavior instead of relying entirely on developer discipline.
Start With Report-Only Mode
Changing CSP enforcement on an existing application can expose compatibility problems.
A safer rollout begins with:
Content-Security-Policy-Report-Only:
require-trusted-types-for 'script';
trusted-types app;

Join the conversation! Your thoughts help the community grow.