Trusted Types Is Broadly Available — but Do Not Enable It Blindly
Trusted Types reached broader browser availability in 2026. Learn how to find DOM XSS risks, introduce Report-Only, and avoid breaking production.
A browser security feature becomes broadly available. That sounds like a simple header change: enable it, deploy, done.
With Trusted Types, that approach can break production.
The CSP directive require-trusted-types-for 'script' can prevent ordinary strings from being written directly into dangerous DOM interfaces such as innerHTML. This meaningfully reduces the attack surface for DOM-based cross-site scripting. MDN lists the feature as newly broadly available in current browsers since February 2026.
But an existing website may contain hundreds of legitimate code paths where frameworks, editors, analytics snippets, or legacy helpers write HTML strings into the DOM. If enforcement is enabled without preparation, the browser blocks not only attacker-controlled code but also your own application features.
The useful question is therefore not: “Can we turn on Trusted Types?”
It is: “Can we identify which parts of the application use dangerous DOM sinks today and migrate them in a controlled way?”
What Trusted Types actually protects
DOM XSS often does not begin with an unsafe script tag in server-rendered HTML. It begins when JavaScript writes untrusted data into a DOM interface that interprets markup or script-capable content.
Common risky sinks include:
element.innerHTMLelement.outerHTMLdocument.write()insertAdjacentHTML()- certain script URL or HTML assignments
- library functions that call the same browser APIs internally
When user input, URL parameters, API responses, or CMS content reach those sinks without appropriate controls, they may become executable markup or script context.
Trusted Types changes the contract. Protected sinks no longer accept arbitrary strings. They require special, non-spoofable values such as TrustedHTML, created through named policies.
That forces the application to make an explicit decision: Where is HTML created, how is it sanitised, and which code is allowed to do so?
Why this does not replace a strict CSP
Trusted Types addresses a particular class of DOM injection risk. It does not replace Content Security Policy, contextual output encoding, or safe templating.
A resilient browser-security strategy combines layers:
- contextual output encoding
- safe framework templates
- avoiding unnecessary HTML-string APIs
- a nonce- or hash-based strict CSP
- controlled third-party scripts
- Trusted Types for dangerous DOM sinks
- testing and reporting
OWASP and web.dev recommend strict CSPs based on nonces or hashes for script execution. Trusted Types complements that control where JavaScript itself constructs DOM content.
A permissive script-src containing many domains does not become safe merely because a Trusted Types header exists. Both controls must match the application's real data flows.
The common failure: immediate enforcement
A team deploys this directly to production:
Content-Security-Policy: require-trusted-types-for 'script'
Suddenly:
- the rich-text editor renders nothing
- the consent banner will not open
- a tag-manager integration fails
- server-supplied HTML fragments disappear
- a legacy component produces empty containers
- a payment or support widget does not initialise
The problem is not that Trusted Types is “too strict.” The problem is that the application never inventoried its DOM-writing paths.
Security controls should expose failures before they block business-critical journeys.
A safer rollout plan
1. Find the sinks first
Search the codebase for direct HTML assignments and related APIs. Include:
- wrapper functions
- design-system components
- Markdown or MDX renderers
- CMS previews
- rich-text editors
- legacy jQuery or plugin calls
- third-party SDKs
- tag managers and consent managers
Text search is only a starting point. Libraries frequently hide the underlying browser API.
2. Use Report-Only before blocking
Introduce Trusted Types through Content-Security-Policy-Report-Only first. The browser can then report violations without immediately stopping the feature.
The reporting endpoint must actually work. A header without received, grouped, and reviewed reports is decoration.
Capture at least:
- affected URL
- violated directive
- script or component context
- release version
- frequency
- browser
- user journey
Apply privacy and data-minimisation controls. Report URLs and script information may contain internal paths or parameters.
3. Remove unsafe patterns instead of wrapping everything
The strongest fix is often to stop generating HTML strings.
Before writing a Trusted Types policy, ask:
- Can
textContentreplaceinnerHTML? - Can the framework use JSX, templates, or safe DOM methods?
- Can the component accept structured data instead of HTML?
- Can a third-party widget be isolated or replaced?
- Does this dynamic HTML path need to exist at all?
A policy that returns every input string as TrustedHTML satisfies the interface and destroys the security benefit.
4. Keep policies small and named
The trusted-types CSP directive controls which policy names the page may create. This makes uncontrolled policy creation easier to detect.
Instead of one global default policy, use narrowly scoped names such as:
sanitized-markdowncms-previewlegacy-editor-adapter
Every policy should have a defined purpose, owner, and sanitisation strategy.
5. Configure sanitisation deliberately
When HTML is genuinely required, use a well-established sanitizer with a reviewed configuration. Consider:
- allowed elements and attributes
- URL schemes
- SVG and MathML behaviour
- embedded media
- event handlers
- style attributes
- links using
target - custom elements
“We use a sanitizer” becomes meaningful only when the configuration and invocation points have been reviewed.
6. Evaluate third parties separately
The hardest blockers are often embedded services rather than your own components. For every widget, ask:
- Does the vendor support Trusted Types?
- Which sinks does the SDK use?
- Can it be isolated in an iframe?
- Is a newer integration available?
- Is the widget business-critical?
- What happens when it is blocked?
Do not silently defeat the control with one universal exception for every third party.
7. Test critical user journeys
Before enforcement, run real end-to-end checks for:
- login and registration
- contact and application forms
- checkout and payment
- cookie and consent flows
- rich-text or CMS content
- support, chat, and booking widgets
- authenticated dashboards
- file and media previews
Do not stop at verifying that a page loads. Assert the business outcome.
Six red flags in existing implementations
-
A default policy trusts every string.
The application works again, but the protection is effectively gone. -
Report-Only has run for months without action.
Violations accumulate while no component improves. -
Only first-party code was reviewed.
Tag managers, consent tools, and widgets remain blind spots. -
The directive exists only on the homepage.
The app, checkout, admin area, or language variants return different headers. -
Several infrastructure layers generate CSP.
The application, CDN, and reverse proxy send duplicate or contradictory directives. -
Testing uses only developer browser profiles.
Stored consent, extensions, and admin sessions hide real visitor failures.
What Website-Pflichtencheck would inspect
A technical Trusted Types and CSP review should not stop at confirming that a header exists. It can examine:
- CSP headers actually delivered across page types
- DOM sinks in first- and third-party code
- Report-Only configuration and the reporting pipeline
- policy names, scope, and sanitizers
- framework, CMS, and editor integrations
- third-party widgets and tag managers
- differences between production, preview, and staging
- critical journeys under enforcement
- regression tests and release monitoring
- interaction with nonces, hashes, and
strict-dynamic
The objective is not to enable a fashionable security header as quickly as possible. It is to expose where the application currently trusts HTML and reduce that trust to a small number of reviewable paths.
Trusted Types is therefore more than a browser feature. It is an architecture test.
If your application only works when every string may be treated as trusted, the security policy is not the problem. It has merely revealed where control was missing.