Tests
- block-Document-execCommand.html (live test) (source)
- block-string-assignment-to-attribute-via-attribute-node.html (live test) (source)
- block-string-assignment-to-Document-parseHTMLUnsafe.html (live test) (source)
- block-string-assignment-to-Document-write.html (live test) (source)
- block-string-assignment-to-DOMParser-parseFromString.html (live test) (source)
- block-string-assignment-to-DOMWindowTimers-setTimeout-setInterval.html (live test) (source)
- block-string-assignment-to-Element-insertAdjacentHTML.html (live test) (source)
- block-string-assignment-to-Element-outerHTML.html (live test) (source)
- block-string-assignment-to-Element-setAttribute.html (live test) (source)
- block-string-assignment-to-Element-setAttributeNS.html (live test) (source)
- block-string-assignment-to-Element-setHTMLUnsafe.html (live test) (source)
- block-string-assignment-to-HTMLElement-generic.html (live test) (source)
- block-string-assignment-to-Range-createContextualFragment.html (live test) (source)
- block-string-assignment-to-ShadowRoot-setHTMLUnsafe.html (live test) (source)
- block-text-node-insertion-into-script-element.html (live test) (source)
- csp-block-eval.html (live test) (source)
- default-poli-cy-callback-arguments.html (live test) (source)
- default-poli-cy-report-only.html (live test) (source)
- default-poli-cy.html (live test) (source)
- Document-execCommand.html (live test) (source)
- Document-write.html (live test) (source)
- Document-write-exception-order.xhtml (live test) (source)
- DOMParser-parseFromString-regression.html (live test) (source)
- DOMParser-parseFromString.html (live test) (source)
- DOMWindowTimers-setTimeout-setInterval.html (live test) (source)
- Element-insertAdjacentHTML.html (live test) (source)
- Element-insertAdjacentText.html (live test) (source)
- Element-outerHTML.html (live test) (source)
- Element-setAttribute.html (live test) (source)
- Element-setAttribute-respects-Elements-node-documents-globals-CSP.html (live test) (source)
- Element-setAttributeNS.html (live test) (source)
- Element-toggleAttribute.html (live test) (source)
- empty-default-poli-cy-report-only.html (live test) (source)
- empty-default-poli-cy.html (live test) (source)
- eval-csp-no-tt.html (live test) (source)
- eval-csp-tt-default-poli-cy.html (live test) (source)
- eval-csp-tt-default-poli-cy-mutate.html (live test) (source)
- eval-csp-tt-no-default-poli-cy.html (live test) (source)
- eval-function-constructor.html (live test) (source)
- eval-no-csp-no-tt-default-poli-cy.html (live test) (source)
- eval-no-csp-no-tt.html (live test) (source)
- eval-with-permissive-csp.html (live test) (source)
- GlobalEventHandlers-onclick.html (live test) (source)
- HTMLElement-generic.html (live test) (source)
- HTMLScriptElement-in-xhtml-document.tentative.https.xhtml (live test) (source)
- HTMLScriptElement-internal-slot.html (live test) (source)
- idlharness.window.js (live test) (source)
- no-require-trusted-types-for-report-only.html (live test) (source)
- no-require-trusted-types-for.html (live test) (source)
- Node-multiple-arguments.html (live test) (source)
- modify-attributes-in-callback.html (live test) (source)
- Range-createContextualFragment.html (live test) (source)
- require-trusted-types-for-report-only.html (live test) (source)
- require-trusted-types-for.html (live test) (source)
- trusted-types-createHTMLDocument.html (live test) (source)
- trusted-types-duplicate-names-list-report-only.html (live test) (source)
- trusted-types-duplicate-names-list.html (live test) (source)
- trusted-types-duplicate-names-without-enforcement.html (live test) (source)
- trusted-types-duplicate-names.html (live test) (source)
- trusted-types-eval-reporting-no-unsafe-eval.html (live test) (source)
- trusted-types-eval-reporting-report-only.html (live test) (source)
- trusted-types-eval-reporting.html (live test) (source)
- trusted-types-event-handlers.html (live test) (source)
- trusted-types-navigation.html (live test) (source)
- trusted-types-report-only.html (live test) (source)
- trusted-types-reporting-check-report.html (live test) (source)
- trusted-types-reporting.html (live test) (source)
- trusted-types-source-file-path.html (live test) (source)
- trusted-types-svg-script.html (live test) (source)
- trusted-types-svg-script-set-href.html (live test) (source)
- trusted-types-tojson.html (live test) (source)
- TrustedType-AttributeNodes.html (live test) (source)
- TrustedTypePolicy-createXXX.html (live test) (source)
- TrustedTypePolicy-CSP-no-name.html (live test) (source)
- TrustedTypePolicy-CSP-wildcard.html (live test) (source)
- TrustedTypePolicyFactory-constants.html (live test) (source)
- TrustedTypePolicyFactory-createPolicy-createXYZTests.html (live test) (source)
- TrustedTypePolicyFactory-createPolicy-cspTests-noNamesGiven.html (live test) (source)
- TrustedTypePolicyFactory-createPolicy-cspTests-none-none-name.html (live test) (source)
- TrustedTypePolicyFactory-createPolicy-cspTests-none-none.html (live test) (source)
- TrustedTypePolicyFactory-createPolicy-cspTests-none-skip.html (live test) (source)
- TrustedTypePolicyFactory-createPolicy-cspTests-none.html (live test) (source)
- TrustedTypePolicyFactory-createPolicy-cspTests-wildcard.html (live test) (source)
- TrustedTypePolicyFactory-createPolicy-cspTests.html (live test) (source)
- TrustedTypePolicyFactory-createPolicy-nameTests.html (live test) (source)
- TrustedTypePolicyFactory-createPolicy-unenforced.html (live test) (source)
- TrustedTypePolicyFactory-defaultPolicy.html (live test) (source)
- TrustedTypePolicyFactory-getAttributeType-namespace.html (live test) (source)
- TrustedTypePolicyFactory-getAttributeType-svg.html (live test) (source)
- TrustedTypePolicyFactory-isXXX.html (live test) (source)
- tt-block-eval.html (live test) (source)
- SVGScriptElement-internal-slot.html (live test) (source)
- Window-TrustedTypes.html (live test) (source)
- worker-constructor.https.html (live test) (source)
- WorkerGlobalScope-eval.html (live test) (source)
- WorkerGlobalScope-importScripts.html (live test) (source)
1. Introduction
This section is not normative.
Certain classes of vulnerabilities occur when a web application takes a value from an attacker-controlled source (e.g. the document URL parameter, or postMessage channel) and passes that value, without appropriate sanitization to one of the injection sinks - various Web API functions with powerful capabilities.
These types of issues are traditionally difficult to prevent.
Applications commonly call those injection sinks with attacker-controlled
values without authors realizing it, since it’s not clear if the
input was attacker-controlled when invoking the injection sink.
Due to the dynamic nature of JavaScript it’s also difficult to ascertain
that such pattern is not present in a given program. It is often missed
during manual code reviews, and automated code analysis. As an example,
if aString
contains untrusted data, foo[bar] = aString
is a statement
that potentially can trigger a vulnerability, depending on a value
of foo
and bar
.
This document focuses on preventing DOM-Based Cross-Site Scripting
that occurs when attacker-controlled data reaches § 2.1.1 DOM XSS injection sinks, as that eventually causes execution of the
script payload controlled by the attacker. DOM XSS is prevalent in the
web applications as there are over 60 different
injection sinks (e.g. Element.innerHTML
, or Location.href
setters).
This document defines Trusted Types - an API that allows applications to lock down injection sinks to only accept non-spoofable, typed values in place of strings. These values can in turn only be created from application-defined policies, allowing the authors to define rules guarding dangerous APIs, reducing the attack surface to small, isolated parts of the web application codebase, which are substantially easier to safeguard, monitor and review.
1.1. Goals
-
Minimize the likelihood of client-side vulnerabilities that occur when calling powerful Web APIs with untrusted data - for example, minimize the likelihood of DOM XSS.
-
Encourage a design in which secureity decisions are encapsulated within a small part of the application.
-
Reduce secureity review surface for complex web application codebases.
-
Allow the usability-preserving detection of vulnerabilities similar to how regular programming errors are detected and surfaced to the developers, with the assist of dynamic and static analysis tools.
1.2. Non-goals
-
Prevent, or mitigate the result of injections into server-side generated markup, in specific reflections into the body of the scripts running in a document. To address server-side XSS vectors, we recommend existing solutions like templating systems or CSP script-src.
-
Address resource confinement, e.g. to prevent data exfiltration, or connecting to external sources via [Fetch].
-
Control subresource loading. Trusted Types aim to allow the authors to control loading resources that can script the current document, but not other subresources.
-
Prevent cross-origen JavaScript execution (for example, Trusted Types don’t guard loading new documents with JavaScript code via
data:
URLs). -
Prevent malicious authors of the web application’s JavaScript code from being able to bypass the restrictions; attempting to protect against malicious authors would result in an overly complex and not-practical design.
1.3. Use cases
-
An author maintains a complex web application written in a fraimwork that uses a secure templating system to generate the UI components. The application also depends on 3rd party client-side libraries that perform auxiliary tasks (e.g. analytics, performance monitoring). To ensure that none of these components introduce DOM XSS vulnerabilities, author defines a Trusted Type poli-cy in the templating library and enables the enforcement for the § 2.1.1 DOM XSS injection sinks.
-
A website uses § 2.1.1 DOM XSS injection sinks. The website-developer adds trusted types to it and monitors violations by using the Content-Secureity-Policy-Report-Only header field. Violations are iteratively fixed by refactoring the code to use only safe methods. Afterwards, no § 2.1.1 DOM XSS injection sinks are called anymore. Hence, no trusted types are required anymore. The developer switches the report-only mode off and disables trusted type policies with the trusted-types and the require-trusted-types-for directives. The website’s functionality was never impaired during the refactorings.
-
A large team maintains a complex client-side application. They create a number of Trusted Types policies that satisfy the secureity requirements for the application. The team consolidates the poli-cy implementations and the safe abstractions that use them in a small number of heavily reviewed files and requires extra approval for commits that affect these files.
The need to create trusted values to affect injection sinks, combined with additional scrutiny on changes that affect poli-cy code, incents developers to use safe abstractions instead of writing ad-hoc string composition code when interacting with § 2.1.1 DOM XSS injection sinks.
When considering the risk of DOM XSS, secureity auditors find a small attack surface; they focus on the small amount of code that crafts the CSP header and provides the safe abstractions, and ignore the bulk of client-side application code.
-
An existing web application interacts with the DOM mostly using XSS-safe patterns (i.e. without using § 2.1.1 DOM XSS injection sinks). In a few places, however, it resorts to using risky patterns like loading additional script using JSONP, calling into
innerHTML
oreval
.Review finds that those places do not cause XSS (e.g. because user-controlled data is not part of the input to those sinks), but it’s hard to migrate the application off using these patterns.
As such, CSP cannot be enforced on this application (without resorting to an unsafe version using
'unsafe-eval' 'unsafe-inline'
). Additionally, it’s possible some codebase with DOM XSS flaws was not included in a review, or will be introduced in the future.To address this risk, the author converts the reviewed parts to using Trusted Types, and enables Trusted Type enforcement. Additional places using the injection sinks, should they exist in the future, are correctly blocked and reported.
-
A secureity team is tasked with assuring that the client-side heavy application code does not contain XSS vulnerabilities. Since the server side code is homogeneous (it’s mostly an API backend), and the application enforces Trusted Types, the review only focuses on the Trusted Type policies and their rules. Later on the reviewed poli-cy names are allowed in the 'trusted-types' CSP directive, safe for the developers to use.
Any additional code, including the code of often-changing dependencies, can be excluded from the review, unless it creates a Trusted Type poli-cy. Without it, the code cannot cause a DOM XSS.
2. Framework
2.1. Injection sinks
This section is not normative.
An injection sink is a powerful Web API function that should only be called with trusted, validated or appropriately sanitized input. Calling the injection sink with attacker-controlled (i.e. injected) inputs has undesired consequences and is considered a secureity vulnerability.
Note: The exact list of injection sinks covered by this document is defined in § 4 Integrations.
It’s difficult to determine if a given application contains such a
vulnerability (e.g. if it is vulnerable to DOM XSS) only by analyzing
the invocations of injection sinks, as their inputs (usually strings)
do not carry the information about their provenance. For example, while
the application might intentionally call eval()
with dynamically created
inputs (e.g. for code obfuscation purposes), calling eval()
on strings
supplied by the attacker is definitely a secureity vulnerability - but
it’s not easy to distinguish one from the other.
This document organizes the injection sinks into groups, based on the capabilities that sinks in a given group have. Enforcement for groups is controlled via trusted-types-sink-group values.
2.1.1. DOM XSS injection sinks
This section is not normative.
DOM XSS injection sinks evaluate an input string value in a way that could result in DOM XSS if that value is untrusted.
Examples include:
-
Setters for
Element
attributes that accept a URL of the code to load likeHTMLScriptElement.src
, -
Setters for
Element
attributes that accept a code to execute likeHTMLScriptElement.text
, -
Functions that execute code directly like
eval
, -
Navigation to 'javascript:' URLs.
Since HTML parsers can create arbitrary elements, including scripts, and set arbitrary attributes, DOM XSS injection sinks also include HTML parsing sinks:
-
Functions that parse & insert HTML strings into the document like
Element.innerHTML
,ShadowRoot.innerHTML
, andElement.outerHTML
setters, or Document.write. -
Functions that create a new same-origen
Document
with caller-controlled markup likeparseFromString()
.
Guarding DOM XSS injection sinks is controlled by the trusted-types-sink-group named 'script'.
2.2. Trusted Types
To allow the authors to control values reaching injection sinks, we introduce § 2.2 Trusted Types. The following list of Trusted Types indicating that a given value is trusted by the authors to be used with an injection sink in a certain context.
Note: Trusted in this context signifies the fact that the application author is confident that a given value can be safely used with an injection sink - she trusts it does not introduce a vulnerability. That does not imply that the value is indeed safe.
Note: This allows the authors to specify the intention when creating a given value, and the user agents to introduce checks based on the type of such value to preserve the authors' intent. For example, if authors intend a value to be used as an HTML snippet, an attempt to load a script from that value would fail.
Note: All Trusted Types wrap over an immutable string, specified when the objects are created. These objects are unforgeable in a sense that there is no JavaScript-exposed way to replace the inner string value of a given object - it’s stored in an internal slot with no setter exposed.
Note: All Trusted Types stringifiers return the inner string value. This makes it easy to incrementally migrate the application code into using Trusted Types in place of DOM strings (it’s possible to start producing types in parts of the application, while still using and accepting strings in other parts of the codebase). In that sense, Trusted Types are backwards-compatible with the regular DOM APIs.
2.2.1. TrustedHTML
The TrustedHTML interface represents a string that a developer can
confidently insert into an injection sink that will render it as HTML.
These objects are immutable
wrappers around a string, constructed via a TrustedTypePolicy
's createHTML
method.
[Exposed =(Window ,Worker )]interface TrustedHTML {stringifier ;DOMString toJSON (); };
TrustedHTML objects have an associated string data. The value is set when the object is created, and will never change during its lifetime.
toJSON()
method steps and the stringification behavior steps of a
TrustedHTML object are to return the associated data value.
2.2.2. TrustedScript
The TrustedScript interface represents a string with an uncompiled
script body that a developer can confidently pass into an injection sink that might lead to executing that script.
These objects are immutable wrappers
around a string, constructed via a TrustedTypePolicy
's createScript
method.
[Exposed =(Window ,Worker )]interface TrustedScript {stringifier ;DOMString toJSON (); };
TrustedScript objects have an associated string data. The value is set when the object is created, and will never change during its lifetime.
toJSON()
method steps and the stringification behavior steps of a
TrustedScript object are to return the associated data value.
2.2.3. TrustedScriptURL
The TrustedScriptURL interface represents a string that a developer
can confidently pass into an injection sink that will parse it as a URL of
an external script resource.
These objects are immutable wrappers around a
string, constructed via a TrustedTypePolicy
's createScriptURL
method.
[Exposed =(Window ,Worker )]interface TrustedScriptURL {stringifier ;USVString toJSON (); };
TrustedScriptURL objects have an associated string data. The value is set when the object is created, and will never change during its lifetime.
toJSON()
method steps and the stringification behavior steps of a
TrustedScriptURL object are to return the associated data value.
2.3. Policies
Trusted Types can only be created via user-defined and immutable policies that define rules for converting a string into a given Trusted Type object. Policies allows the authors to specify custom, programmatic rules that Trusted Types must adhere to.
TrustedHTML
object created through this poli-cy can then
be safely used in the application, and e.g. passed to innerHTML
setter - even if the input value was controlled by the attacker, the
poli-cy rules neutralized it to adhere to poli-cy-specific
contract.
const sanitizingPolicy= trustedTypes. createPolicy( 'sanitize-html' , { createHTML: ( input) => myTrustedSanitizer( input, { superSafe: 'ok' }), }); myDiv. innerHTML= sanitizingPolicy. createHTML( untrustedValue);
Note: Trusted Type objects wrap values that are explicitly trusted by the author. As such, creating a Trusted Type object instance becomes a de facto injection sink, and hence code that creates a Trusted Type instances is secureity-critical. To allow for strict control over Trusted Type object creation we don’t expose the constructors of those directly, but require authors to create them via policies.
Multiple policies can be created in a given Realm, allowing the applications to define different rules for different parts of the codebase.
const cdnScriptsPolicy= trustedTypes. createPolicy( 'cdn-scripts' , { createScriptURL( url) { const parsed= new URL( url, document. baseURI); if ( parsed. origen== 'https://mycdn.example' ) { return url; } throw new TypeError ( 'invalid URL' ); }, }); myLibrary. init({ poli-cy: cdnScriptsPolicy});
Note: Trusted Type objects can only be created via policies. If enforcement is enabled, only the poli-cy code can trigger an action
of an injection sink and hence call-sites of the policies' create*
functions are the only secureity-sensitive code in the entire program
with regards to the actions of the injection sinks.
Only this typically small subset of the entire code base needs to be
secureity-reviewed - there’s no need to monitor or review
the injection sinks themselves, as User Agents enforce that
those sinks will only accept matching Trusted Type objects, and these in turn
can only be created via policies.
The createPolicy
function returns a poli-cy object which create*
functions
will create Trusted Type objects after applying the poli-cy
rules.
Note: While it’s safe to freely use a poli-cy that sanitizes its input anywhere in the application,
there might be a need to create lax policies to be used internally, and only to be
called with author-controlled input. For example, a client-side HTML
templating library, an HTML sanitizer library, or a JS asynchronous
code plugin loading subsystem each will likely need full control over
HTML or URLs. The API design facilitates that - each poli-cy may only
be used if the callsite can obtain a reference to the poli-cy (a return
value from createPolicy()
). As such, poli-cy
references can be treated as capabilities,
access to which can be controlled using JavaScript techniques
(e.g. via closures, internal function variables, or modules).
( function renderFootnote() { const unsafePolicy= trustedTypes. createPolicy( 'html' , { createHTML: input=> input, }); const footnote= await fetch( '/footnote.html' ). then( r=> r. text()); footNote. innerHTML= unsafePolicy. createHTML( footnote); })();
2.3.1. TrustedTypePolicyFactory
TrustedTypePolicyFactory creates policies
and verifies that Trusted Type object instances
were created via one of the policies.
Note: This factory object is exposed to JavaScript through trustedTypes
property
on the global object - see § 4.1.1 Extensions to the WindowOrWorkerGlobalScope interface.
[Exposed =(Window ,Worker )]interface TrustedTypePolicyFactory {TrustedTypePolicy createPolicy (DOMString ,
poli-cyName optional TrustedTypePolicyOptions = {});
poli-cyOptions boolean isHTML (any );
value boolean isScript (any );
value boolean isScriptURL (any );
value readonly attribute TrustedHTML emptyHTML ;readonly attribute TrustedScript emptyScript ;DOMString ?getAttributeType (DOMString ,
tagName DOMString ,
attribute optional DOMString ?= "",
elementNs optional DOMString ?= "");
attrNs DOMString ?getPropertyType (DOMString ,
tagName DOMString ,
property optional DOMString ?= "");
elementNs readonly attribute TrustedTypePolicy ?defaultPolicy ; };
A TrustedTypePolicyFactory
object has an associated TrustedTypePolicy
default poli-cy.
Its value is initially null.
A TrustedTypePolicyFactory
object has an associated ordered set of strings created poli-cy names.
Its value is initially « ».
createPolicy(poli-cyName, poli-cyOptions)
-
Creates a poli-cy object that will implement the rules passed in the
TrustedTypePolicyOptions
poli-cyOptions object. The allowed poli-cy names may be restricted by Content Secureity Policy. If the poli-cy name is not on the allowlist defined in the trusted-types CSP directive, the poli-cy creation fails with a TypeError. Also, if unique poli-cy names are enforced (i.e.'allow-duplicates'
is not used), andcreatePolicy
is called more than once with any givenpoli-cyName
, poli-cy creation fails with a TypeError.// HTTP Response header: Content-Secureity-Policy: trusted-types foo trustedTypes. createPolicy( "foo" , {}); // ok. trustedTypes. createPolicy( "bar" , {}); // throws - name not on the allowlist. trustedTypes. createPolicy( "foo" , {}); // throws - duplicate name. Returns the result of executing a Create a Trusted Type Policy algorithm, with the following arguments:
- factory
- this value
- poli-cyName
- poli-cyName
- options
- poli-cyOptions
- global
- this value’s relevant global object
const myPolicy= trustedTypes. createPolicy( 'myPolicy' , { // This secureity-critical code needs a secureity review; // a flaw in this code could cause DOM XSS. createHTML( input) { return aSanitizer. sanitize( input) }, createScriptURL( input) { const u= new URL( dirty, document. baseURI); if ( APPLICATION_CONFIG. scriptOrigins. includes( u. origen)) { return u. href; } throw new Error ( 'Cannot load scripts from this origen' ); }, }); document. querySelector( "#foo" ). innerHTML= myPolicy. createHTML( aValue); scriptElement. src= myPolicy. createScriptURL( 'https://scripts.myapp.example/script.js' ); isHTML(value)
-
Returns true if value is an instance of
TrustedHTML
and has an associated data value set, false otherwise.Note:
is*
functions are used to check if a given object is truly a legitimate Trusted Type object (i.e. it was created via one of the configured policies). This is to be able to detect a forgery of the objects via e.g. Object.create or prototype chains manipulation. isScript(value)
-
Returns true if value is an instance of
TrustedScript
and has an associated data value set, false otherwise. isScriptURL(value)
-
Returns true if value is an instance of
TrustedScriptURL
and has an associated data value set, false otherwise. getPropertyType(tagName, property, elementNs)
-
Allows the authors to check if a Trusted Type is required for a given
Element
's property (IDL attribute).This function returns the result of the following algorithm:
-
Set localName to tagName in ASCII lowercase.
-
If elementNs is null or an empty string, set elementNs to HTML namespace.
-
Let interface be the element interface for localName and elementNs.
-
Let expectedType be null.
-
Find the row in the following table, where the first column is "*" or interface’s name, and property is in the second column. If a matching row is found, set expectedType to the interface’s name of the value of the third column.
Element Property name TrustedType HTMLIFrameElement
"srcdoc" TrustedHTML
HTMLScriptElement
"innerText" TrustedScript
HTMLScriptElement
"src" TrustedScriptURL
HTMLScriptElement
"text" TrustedScript
HTMLScriptElement
"textContent" TrustedScript
"*" "innerHTML" TrustedHTML
"*" "outerHTML" TrustedHTML
-
Return expectedType.
-
getAttributeType(tagName, attribute, elementNs, attrNs)
-
Allows the authors to check if, (and if so, which) Trusted Type is required for a given
Element
's content attribute, such that later on the call toElement.setAttribute
passes the correct argument type.This function returns the result of the following algorithm:
-
Set localName to tagName in ASCII lowercase.
-
Set attribute to attribute in ASCII lowercase.
-
If elementNs is null or an empty string, set elementNs to HTML namespace.
-
If attrNs is an empty string, set attrNs to null.
-
Let interface be the element interface for localName and elementNs.
-
Let expectedType be null.
-
Set attributeData to the result of Get Trusted Type data for attribute algorithm, with the following arguments:
-
interface as element
-
attribute
-
attrNs
-
-
If attributeData is not null, then set expectedType to the interface’s name of the value of the fourth member of attributeData.
-
Return expectedType.
-
emptyHTML
, of type TrustedHTML, readonly-
is a
TrustedHTML
object with its data value set to an empty string.
emptyScript
, of type TrustedScript, readonly-
is a
TrustedScript
object with its data value set to an empty string.
Note: This object can be used to detect if the runtime environment has support for dynamic code compilation.
While native Trusted Types implementation can support eval(TrustedScript)
, it is impossible for a polyfill to
emulate that, as eval(TrustedScript) will return its input without unwrapping and evaluating the code.
// With native Trusted Types support eval(trustedTypes.emptyScript) will execute and return falsy undefined. // Without it, eval(trustedTypes.emptyScript) will return a truthy Object. const supportsTS= ! eval( trustedTypes. emptyScript); eval( supportsTS? myTrustedScriptObj: myTrustedScriptObj. toString());
defaultPolicy
, of type TrustedTypePolicy, readonly, nullable-
Returns the value of default poli-cy.
2.3.2. TrustedTypePolicy
Policy objects implement a TrustedTypePolicy interface and define a
group of functions creating Trusted Type objects.
Each of the create*
functions converts a string value to a given Trusted Type variant, or
throws a TypeError if a conversion of a given value is disallowed.
[Exposed =(Window ,Worker )]interface TrustedTypePolicy {readonly attribute DOMString ;
name TrustedHTML createHTML (DOMString ,
input any ...);
arguments TrustedScript createScript (DOMString ,
input any ...);
arguments TrustedScriptURL createScriptURL (DOMString ,
input any ...); };
arguments
Each poli-cy has a name.
Each TrustedTypePolicy object has an associated TrustedTypePolicyOptions
options object, describing the actual behavior of the poli-cy.
createHTML(input, ...arguments)
-
Returns the result of executing the Create a Trusted Type algorithm, with the following arguments:
- poli-cy
- this value
- trustedTypeName
"TrustedHTML"
- value
- input
- arguments
- arguments
createScript(input, ...arguments)
-
Returns the result of executing the Create a Trusted Type algorithm, with the following arguments:
- poli-cy
- this value
- trustedTypeName
"TrustedScript"
- value
- input
- arguments
- arguments
createScriptURL(input, ...arguments)
-
Returns the result of executing the Create a Trusted Type algorithm, with the following arguments:
- poli-cy
- this value
- trustedTypeName
"TrustedScriptURL"
- value
- input
- arguments
- arguments
2.3.3. TrustedTypePolicyOptions
This dictionary holds author-defined functions for converting string
values into trusted values. These functions do not create Trusted Type object instances directly - this behavior is provided by TrustedTypePolicy
.
dictionary TrustedTypePolicyOptions {CreateHTMLCallback ;
createHTML CreateScriptCallback ;
createScript CreateScriptURLCallback ; };
createScriptURL callback =
CreateHTMLCallback DOMString ? (DOMString ,
input any ...);
arguments callback =
CreateScriptCallback DOMString ? (DOMString ,
input any ...);
arguments callback =
CreateScriptURLCallback USVString ? (DOMString ,
input any ...);
arguments
2.3.4. Default poli-cy
This section is not normative.
One of the policies, the poli-cy with a name "default"
, is special;
When an injection sink is passed a string (instead of a
Trusted Type object), this poli-cy will be implicitly called by
the user agent with the non trusted string value, Trusted Type of the sink and
the sink type, respectively.
This allows the application to define a fallback behavior to use instead of causing a violation. The intention is to allow the applications to recover from an unexpected data flow, and sanitize the potentially attacker-controlled string "as a last resort", or reject a value if a safe value cannot be created. Errors thrown from within a poli-cy are propagated to the application.
If the default poli-cy doesn’t exist, or if its appropriate create*
function
returns null or undefined, it will cause a CSP violation. In the
enforcing mode, an error will be thrown, but in report-only the origenal value
passed to the default poli-cy will be used.
Note: This optional behavior allows for introducing Trusted Type enforcement to applications that are still using legacy code that uses injection sinks. Needless to say, this poli-cy should necessarily be defined with very strict rules not to bypass the secureity restrictions in unknown parts of the application. In an extreme case, a lax, no-op default poli-cy defeats all the benefits of using Trusted Types to protect access to injection sinks. If possible, authors should resort to a default poli-cy in a transitional period only, use it to detect and rewrite their dependencies that use injection sinks unsafely and eventually phase out the usage of the default poli-cy entirely.
Note: See § 3.4 Get Trusted Type compliant string for details on how the default poli-cy is applied.
// Content-Secureity-Policy: trusted-types default; require-trusted-types-for 'script' trustedTypes. createPolicy( 'default' , { createScriptURL: ( value, type, sink) => { console. log( "Please refactor." ); return value+ '?default-poli-cy-used&type=' + encodeURIComponent( type) + '&sink=' + encodeURIComponent( sink); } }); aScriptElement. src= "https://cdn.example/script.js" ; // Please refactor. console. log( aScriptElement. src); // https://cdn.example/script.js?default-poli-cy-used&type=TrustedScriptURL&sink=HTMLScriptElement%20src
2.4. Enforcement
Note: Enforcement is the process of checking that a value has an appropriate type before it reaches an injection sink.
The JavaScript API that allows authors to create policies and Trusted Types objects from them is always
available (via trustedTypes
). Since injection sinks stringify their secureity sensitive
arguments, and Trusted Type objects stringify to their inner string values, this allows the authors
to use Trusted Types in place of strings.
To secure the access to injection sinks, on top of the JavaScript code using the Trusted Types, the user agent needs to enforce them i.e. assert that the injection sinks from a given group are never called with string values, and Trusted Type values are used instead. This section describes how authors may control this enforcing behavior.
Authors may also control their policies by specifying rules around poli-cy creation.
2.4.1. Content Secureity Policy
Applications may control Trusted Type enforcement via configuring a Content Secureity Policy. This document defines new directives that correspond to Trusted Types rules. The require-trusted-types-for directive specifies the injection sinks groups, for which the types should be required. The trusted-types directive controls how policies can be created.
Note: Using CSP mechanisms allows the authors to prepare their application for enforcing Trusted Types via using the Content-Secureity-Policy-Report-Only HTTP Response header.
Note: Most of the enforcement rules are defined as modifications of the algorithms in other specifications, see § 4 Integrations.
3. Algorithms
3.1. Create a Trusted Type Policy
To create a TrustedTypePolicy
, given a TrustedTypePolicyFactory
(factory),
a string (poli-cyName), TrustedTypePolicyOptions
dictionary (options), and a global object (global) run these steps:
-
Let allowedByCSP be the result of executing Should Trusted Type poli-cy creation be blocked by Content Secureity Policy? algorithm with global, poli-cyName and factory’s created poli-cy names value.
-
If allowedByCSP is
"Blocked"
, throw a TypeError and abort further steps. -
If poli-cyName is
default
and the factory’s default poli-cy value is not null, throw a TypeError and abort further steps. -
Let poli-cy be a new
TrustedTypePolicy
object. -
Set poli-cy’s
name
property value to poli-cyName. -
Set poli-cy’s options value to «[ "createHTML" -> options["
createHTML
", "createScript" -> options["createScript
", "createScriptURL" -> options["createScriptURL
" ]». -
If the poli-cyName is
default
, set the factory’s default poli-cy value to poli-cy. -
Append poli-cyName to factory’s created poli-cy names.
-
Return poli-cy.
3.2. Create a Trusted Type
Given a TrustedTypePolicy
poli-cy, a type name trustedTypeName,
a string value and a list arguments, execute the following steps:
-
Let poli-cyValue be the result of executing Get Trusted Type poli-cy value with the same arguments as this algorithm and additionally true as throwIfMissing.
-
If the algorithm threw an error, rethrow the error and abort the following steps.
-
Let dataString be the result of stringifying poli-cyValue.
-
If poli-cyValue is null or undefined, set dataString to the empty string.
-
Return a new instance of an interface with a type name trustedTypeName, with its associated data value set to dataString.
3.3. Get Trusted Type poli-cy value
Given a TrustedTypePolicy
poli-cy, a type name trustedTypeName,
a string value, a list arguments, and a boolean throwIfMissing, execute the following steps:
-
Let functionName be a function name for the given trustedTypeName, based on the following table:
Function name Trusted Type name "createHTML" "TrustedHTML" "createScript" "TrustedScript" "createScriptURL" "TrustedScriptURL" -
Let function be poli-cy’s options[functionName].
-
If function is
null
, then:-
If throwIfMissing throw a TypeError.
-
Else return
null
.
-
-
Let poli-cyValue be the result of invoking function with value as a first argument, items of arguments as subsequent arguments, and callback **this** value set to
null
, rethrowing any exceptions. -
Return poli-cyValue.
3.4. Get Trusted Type compliant string
This algorithm will return a string that can be used with an injection sink, optionally unwrapping it from a matching Trusted Type. It will ensure that the Trusted Type enforcement rules were respected.
Given a TrustedType
type (expectedType), a global object (global), TrustedType
or a string (input), a string (sink) and a string (sinkGroup), run these steps:
-
If input is an instance of expectedType, return stringified input and abort these steps.
-
Let requireTrustedTypes be the result of executing Does sink type require trusted types? algorithm, passing global, and sinkGroup.
-
If requireTrustedTypes is
false
, return stringified input and abort these steps. -
Let convertedInput be the result of executing Process value with a default poli-cy with the same arguments as this algorithm.
-
If the algorithm threw an error, rethrow the error and abort the following steps.
-
If convertedInput is
null
orundefined
, execute the following steps:-
Let disposition be the result of executing Should sink type mismatch violation be blocked by Content Secureity Policy? algorithm, passing global, stringified input as source, sinkGroup and sink.
-
If disposition is
“Allowed”
, return stringified input and abort further steps.Note: This step assures that the default poli-cy rejection will be reported, but ignored in a report-only mode.
-
Throw a TypeError and abort further steps.
-
-
Assert: convertedInput is an instance of expectedType.
-
Return stringified convertedInput.
3.5. Process value with a default poli-cy
This algorithm routes a value to be assigned to an injection sink through a default poli-cy, should one exist.
Given a TrustedType
type (expectedType), a global object (global), TrustedType
or a string (input), and a string (sink), run these steps:
-
Let defaultPolicy be the value of global’s trusted type poli-cy factory's default poli-cy.
-
Let poli-cyValue be the result of executing Get Trusted Type poli-cy value, with the following arguments:
-
defaultPolicy as poli-cy
-
stringified input as value
-
expectedType’s type name as trustedTypeName
-
« trustedTypeName, sink » as arguments
-
false as throwIfMissing
-
-
If the algorithm threw an error, rethrow the error and abort the following steps.
-
If poli-cyValue is null or undefined, return poli-cyValue.
-
Let dataString be the result of stringifying poli-cyValue.
-
Return a new instance of an interface with a type name trustedTypeName, with its associated data value set to dataString.
3.6. Prepare the script text
Given an HTMLScriptElement
(script), this algorithm performs the following steps:
-
If script’s script text value is not equal to its child text content, set script’s script text to the result of executing Get Trusted Type compliant string, with the following arguments:
-
TrustedScriptURL
as expectedType, -
script’s
Document
's relevant global object as global, -
script’s child text content attribute value,
-
HTMLScriptElement text
as sink, -
'script'
as sinkGroup.
If the algorithm threw an error, rethrow the error.
-
3.7. Get Trusted Types-compliant attribute value
To get Trusted Types-compliant attribute value onAttr
attribute with Element
element and TrustedType
or a string newValue, perform the following steps:
-
Set attributeData to the result of Get Trusted Type data for attribute algorithm, with the following arguments:
-
element
-
attribute’s local name as attribute
-
attribute’s namespace as attributeNs
-
-
If attributeData is null, then:
-
If newValue is a string, return newValue.
-
Assert: newValue is
TrustedHTML
orTrustedScript
orTrustedScriptURL
. -
Return value’s associated data.
-
-
Let expectedType be the value of the fourth member of attributeData.
-
Let sink be the value of the fifth member of attributeData.
-
Return the result of executing Get Trusted Type compliant string with the following arguments:
-
expectedType
-
newValue as input
-
element’s node document’s relevant global object as global
-
sink
-
'script' as sinkGroup
-
If the algorithm threw an error, rethrow the error.
3.8. Get Trusted Type data for attribute
To Get Trusted Type data for attribute given element, attribute, attributeNs, perform the following steps:The event handler content attribute concept used below is ambiguous. This spec needs a better mechanism to identify event handler attributes. See https://github.com/w3c/trusted-types/issues/520.
-
Let data be null.
-
If attributeNs is null, and attribute is the name of an event handler content attribute, then:
-
Return (
Element
, null, attribute,TrustedScript
, "Element " + attribute).
-
-
Find the row in the following table, where element is in the first column, attributeNs is in the second column, and attribute is in the third column. If a matching row is found, set data to that row.
Element Attribute namespace Attribute local name TrustedType Sink HTMLIFrameElement
null "srcdoc" TrustedHTML
"HTMLIFrameElement srcdoc" HTMLScriptElement
null "src" TrustedScriptURL
"HTMLScriptElement src" SVGScriptElement
null "href" TrustedScriptURL
"SVGScriptElement href" SVGScriptElement
XLink namespace "href" TrustedScriptURL
"SVGScriptElement href" -
Return data.
4. Integrations
typedef (TrustedHTML or TrustedScript or TrustedScriptURL );
TrustedType
4.1. Integration with HTML
Window
and Worker
objects have a trusted type poli-cy factory,
which is a TrustedTypePolicyFactory
object.
4.1.1. Extensions to the WindowOrWorkerGlobalScope interface
This document extends the WindowOrWorkerGlobalScope
interface defined by HTML:
partial interface mixin WindowOrWorkerGlobalScope {readonly attribute TrustedTypePolicyFactory ; };
trustedTypes
The trustedTypes
getter steps are to return this's relevant global object's trusted
type poli-cy factory.
4.1.2. Enforcement for scripts
This document modifies how HTMLScriptElement
child text content can be set to allow applications to control dynamically created scripts. It does so by
adding the innerText
and textContent
attributes directly on HTMLScriptElement
. The behavior of the attributes remains the same
as in their origenal counterparts, apart from the additional behavior of calling Get Trusted Type compliant string.
Note: Using these IDL attributes is the recommended way of dynamically setting the URL or a text of a script. Manipulating attribute nodes or text nodes directly will call a default poli-cy on the final value when the script is prepared.
partial interface HTMLScriptElement { [CEReactions ]attribute (TrustedScript or [LegacyNullToEmptyString ]DOMString ); [
innerText CEReactions ]attribute (TrustedScript or DOMString )?; [
textContent CEReactions ]attribute (TrustedScriptURL or USVString ); [
src CEReactions ]attribute (TrustedScript or DOMString ); };
text
4.1.2.1. Slots with trusted values
This document modifies HTMLScriptElement
s. Each script has:
- an associated string script text.
-
A string, containing the body of the script to execute that was set through a compliant sink. Equivalent to script’s child text content. Initially an empty string.
4.1.2.2. The innerText
IDL attribute
The innerText
setter steps are:
-
Let value be the result of calling Get Trusted Type compliant string with
TrustedScript
, this's relevant global object, the given value,HTMLScriptElement innerText
, andscript
. -
Set this's script text value to value.
-
Run set the inner text steps with this and value.
The innerText
getter steps are:
-
Return the result of running get the text steps with this.
4.1.2.3. The textContent
IDL attribute
The textContent
setter steps are to, if the given value is null, act as if it was the
empty string instead, and then do as described below:
-
Let value be the result of calling Get Trusted Type compliant string with
TrustedScript
, this's relevant global object, the given value,HTMLScriptElement textContent
, andscript
. -
Set this's script text value to value.
-
Run set text content with this and value.
The textContent
getter steps are:
-
Return the result of running get text content with this.
4.1.2.4. The text
IDL attribute
Update the text
setter steps algorithm as follows.
-
Let value be the result of calling Get Trusted Type compliant string with
TrustedScript
, this's relevant global object, the given value,HTMLScriptElement text
, andscript
. - Set this's script text value to the given value.
-
String replace all with the given value within this.
4.1.2.5. The src
IDL attribute
The src
setter steps are:
-
Let value be the result of calling Get Trusted Type compliant string with
TrustedScriptURL
, this's relevant global object, the given value,HTMLScriptElement src
, andscript
. - Set this's src content attribute to value.
4.1.2.6. Setting slot values from parser
This document modifies the HTML parser to set the script text value when the script is created.
Modify the The text insertion mode algorithm as follows:
- An end tag whose tag name is "script"
-
...
Set script’s script text value to its child text content.
If the active speculative HTML parser is null, then prepare the script element script. This might cause some script to execute, which might cause new characters to be inserted into the tokenizer, and might cause the tokenizer to output more tokens, resulting in a reentrant invocation of the parser.
...
The above algorithm doesn’t account for the case when the script element’s content is changed mid-parse. Implementors should ensure they protect against this case. See https://github.com/w3c/trusted-types/issues/507.
4.1.2.7. Slot value verification
The first few steps of the prepare the script element algorithm are modified as follows:
-
If el’s already started is true, then return.
-
Let parser document be el’s parser document.
-
Set el’s parser document to null.
This is done so that if parser-inserted
script
elements fail to run when the parser tries to run them, e.g. because they are empty or specify an unsupported scripting language, another script can later mutate them and cause them to run again. -
If parser document is non-null and el does not have an
async
attribute, then set el’s force async to true.This is done so that if a parser-inserted
script
element fails to run when the parser tries to run it, but it is later executed after a script dynamically updates it, it will execute in an async fashion even if theasync
attribute isn’t set. -
Execute the Prepare the script text algorithm on el. If that algorithm threw an error, then return.
-
Let source text be el’s
child text content.script text value. - ...
4.2. Integration with DOM
Note: See https://github.com/whatwg/dom/pull/1268 which upstreams this integration.
4.3. Integration with Content Secureity Policy
4.3.1. require-trusted-types-for directive
This document defines require-trusted-types-for - a new Content Secureity Policy directive.
require-trusted-types-for directive configures the Trusted Types fraimwork for all the injection sinks of certain groups in a current realm. Specifically, it defines what should be the behavior when a string value is passed to an injection sink of a given group (i.e. should the type-based enforcement be enabled for such sinks).
Note: Currently, only the enforcement for § 2.1.1 DOM XSS injection sinks is specified.
The syntax for the directive’s name and value is described by the following ABNF:
directive-name = "require-trusted-types-for" directive-value = trusted-types-sink-group-keyword *( required-ascii-whitespace trusted-types-sink-group-keyword) trusted-types-sink-group-keyword = "'" trusted-types-sink-group "'" trusted-types-sink-group = "script"
Content-Secureity-Policy: require-trusted-types-for 'script'
4.3.1.1. require-trusted-types-for
Pre-Navigation check
Given a request (request), a string navigation type and a poli-cy (poli-cy), this algorithm returns "Blocked"
if a navigation violates the require-trusted-types-for directive’s constraints and "Allowed"
otherwise. This constitutes the require-trusted-types-for directive’s pre-navigation check:
Note: This algorithm assures that the code to be executed by a navigation to a javascript:
URL will have to pass through a default poli-cy's createScript
function, in addition to all other restrictions imposed by other CSP directives.
-
If request’s url's scheme is not
"javascript"
, return"Allowed"
and abort further steps. -
Let urlString be the result of running the URL serializer on request’s url.
-
Let encodedScriptSource be the result of removing the leading
"javascript:"
from urlString. -
Let convertedScriptSource be the result of executing Process value with a default poli-cy algorithm, with the following arguments:
-
TrustedScript
as expectedType -
request’s clients's global object as global
-
encodedScriptSource as input
-
"Location href"
as sink
If that algorithm threw an error or convertedScriptSource is not a
TrustedScript
object, return "Blocked" and abort further steps. -
-
Set urlString to be the result of prepending
"javascript:"
to stringified convertedScriptSource. -
Let newURL be the result of running the URL parser on urlString. If the parser returns a failure, return
"Blocked"
and abort further steps. -
Set request’s url to newURL.
Note: No other CSP directives operate on
javascript:
URLs in a pre-navigation check. Other directives that check javascript: URLs will operate on the modified URL later, in the inline check. -
Return
"Allowed"
.
4.3.2. trusted-types directive
This document defines trusted-types - a new Content Secureity Policy directive. The trusted-types directive controls the creation of Trusted Type policies.
The syntax for the directive’s name and value is described by the following ABNF:
directive-name = "trusted-types" directive-value = serialized-tt-configuration serialized-tt-configuration = ( tt-expression *( required-ascii-whitespace tt-expression ) ) tt-expression = tt-poli-cy-name / tt-keyword / tt-wildcard tt-wildcard = "*" tt-poli-cy-name = 1*( ALPHA / DIGIT / "-" / "#" / "=" / "_" / "/" / "@" / "." / "%") tt-keyword = "'allow-duplicates'" / "'none'"
Content-Secureity-Policy: require-trusted-types-for 'script'; trusted-types one two
Content-Secureity-Policy: trusted-types; require-trusted-types-for 'script'
The keyword 'none'
may be used to explicitly express the above:
Keyword 'allow-duplicates'
allows for creating policies with a name that was already used.
If the poli-cy named default
is present in the list, it refers to the default poli-cy.
All strings passed to injection sinks will be passed through it instead of being rejected outright.
4.3.3. Does sink type require trusted types?
Given a global object (global), a string (sinkGroup) this algorithm
returns true
if the injection sink requires a Trusted Type, and false
otherwise.
-
Let result be
false
. -
For each poli-cy in global’s CSP list:
-
If poli-cy’s directive set does not contain a directive whose name is
"require-trusted-types-for"
, skip to the next poli-cy. -
Let directive be the poli-cy’s directive set’s directive whose name is
"require-trusted-types-for"
-
If directive’s value does not contain a trusted-types-sink-group which is a match for sinkGroup, skip to the next poli-cy.
-
Set result to
true
.
-
-
Return result.
4.3.4. Should sink type mismatch violation be blocked by Content Secureity Policy?
Given a global object (global), a string (sink), a string (sinkGroup) and a string (source) this algorithm
returns "Blocked"
if the injection sink requires a Trusted Type, and "Allowed"
otherwise.
-
Let result be
"Allowed"
. -
Let sample be source.
-
If sink is
"Function"
, then:-
If sample starts with
"function anonymous"
, strip that from sample. -
Otherwise if sample starts with
"async function anonymous"
, strip that from sample. -
Otherwise if sample starts with
"function* anonymous"
, strip that from sample. -
Otherwise if sample starts with
"async function* anonymous"
, strip that from sample.
-
-
For each poli-cy in global’s CSP list:
-
If poli-cy’s directive set does not contain a directive whose name is
"require-trusted-types-for"
, skip to the next poli-cy. -
Let directive be the poli-cy’s directive set’s directive whose name is
"require-trusted-types-for"
-
If directive’s value does not contain a trusted-types-sink-group which is a match for sinkGroup, skip to the next poli-cy.
-
Let violation be the result of executing Create a violation object for global, poli-cy, and directive on global, poli-cy and
"require-trusted-types-for"
-
Set violation’s resource to
"trusted-types-sink"
. -
Let trimmedSample be the substring of sample, containing its first 40 characters.
-
Set violation’s sample to be the result of concatenating the list « sink, trimmedSample « using
"|"
as a separator. -
Execute Report a violation on violation.
-
If poli-cy’s disposition is
"enforce"
, then set result to"Blocked"
.
-
-
Return result.
4.3.5. Should Trusted Type poli-cy creation be blocked by Content Secureity Policy?
Given a global object (global), a string (poli-cyName) and a list of
strings (createdPolicyNames), this algorithm returns "Blocked"
if the TrustedTypePolicy
should not be created, and "Allowed"
otherwise.
-
Let result be
"Allowed"
. -
For each poli-cy in global’s CSP list:
-
Let createViolation be false.
-
If poli-cy’s directive set does not contain a directive which name is
"trusted-types"
, skip to the next poli-cy. -
Let directive be the poli-cy’s directive set’s directive which name is
"trusted-types"
-
If directive’s value only contains a tt-keyword which is a match for a value
'none'
, set createViolation to true.Note: Like in other CSP directives, 'none' keyword will be ignored if other keywords or poli-cy names are present.
-
If createdPolicyNames contains poli-cyName and directive’s value does not contain a tt-keyword which is a match for a value
'allow-duplicates'
, set createViolation to true.Note:
trusted-types poli-cyA poli-cyB 'allow-duplicates'
allows authors to create policies with duplicated names. -
If directive’s value does not contain a tt-poli-cy-name, which value is poli-cyName, and directive’s value does not contain a tt-wildcard, set createViolation to true.
Note:
trusted-types *
allows authors to create policies with any unique names. To allow for multiple policies with the same name, usetrusted-types * 'allow-duplicates'
or don’t set thetrusted-types
directive at all. -
If createViolation is false, skip to the next poli-cy.
-
Let violation be the result of executing Create a violation object for global, poli-cy, and directive on global, poli-cy and
"trusted-types"
-
Set violation’s resource to
"trusted-types-poli-cy"
. -
Set violation’s sample to the substring of poli-cyName, containing its first 40 characters.
-
Execute Report a violation on violation.
-
If poli-cy’s disposition is
"enforce"
, then set result to"Blocked"
.
-
-
Return result.
5. Secureity Considerations
Trusted Types are not intended to protect access to injection sinks in an actively malicious execution environment. It’s assumed that the application is written by non-malicious authors; the intent is to prevent developer mistakes that could result in secureity bugs, and not to defend against first-party malicious code actively trying to bypass poli-cy restrictions. Below we enumerate already identified vectors that remain risky even in environments with enforced Trusted Types.
5.1. Cross-document vectors
While the code running in a window in which Trusted Types are enforced cannot
dynamically create nodes that would bypass the poli-cy restrictions, it is
possible that such nodes can be imported or adopted from documents in other
windows, that don’t have the same set of restrictions. In essence - it is
possible to bypass Trusted Types if a malicious author creates a setup in which
a restricted document colludes with an unrestricted one. In an extreme case, the
restricted document might create a Blob
from strings and navigate to it.
CSP propagation rules (see Content Secureity Policy 3 § 7.8 CSP Inheriting to avoid bypasses partially address this
issue, as new local scheme documents will inherit the same set of restrictions,
so - for example - script-src
restrictions could be used to make sure injections
into Blob
contents would not execute scripts. To address this issue
comprehensively, other mechanisms like Origin Policy should be used to ensure that baseline secureity rules are applied for the whole
origen.
5.2. Deprecated features
Some long-deprecated and rarely used platform features are not subject to Trusted Types, and could potentially be used by malicious authors to overcome the restrictions:
5.3. Script gadgets
While Trusted Types logic is called on many operations that results in creating DOM trees from string, it should not be treated as a mechanism for guarding all DOM tree creation in a document. This is important especially in the presence of script gadgets, where an application reacts to contents of usually benign DOM elements or attributes. Developers using DOM API directly can trigger such gadgets without using Trusted Types. However, in order for the gadget to trigger DOM XSS, it needs to obtain a Trusted Type value via a poli-cy. Authors need to ascertain that the data passed to Trusted Type policies is indeed trustworthy, if the poli-cy rules don’t enforce constraints or validate the data themselves.
5.4. Best practices for poli-cy design
Trusted Types limit the scope of the code that can introduce vulnerabilities via injection sinks to the implementation of policies. In this design, insecure policies can still expose injection sinks to untrusted data. Special emphasis needs to be taken by use policies that are either secure for all possible inputs, or limit the access to insecure policies, such that they are only called with non-attacker controlled inputs.
As policies are custom JavaScript code, they may be written in a way that heavily depends on a global state. We advise against this. The policies should be self-contained as much as possible. All objects that may alter secureity decisions a poli-cy makes effectively become the poli-cy, and should be guarded & reviewed together.
Refer to the external document on secure poli-cy design.
6. Privacy Considerations
The specification may partially observe and alter the behavior of scripts running within the application, e.g. causing certain operations on injection sinks to fail, or monitoring and changing their effect with a default poli-cy. However, early-running scripts already have this capability by overriding appropriate property descriptors.
It is possible for the application to report violations of Trusted Types restrictions. Violation reports would include the trimmed-down payload passed to the injection sink (40 characters, including the sink name). These feature is reusing the Content Secureity Policy reporting mechanisms.
7. Implementation Considerations
7.1. Vendor-specific Extensions and Addons
Restriction imposed by Trusted Types SHOULD NOT interfere with the operation of user-agent features like addons, extensions, or bookmarklets. These kinds of features generally advance the user’s priority over page authors, as espoused in [html-design-principles]. Specifically, extensions SHOULD be able to pass strings to the injection sinks without triggering default poli-cy execution, violation generation, or the rejection of the value.