1. Introduction
This section is not normative.
DOM-Based Cross-Site Scripting (DOM XSS) occurs when a web application takes a string value from an attacker-controlled source (e.g. the document URL parameter, or postMessage channel) and passes that value to one of the injection sinks, that eventually causes execution of the script payload controlled by the attacker.
This vulnerability type is prevalent in the web applications for two
reasons. For one, it’s easy to introduce - there are over 60 different
injection sinks (e.g. Element.innerHTML
, or Location.href
setters).
A lot of those sinks are widely used, and are often passed an attacker-controlled
value without the developer realizing it. Secondly, DOM XSS is
difficult to prevent. Due to the dynamic nature of JavaScript it’s
difficult to ascertain that this vulnerability is not present in a
given program - as such, DOM XSS is often missed during manual code
reviews, and automated code analysis. As an example, foo[bar] = aString
is a statement that potentially introduces DOM XSS.
This document defines Trusted Types - an API that allows applications to lock down DOM XSS 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 writing values to the DOM, and reducing the DOM XSS 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 accidental DOM XSS introduction by the authors.
-
Encourage a design in which XSS-related security decisions are encapsulated within a small part of the application.
-
Reduce DOM XSS security review surface for complex web application codebases.
1.2. Non-goals
-
Address injections into server-side generated markup, in specific reflections into the body of the scripts running in a document.
mention other solutions, like templating systems, or CSP for mitigating
1.3. Use cases
figure out if we need this section here. CSP has none, SRI has one and it looks useful.
-
An author maintains a complex web application written in a framework 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 introduces DOM XSS vulnerabilities, author defines a Trusted Type policy in the templating policy and enables the enforcement for the DOM sinks.
2. Framework
2.1. Injection sinks
This section is not normative.
A DOM XSS injection sink is a function that evaluates an input string value in a way that could result in XSS if that value is untrusted.
Examples of injection sinks include:
-
Functions that parse & insert HTML strings into he document like Element.innerHTML setter
-
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
. -
Functions that accept URLs with
javascript:
scheme -
Functions that create a new same-origin
Document
with caller-controlled markup likeparseFromString()
.
An application is vulnerable to DOM XSS if it permits a flow of data from an attacker-controlled source and permits that data to reach an injection sink without appropriate validation, sanitization or escaping.
It’s difficult to determine if DOM XSS is present by analyzing the invocations of injection sinks, as the strings do not carry the information about the provenance of their value. To allow the authors to control values reaching sensitive DOM and JavaScript functions, we introduce Trusted Types.
Note: The exact list of injection sinks covered by this document is defined in §4 Integrations.
Consider surfacing the DOM sink (node + attr) => type mapping in the API, to faciliate building HTML sanitizers. <https://github.com/WICG/trusted-types/issues/43>
2.2. Trusted Types
We introduce 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 the authors intends a value to be used as a URL of an image, an attempt to load a script from that URL would fail.
Note: All Trusted Types wrap over an immutable string, specified when the objects are created. These objects are unforgable 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 ]interface {
TrustedHTML stringifier ; };
TrustedHTML objects have a [[Data]]
internal slot which holds a
DOMString. The slot’s value is set when the object is created, and
will never change during its lifetime.
To stringify a TrustedHTML object, return the DOMString from its [[Data]]
internal slot.
Add TrustedHTML.EMPTY. <https://github.com/WICG/trusted-types/issues/95>
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 ]interface {
TrustedScript stringifier ; };
TrustedScript objects have a [[Data]]
internal slot which holds a
DOMString. The slot’s value is set when the object is created, and
will never change during its lifetime.
To stringify a TrustedScript object, return the DOMString from its [[Data]]
internal slot.
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 ]interface {
TrustedScriptURL stringifier ; };
TrustedScriptURL objects have a [[Data]]
internal slot which holds a
USVString. The slot’s value is set when the object is created, and
will never change during its lifetime.
To stringify a TrustedScriptURL object, return the USVString from its [[Data]]
internal slot.
2.2.4. TrustedURL
The TrustedScriptURL interface represents a string that a developer
can confidently pass into an injection sink that will be parse it a URL of
an external resource that is not scripted.
These objects are immutable wrappers around a
string, constructed via a TrustedTypePolicy
's createURL
method.
[Exposed =Window ]interface {
TrustedURL stringifier ; };
TrustedURL objects have a [[Data]]
internal slot which holds a
USVString. The slot’s value is set when the object is created, and
will never change during its lifetime.
To stringify a TrustedURL object, return the USVString from its [[Data]]
internal slot.
Consider adding new set of types, e.g. related to CSS. <https://github.com/WICG/trusted-types/issues/104>
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 policy 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
policy rules neutralized it to adhere to policy-specific
contract.
const sanitizingPolicy= TrustedTypes. createPolicy( 'sanitize-html' , { createHTML: ( input) => myTrustedSanitizer( input, { superSafe: 'ok' }), }, /* expose = */ true ); 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 DOM XSS injection sink, and hence code that creates Trusted Type instances is security-critical. To allow for strict control over Trusted Type object creation we don’t expose the constructors of those directly, but require policy usage.
There can be multiple policies for a document, 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. origin== 'https://mycdn.example' ) { return URL. toString(); } throw new TypeError( 'invalid URL' ); }, }); myLibrary. init({ policy: cdnScriptsPolicy});
Note: As Trusted Type objects can only be created via policies, if enforcement is enabled, only the policy code can introduce a DOM XSS, and hence call-sites of the policies' factory functions are the only security-sensitive code in the entire program. Only this typically small subset of the entire code base needs to be security-reviewed for DOM XSS - there’s no need to monitor or review the traditional DOM sinks, as User Agents enforce that those sinks will only accept Trusted Type objects, and these in turn can only be created via policies.
The createPolicy
function returns a policy object whose create* functions
will create Trusted Type objects after applying the policy
rules. Policies may also be optionally exposed, allowing callers to
obtain a reference to the policy object from the global registry.
Note: While it’s safe to globally expose a policy that sanitizes its input
(and allow any part of the application to use it), 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 policy may only
be used if the callsite can obtain a reference to the policy (a return
value from createPolicy()
). As such, policy
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 window.TrustedTypes
reference - see §4.1.2 Extensions to the Window interface.
[Exposed =Window ]interface { [
TrustedTypePolicyFactory Unforgeable ]TrustedTypePolicy createPolicy (DOMString ,
policyName optional TrustedTypePolicyOptions ,
policyOptions optional boolean =
exposed false ); [Unforgeable ]TrustedTypePolicy getExposedPolicy (DOMString ); [
policyName Unforgeable ]sequence <DOMString >getPolicyNames (); [Unforgeable ]boolean isHTML (object ?); [
checkedObject Unforgeable ]boolean isScript (object ?); [
checkedObject Unforgeable ]boolean isScriptURL (object ?); [
checkedObject Unforgeable ]boolean isURL (object ?); };
checkedObject
Internal slot [[PolicyMap]]
contains a map, with each map entry
being a pair of a policy name (DOMString key) and the
TrustedTypePolicy (value).
Internal slot [[Configuration]]
stores the TrustedTypeConfiguration
to be applied for documents the factory is created for.
createPolicy(policyName, policyOptions, exposed)
-
Creates a uniquely named policy object that will implement the rules passed in the
TrustedTypePolicyOptions
object. Allowed policy names may be restricted by the Trusted-Types HTTP Response Header - if that is present, and the policy name is not on the whitelist defined in the header, the policy creation fails with a TypeError. Also, if createPolicy is called more than once with any given policyName, policy creation fails with a TypeError.// HTTP Response header: Trusted-Types: "foo" TrustedTypes. createPolicy( "foo" , {}); // ok. TrustedTypes. createPolicy( "bar" , {}); // throws - name not on the whitelist. TrustedTypes. createPolicy( "foo" , {}); // throws - duplicate name. The policy can also be optionally exposed, allowing for a policy retrieval via
getExposedPolicy(policyName)
.Returns the result of executing a Create a Trusted Type Policy algorithm, with the following arguments:
- factory
- context object
- policyName
- policyName
- exposed
- exposed
getPolicyNames()
-
Returns a new list, comprising of all keys of the
[[PolicyMap]]
internal slot map. getExposedPolicy(policyName)
-
Returns a policy object identified by a name, if that policy exists and is exposed. Returns the result of executing a Get exposed policy algorithm, with the following arguments:
- factory
- context object
- policyName
- policyName
isHTML(checkedObject)
-
Returns true if checkedObject is an instance of
TrustedHTML
and has its[[Data]]
internal slot set, false otherwise.Note:
is*
functions are used to check if a given object is truly a legitimate Trusted Type object (e.g. 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(checkedObject)
-
Returns true if checkedObject is an instance of
TrustedScript
and has its[[Data]]
internal slot set, false otherwise. isScriptURL(checkedObject)
-
Returns true if checkedObject is an instance of
TrustedScriptURL
and has its[[Data]]
internal slot set, false otherwise. isURL(checkedObject)
-
Returns true if checkedObject is an instance of
TrustedURL
and has its[[Data]]
internal slot set, false otherwise.
const myPolicy= TrustedTypes. createPolicy( 'myPolicy' , { // This needs security review, as it’s security critical code; // 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. origin)) { return u. href; } throw new Error( 'Cannot load scripts from this origin' ); }, }); TrustedTypes. getPolicyNames(); // ['myPolicy'] TrustedTypes. getExposedPolicy( 'myPolicy' ); // null document. querySelector( "#foo" ). innerHTML= myPolicy. createHTML( aValue); scriptElement. src= myPolicy. createScriptURL( 'https://scripts.myapp.example/script.js' );
2.3.2. TrustedTypePolicy
Policy objects implement a TrustedTypePolicy interface and define a group of functions creating Trusted Type objects. Each policy is identified by a name unique within a realm. 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 ]interface { [
TrustedTypePolicy Unforgeable ]readonly attribute DOMString ; [
name Unforgeable ]TrustedHTML createHTML (DOMString ); [
input Unforgeable ]TrustedScript createScript (DOMString ); [
input Unforgeable ]TrustedScriptURL createScriptURL (DOMString ); [
input Unforgeable ]TrustedURL createURL (DOMString ); };
input
Each TrustedTypePolicy object has an [[options]]
internal slot, holding the TrustedTypePolicyOptions
object describing the actual behavior of the policy.
createHTML(input)
-
Returns the result of executing the Create a Trusted Type algorithm, with the following arguments:
- policy
- context object
- trustedTypeName
"TrustedHTML"
- value
- input
createScript(input)
-
Returns the result of executing the Create a Trusted Type algorithm, with the following arguments:
- policy
- context object
- trustedTypeName
"TrustedScript"
- value
- input
createScriptURL(input)
-
Returns the result of executing the Create a Trusted Type algorithm, with the following arguments:
- policy
- context object
- trustedTypeName
"TrustedScriptURL"
- value
- input
createURL(input)
-
Returns the result of executing the Create a Trusted Type algorithm, with the following arguments:
- policy
- context object
- trustedTypeName
"TrustedURL"
- value
- input
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 CreateURLCallback ?;
createURL CreateScriptURLCallback ?;
createScriptURL boolean =
exposed false ; };callback =
CreateHTMLCallback DOMString (DOMString );
input callback =
CreateScriptCallback DOMString (DOMString );
input callback =
CreateURLCallback USVString (DOMString );
input callback =
CreateScriptURLCallback USVString (DOMString );
input
2.3.4. Default policy
This section is not normative.
One of the policies, the "default" policy, is special; while all other policies have to be called explicitly to create a TrustedType object, the default policy can also be called implicitly by the user agent. It allows the application to define the rules that should be run as a fallback, in case an injection sink is passed a string (instead of a Trusted Type object).
This optional behavior allows for introducing Trusted Type enforcement to applications that are still using legacy code that writes to the DOM
(or calls eval
) directly. Needless to say, this exposed policy should
necessarily be defined with very strict rules not to introduce a DOM
XSS vulnerability in unknown parts of the application. In an extreme
case, a lax, no-op default policy could bring the application DOM XSS
security posture back to the pre-Trusted Types level. If possible,
authors should resort to a default policy in a transitional period
only, use it to detect and rewrite "raw DOM writes" dependencies and
eventually phase out its usage entirely.
Note: See §3.2.2 Get Trusted Type compliant string for details on how the default policy is applied.
2.4. Enforcement
This section describes how applications may require Trusted Types values for their injection sinks via specifying a HTTP response header, and what actions should be undertaken if a string value is used instead.
Note: Most of the enforcement rules are defined as modifications of the algorithms in other specifiactions, see §4 Integrations.
2.4.1. TrustedTypeConfiguration
A Trusted Type Configuration defines enforcement setting for Trusted Types and restrictions on policy names that can be applied
to a Document
.
enum {
StringAtSinkDisposition ,
"reject" ,
"report" , };
"unsafe-allow" enum {
UnknownPolicyNameDisposition ,
"reject" , };
"allow" dictionary {
TrustedTypeConfiguration UnknownPolicyNameDisposition = "allow";
unknownPolicyName StringAtSinkDisposition ?;
domSinks sequence <DOMString >;
allowedNames DOMString = "default"; };
reportingGroup
Each Trusted Type Configuration has an associated string at sink disposition
(for all DOM sinks).
It is either “reject”, “report” or “unsafe-allow”.
Each Trusted Type Configuration has an associated unknown policy name disposition
,
which is either “reject” or “allow”.
Each Trusted Type Configuration has an associated allowed policy names set.
Each Trusted Type Configuration has a related reporting group name.
Decide if it should be possible from JS to determine if types are enforced without resorting to try {} catch
. <https://github.com/WICG/trusted-types/issues/36>
2.4.2. Trusted-Types HTTP Response Header
In the current Chromium implementation, the enforcement mechanism is
configured in the Content-Security-Policy
header (instead of Trusted-Types
), with slightly different syntax. See explainer and platform test files. <https://github.com/WICG/trusted-types/issues/1>
+mkwst The header does not appear in the origin trials. Can the spec differ so much from the implementation, especially given the upcoming Origin Trials?
The Trusted-Types HTTP response header instructs the user agent to apply a particular configuration of the Trusted Types framework to the document created from a given response. Specifically, the header value defines which policies (identified by name) can be created by the application, and what should be the behavior when a string value is passed to an injection sink (e.g. should the type-based enforcement be enabled, or whether to attempt implicit conversion with a default policy).
The header value is a serialized Trusted Types configuration represented by the following ANBF:
TRUSTEDTYPES = json-field-value
The header’s value is interpreted as a JSON-formatted array of values
without the outer [
and ]
, as described in Section 4 of [HTTP-JFV].
Note: The header syntax is tailored to making a secure configuration simple, while allowing explicit change towards less strict configurations possible.
Trusted-Types: "one", "two"
null
indicates policies may not be created, and sinks are
enforced. I.e. no injection sinks can be used in a document.
Trusted-Types: null
A policy named "*"
makes it possible to create policies with any
previously unused name.
If the policy named “default”
is present in the list, it refers to the default policy, and unless otherwise configured,
all strings passed to injection sinks will be passed through it instead
of being rejected outright.
To specify more fine-grained control over the enforcement, authors can use a header value that is an object. That object allows for configuring the enforcement for the injection sinks.
Trusted-Types: "*", {"dom”: "unsafe-allow"}
Report violations using a “trustedtypes” reporting group.
Trusted-Types: "*", {"report": "trustedtypes"}
Explicitly specify that a string passed to an injection sink requiring any Trusted Type should be rejected. This is the default behavior if the header is present.
Trusted-Types: "*", {"dom": "reject"}
Decide if separate per-type enforcement settings should be exposed to the authors. <https://github.com/WICG/trusted-types/issues/66>
it seems to be the case that one object is allowed and it should appear last, it cannot contain an allowedNames property and the allowedNames set should be the string values. Clarify.
maybe treat a string as a configuration that is equivalent to a
configuration that allows just that name and which has the default values
for the other properties and allow {"allowedNames":[...],...}
.
This would enable a use case where migrating one tool at a time by having
some policies that are report-only and others that are enforced.
if so, need example of 2 disjoint allowed name sets with different configurations.
what happens if there are 2 configurations with overlapping allowed name sets?
does a single configuration with an unknown policy name disposition of "allow" govern all policy names that appear in no other configuratons.
2.4.3. Violation
A violation represents an action which is disallowed by the TrustedTypeConfiguration
objects associated with the Document
.
how does this relate to webappsec-csp/Violation?
TODO: Describe the properties of the violation Each violation has a configuration , which is a Trusted Type Configuration. Each violation has a global object , which is a global object.
TODO(mkwst): How to serialize? CSP3 has no serialization defined for the violation object, although reporting assumes the object should be serializable.
2.4.4. Reporting
How does a policy violation get reported (both at the sink level, and when creating a policy).
3. Algorithms
3.1. Policies
3.1.1. Initialize policy factory
To initialize a Trusted Type Factory
with a TrustedTypeConfiguration
run these steps:
-
Let factory be a new
TrustedTypePolicyFactory
object, with an empty[[PolicyMap]]
map. -
Set the factory's
[[Configuration]]
internal slot to configuration. -
Return factory.
does configuration need to be defensively copied.
3.1.2. Create a Trusted Type Policy
To create a TrustedTypePolicy
in a factory
,
given a DOMString (policyName), policy options dictionary (options)
and exposed flag (exposed), run these steps:
-
If factory's
[[PolicyMap]]
internal slot has an entry with the keypolicyName
, then throw a TypeError. -
Let policyAllowed be the result of running Is policy name allowed algorithm.
-
If policyAllowed is False, throw a TypeError.
-
If Is a default policy algorithm returns True and exposed is False, then throw a TypeError.
-
Let policy be a new
TrustedTypePolicy
object. -
Set policy’s
name
property value to policyName. -
Let policyOptions be a new
TrustedTypePolicyOptions
object. -
Set policyOptions
createHTML
property to option'screateHTML
property value. -
Set policyOptions
createScript
property to option'screateScript
property value. -
Set policyOptions
createScriptURL
property to option'screateScriptURL
property value. -
Set policyOptions
createURL
property to option'screateURL
property value. -
Set policy's
[[options]]
internal slot value to policyOptions. -
Set the value for the policyName entry of factory's
[[PolicyMap]]
to policy. -
Return policy.
3.1.3. Get exposed policy
-
Let policyName and factory be the same variables as those of the same name in the algorithm that invoked these steps.
-
If factory's
[[PolicyMap]]
internal slot does not have an entry with the key policyName, return null. -
Otherwise, let policy be the value of the policyName entry of factory's
[[PolicyMap]]
. -
If policy's
[[options]]
'sexposed
attribute is false, return null. -
Return policy.
3.1.4. Get default policy
To get the default policy for a factory, execute the following steps:-
Set policyName to
"default"
. -
Return the result of executing the Get exposed policy algorithm.
3.1.5. Is policy name allowed
Let policyName and factory be the same variables as those of the same name in the algorithm that invoked these steps.
-
Let configuration be the value of factory's internal
[[Configuration]]
slot. -
If configuration's
unknownPolicyName
's is"allow"
, return true. -
Otherwise, if factory's
[[Configuration]]
'sallowedNames
set contains policyName, return true. -
Return false.
3.1.6. Is a default policy
Let policyName be the same variable as that of the same name in the algorithm that invoked these steps.
-
If policyName equals
"default"
, return true. -
Otherwise, return false.
3.1.7. Create a Trusted Type
Given a TrustedTypePolicy
policy, a type name trustedTypeName,
and a string value, 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" "createURL" "TrustedURL" -
Let options be the value of policy's
[[options]]
slot. -
Let function be the value of the property in options named functionName.
-
If function is null, throw a TypeError.
-
Let policyValue be the result of invoking function with value as a first argument, and callback **this** value set to null.
-
If policyValue is an error, return policyValue and abort the following steps.
-
Let dataString be the result of stringifying policyValue.
-
Let trustedObject be a new instance of an interface with a type name trustedTypeName, with its
[[Data]]
internal slot value set to dataString. -
Return trustedObject.
3.2. Enforcement
3.2.1. Obtain a Trusted Type Configuration for a response
This algorithm parses the Trusted-Types HTTP Response Header from
the response as a [HTTP-JFV] value and creates a configuration
object. The header value consists of a list of values.
Every string value is assumed to be an allowed policy name
,
and the presence of the header by default enforces the types at every sink type.
Given a Response
(response), perform the following steps:
-
Let config be a new
TrustedTypeConfiguration
. -
Let defaultSinkDisposition be
“unsafe-allow”
. -
Let hasWildcardPolicy be true
-
Let header be the value of the header in response’s header list whose name is
“Trusted-Types”
-
Let list be the result of executing the algorithm defined in Section 4 of [HTTP-JFV] on header. If that algorithm results in an error, abort these steps.
A trailing comma should not disable enforcement. Do we need to leave the document in a locked down state? Maybe set config.domSinks to "reject" and return config.
-
If list is not empty, then set hasWildcardPolicy to false and set defaultSinkDisposition to
“reject”
. -
For each item in list:
-
If item is a string :
-
If item is equal to
“*”
, then set hasWildcardPolicy to true. -
Otherwise, add item to config's
allowedNames
set.
-
-
Otherwise, if item is an object, for each name → value of item, execute the following steps:
-
Let propertyName be the result of running ASCII lowercase on name.
-
Execute the first statement, switching on propertyName:
-
case
“dom”
: If value is a validStringAtSinkDisposition
, set defaultSinkDisposition to that value. Otherwise, throw an error. -
case
“report”
: If value is a string, set config'sreportingGroup
to that value. Otherwise, throw an error. -
Otherwise, continue.
-
-
-
Otherwise, throw an error.
-
-
If hasWildcardPolicy is false, then set config's
unknownPolicyName
to“reject”
. -
If config’s
domSinks
is null, set config’s domSinks to defaultSinkDisposition’s value. -
Return config.
3.2.2. Get Trusted Type compliant string
This algorithm will return a string that can be assigned to a DOM 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 Document
(document), a TrustedType
(input), and a boolean
(passThroughFunctions) run these steps:
input could also be a Function
, e.g. for setTimeout
. Maybe add or Function
to ScriptString
and rename to avoid confusion.
Make it clear that no reporting is done when disposition is unsafe-allow
.
In step 1, refer to the internal slot in Document or the IDL additions to document that store the configuration.
-
Let disposition be document’s TrustedTypeConfiguration’s
domSinks
. -
If disposition is
“unsafe-allow”
, then run these steps:-
If passThroughFunctions is true and input is a
Function
, return input and abort these steps. -
Otherwise, return stringified input and abort these steps.
-
-
If input has type expectedType, return stringified input and abort these steps.
-
If passThroughFunctions is true and input is a
Function
, return input and abort these steps. -
Otherwise, execute the following steps:
-
Let defaultPolicy be the result of executing Get default policy algorithm on document’s browsing context's
Window
object. -
If defaultPolicy is null, abort these steps.
-
Let convertedInput be the result of executing Create a Trusted Type algorithm, with the following arguments:
-
defaultPolicy as policy
-
input as value
-
expectedType’s type name as trustedTypeName
-
-
If convertedInput is an error, then return error and abort the following steps.
-
If convertedInput has type expectedType, then return stringified convertedInput and abort the following steps.
-
If passThroughFunctions is true and convertedInput is a
Function
, then return convertedInput and abort the following steps. -
Set input to convertedInput’s value.
-
-
Execute Report sink type mismatch violation algorithm.
-
If disposition is
“report”
, then return stringified input and abort these steps. -
Throw a
TypeError
.
3.2.3. Enforce a Trusted Type
Note: enforcement is the process of checking that a value has an appropriate type before it reaches an injection sink.
Enforce a Trusted Type algorithm describes a modification to the injection sinks,
asserting that the input meets Trusted Type restrictions set for the current Document
. It accepts an input
value that the original function would and will optionally
pass-through to the original function -- all original arguments to the
function apart from input are passed through without modification.
-
Let compliantValue be the result of executing Get Trusted Type compliant string algorithm with
-
document being the current
Document
-
input being the new attribute value
-
passThroughFunctions being false, and
-
expectedType being the entry in the following table based on the sink type:
Sink parameter type expectedType HTMLString
TrustedHTML
ScriptString
TrustedScript
ScriptURLString
TrustedScriptURL
URLString
TrustedURL
-
-
If the previous algorithm throws an exception, rethrow the exception, and abort these steps.
-
Execute the original function with compliantValue instead of the original value. If the original functions accepts other arguments, pass-them through to the original function. Return the result.
3.2.4. Create a Violation for
3.2.5. Report sink type mismatch violation
Check that this algorithm is complete.
Given a violation (violation), this algorithm reports
it to the endpoint
specified in the violation’s configuration
object
.
-
Enqueue a task to run the following steps:
-
Let group be violation’s configuration’s
reportingGroup
. -
Let settings be violation’s global object’s relevant settings object.
-
Execute Queue data as type for endpoint group on settings algorith with the following arguments:
-
data = violation
-
type =
“trusted-types”
-
endpoint group = group
-
settings = settings
Note: The optional url parameter is not provided.
-
-
4. Integrations
typedef (DOMString or TrustedHTML );
HTMLString typedef (DOMString or TrustedScript );
ScriptString typedef (USVString or TrustedScriptURL );
ScriptURLString typedef (USVString or TrustedURL );
URLString typedef (TrustedHTML or TrustedScript or TrustedScriptURL or TrustedURL );
TrustedType
4.1. Integration with HTML
Window
objects have a trusted type policy factory
,
which is a TrustedTypePolicyFactory
object.
Document
objects have a trusted type configuration,
which is a TrustedTypeConfiguration
object.
4.1.1. Initialize a Document’s trusted type configuration algorithm
This algorithm should be executed during the Initializing a new Document object algorithm.
Given a Document
(document), a browsing context (browsingContext) and
a response (response), the user agent performs the
following steps in order to initialize *document*'s TrustedTypePolicyConfiguration:
-
Let configuration be the result of executing the Obtain a Trusted Type Configuration for a response algorithm on response. If that algorithm results in an error, abort these steps.
-
Set *document*'s TrustedTypePolicyConfiguration to configuration.
-
Let factory be the result of executing the Initialize policy factory algorithm on configuration.
-
Set browsingContext’s
WindowProxy
object’sTrustedTypes
attribute to factory.
4.1.2. Extensions to the Window interface
This document extends the Window
interface defined by HTML:
removed TreatNullAs=EmptyString from features parameter which is not recognized by bikeshed. Maybe there’s additional configuration required. See "It should not be used in specifications unless ..."
partial interface mixin Window { [Unforgeable ]readonly attribute TrustedTypePolicyFactory ;
TrustedTypes WindowProxy ?(
open optional URLString = "about:blank",
url optional DOMString = "_blank",
target optional /* [TreatNullAs=EmptyString] */DOMString = ""); };
features
TrustedTypes
returns the trusted
type policy factory of the current Window
, if the current Window
has a trusted type policy factory, or null otherwise.
open
: The type of the url argument changes from USVString
to URLString
.
4.1.3. Extensions to the Document interface
This document modifies the Document
interface defined by HTML:
partial interface mixin Document {WindowProxy ?(
open URLString ,
url DOMString ,
name DOMString ); [
features CEReactions ]void (
write HTMLString ...); [
text CEReactions ]void (
writeln HTMLString ...); };
text
Note: The types of arguments were changed.
4.1.4. Enforcement in window open steps algorithm
Modify the window open steps to accept a URLString
(url) (instead of a string url), and add the following
steps after step 9:
-
Set url to the result of executing Get Trusted Type compliant string algorithm with:
-
document being the source browsing context’s active document,
-
input being url,
-
passThroughFunctions being false, and
-
expectedType being
TrustedURL
.
-
-
If the previous algorithm throws an exception, rethrow the exception, and abort the following steps.
4.1.5. Enforcement in Location navigation algorithm
To the Location-object navigate algorithm, add the following steps before step 1:
-
Set url to the result of executing Get Trusted Type compliant string algorithm with:
-
document being the Location object’s
Document
, -
input being url,
-
passThroughFunctions being false, and
-
expectedType being
TrustedURL
.
-
-
If the previous algorithm throws an exception, rethrow the exception, and abort the following steps.
4.1.6. Enforcement in document write steps
Modify the document write steps algorithm to accept an HTMLString
(input) (instead of a string
input), and add the following steps before step 1:
-
Set input to the result of executing Get Trusted Type compliant string algorithm with:
-
document being document,
-
input being input,
-
passThroughFunctions being false, and
-
expectedType being
TrustedHTML
.
-
-
If the previous algorithm throws an exception, rethrow the exception, and abort the following steps.
4.1.7. Enforcement in property sinks
This document modifies the setters of the following properties of various DOM elements. For each property in the list, modify the IDL to accept a given parameter type instead of the DOMString / USVString. The setters will execute the Enforce a Trusted Type algorithm.
4.1.8. Enforcement in timer functions
To the timer initialization steps algorithm, add a step between 7.1 and 7.2:
-
Set the first method argument to the result of executing the Get Trusted Type compliant string algorithm, with
-
document set to the document of the method content proxy.
-
input set to the first method argument,
-
expectedType set to
TrustedScript
and -
passThroughFunctions set to true.
-
Note: Makes sure that a TrustedScript
is passed to timer
functions in place of a string when Trusted Types are enforced, but
also unconditionally accepts any Function
object.
4.1.9. Enforcement in event handler content attributes
This document modifies the attribute change steps for an event handler content attribute.
At the beginning of step 5, insert the following steps:
-
Let value be the result of executing the Get Trusted Type compliant string algorithm, with
-
document set to the owner document of eventTarget,
-
input set to value,
-
expectedType set to
TrustedScript
, and -
passThroughFunctions set to false.
-
-
If the algorithm throws an error, abort these steps.
4.1.10. String compilation
Note: See TC39/ecma262 issue #938 (adding a string to be compiled to algorithm parameters)
Modify HostEnsureCanCompileStrings algorithm, adding the following steps before step 1:
-
Let value be the result of executing the Get Trusted Type compliant string algorithm, with:
-
document set to the callerRealm’s environment setting object's responsible document,
-
input set to codeToCompile,
-
expectedType being
TrustedScript
, and -
passThroughFunctions set to false
-
-
If the algorithm throws an error, throw an
EvalError
.
4.2. Integration with DOM Parsing
Note: Re [DOM-Parsing].
4.2.1. Extensions to the Element interface
This document modifies the Element
interface defined by DOM Parsing:
partial interface Element { [CEReactions /*, TreatNullAs=EmptyString */]attribute HTMLString ; [
innerHTML CEReactions /*, TreatNullAs=EmptyString */]attribute HTMLString ; [
outerHTML CEReactions ]void (
insertAdjacentHTML DOMString ,
position HTMLString ); };
text
For innerHTML
's and outerHTML
's execute the Enforce a Trusted Type algorithm.
For the insertAdjacentHTML()
method, execute the Enforce a Trusted Type algorithm with input argument set to the text parameter value.
removed TreatNullAs=EmptyString from features parameter which is not recognized by bikeshed. Maybe there’s additional configuration required. See "It should not be used in specifications unless ..."
TreatNullAs is confusing, as for TrustedHTML, for some sinks a ull value will result in "", and "null" for others. This already caused problems in the polyfill. <https://github.com/WICG/trusted-types/issues/2>
4.2.2. Extensions to the Range interface
This document modifies the Range
interface defined by [DOM-Parsing]:
partial interface Range { [CEReactions ,NewObject ]DocumentFragment (
createContextualFragment HTMLString ); };
fragment
For createContextualFragment()
function, execute the Enforce a Trusted Type algorithm with the input argument set to
the fragment value.
4.2.3. Extensions to the DOMParser interface
This document modifies the DOMParser
interface defined by [DOM-Parsing]:
[,
Constructor Exposed =Window ]interface { [
DOMParser NewObject ]Document (
parseFromString HTMLString ,
str SupportedType ); };
type
IDL linkage broken for SupportedType but I don’t want DOMParser to not show up in the IDL summary.
// Not modified by this document, but bikeshed is not recognizing // SupportedTypeenum {
SupportedType ,
"text/html" ,
"text/xml" ,
"application/xml" ,
"application/xhtml+xml" };
"image/svg+xml"
For parseFromString()
function, execute the Enforce a
Trusted Type algorithm with input argument set to the str value.
Do we need to specify that the enforcement type is TrustedHTML
, or
that it is dependent on type which may be "image/svg+xml"
or generic XML?
5. Security Considerations
Trusted Types are not intended to defend against XSS 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 security bugs, and not to defend against first-party malicious code actively trying to bypass policy restrictions.
5.1. Bypass vectors
Mention node-adoption bypass vectors. <https://github.com/WICG/trusted-types/issues/49>
Mention anchor element properties bypass. <https://github.com/WICG/trusted-types/issues/64>
Mention text/attribute node copy bypass vectors. <https://github.com/WICG/trusted-types/issues/47>
Mention bypass vectors with template elements. <https://github.com/WICG/trusted-types/issues/42>
Mention corner cases with types that depend on a different attribute value. <https://github.com/WICG/trusted-types/issues/6>
5.2. Best practices for policy design
Trusted Types limit the scope of the code that can introduce DOM XSS vulnerabilities to the implementation of policies. In this design, insecure policies can still enable XSS. 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.
Mention the policy is global state-dependant. <https://github.com/WICG/trusted-types/issues/78>
Refer to the external document on secure policy design.
6. Implementation Considerations
6.1. Vendor-specific Extensions and Addons
Restriction imposed by the TrustedTypeConfiguration
objects 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 DOM XSS injection sinks of the document without triggering default policy execution, violation generation, or the rejection of the value.