GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing w3c.github.io — Trusted Types Tests
1. IntroductionThis 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 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. 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
1.2. Non-goals
1.3. Use cases
2. Framework2.1. Injection sinksThis 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 security 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 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 sinksThis 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:
Since HTML parsers can create arbitrary elements, including scripts, and set arbitrary attributes, DOM XSS injection sinks also include HTML parsing sinks:
Guarding DOM XSS injection sinks is controlled by the trusted-types-sink-group named 'script'. 2.2. Trusted TypesTo 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.
|
| 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
to Element.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 policy.
TrustedTypePolicyPolicy 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 Exposed =Window ]TrustedHTMLParserOptions createParserOptions (optional SetHTMLUnsafeOptions = {},options any ...); };arguments
Each policy has a name.
Each TrustedTypePolicy object has an associated TrustedTypePolicyOptions options object, describing the actual behavior of the policy.
createHTML(input, ...arguments)
Returns the result of executing the Create a Trusted Type algorithm, with the following arguments:
"TrustedHTML"
createScript(input, ...arguments)
Returns the result of executing the Create a Trusted Type algorithm, with the following arguments:
"TrustedScript"
createScriptURL(input, ...arguments)
Returns the result of executing the Create a Trusted Type algorithm, with the following arguments:
"TrustedScriptURL"
createParserOptions(options, ...arguments)
Returns the result of executing the create a trusted type algorithm, with the following arguments:
"TrustedHTMLParserOptions"
TrustedTypePolicyOptionsThis 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 CreateParserOptionsCallback ; };createParserOptions callback =CreateHTMLCallback DOMString ? (DOMString ,input any ...);arguments callback =CreateScriptCallback DOMString ? (DOMString ,input any ...);arguments callback =CreateScriptURLCallback USVString ? (DOMString ,input any ...);arguments callback =CreateParserOptionsCallback SetHTMLUnsafeOptions ? (SetHTMLUnsafeOptions ,options any ...);arguments
This section is not normative.
One of the policies, the policy with a name "default", is special;
When an injection sink is passed a string (instead of a
Trusted Type object), this policy 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 policy are propagated to the application.
If the default policy 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 original value
passed to the default policy 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 policy should necessarily be defined with very strict rules not to bypass the security restrictions in unknown parts of the application. In an extreme case, a lax, no-op default policy defeats all the benefits of using Trusted Types to protect access to injection sinks. If possible, authors should resort to a default policy 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 policy entirely.
Note: See § 3.5 Get Trusted Type compliant string for details on how the default policy is applied.
// Content-Security-Policy: trusted-types default; require-trusted-types-for 'script' trustedTypes. createPolicy( 'default' , { createScriptURL: ( value, type, sink) => { console. log( "Please refactor." ); return value+ '?default-policy-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-policy-used&type=TrustedScriptURL&sink=HTMLScriptElement%20src
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 security 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 policy creation.
Applications may control Trusted Type enforcement via configuring a Content Security 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-Security-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.
createParserOptionsWhile createHTML relies on sanitizing strings before they are injected to the parser using a JS sanitizer,
the createParserOptions allows the page’s default policy to enforce HTML sanitization.
A createParserOptions callback in a default policy runs whenever
an HTML fragment sink is invoked with unvetted parser options (or default options), allowing the policy to vet caller-supplied options
and enforce sanitization even when the input markup is already an instance of TrustedHTML.
Content-Security-Policy: require-trusted-types-for 'script'
Inject a sanitizer when using an HTML injection sink.
( async function renderFootnote() { trustedTypes. createPolicy( 'default' , { createParserOptions: options=> { const sanitizer= new Sanitizer( options. sanitizer? . get() ?? {}); sanitizer. removeUnsafe(); return { ... options, sanitizer}; } }); const trustedOptions= trustedTypes. createPolicy( 'trusted' , { createParserOptions: options=> options}). createParserOptions({}); const untrustedFootnoteContent= await fetch( '/footnote.html' ). then( r=> r. text()); // This HTML will be sanitized with a "safe" HTML sanitizer, as the default policy injects // a sanitizer with unsafe markup removed. footNote. innerHTML= untrustedFootnoteContent; // or: footNote. setHTMLUnsafe( untrustedFootnoteContent, {}); const trustedMainContent= await fetch( "main.html" ). then( r=> r. text()); main. setHTMLUnsafe( trustedMainContent, trustedOptions); })();
Apart from sanitization, the default policy can also control whether an HTML injection executes scripts by overriding the caller’s runScripts setting.
HTML inserted with runScripts set to false can still insert script elements into the document,
but those scripts are not automatically executed.
( async function renderFootnote() { trustedTypes. createPolicy( 'default' , { createHTML: string=> string, createParserOptions: options=> { return { ... options, runScripts: false }; } }); // The default policy would override the runScripts value to false. main. setHTMLUnsafe( someHTMLWithScripts, { runScripts: true }); // This applies to Range.prototype.createContextualFragment() const fragment= new Range(). createContextualFragment( "<script>alert(1)</" + "script>" ); const div= document. createElement( 'div' ); // The scripts in the fragment would not be executed, as the default policy overrides runScripts. div. appendChild( fragment); })();
This section is not normative.
The following table summarizes the behavior of get trusted type compliant input for various combinations of arguments and default policy callbacks under enforcing Content Security Policy:
| documentType | options | input | Default policy state / callback | Result | Effective sanitizer
| Rationale |
|---|---|---|---|---|---|---|
"html"
| TrustedHTMLParserOptions
| String or TrustedHTML
| (Ignored) | Returns (stringified |input|, |options|).
| options’s sanitizer configuration | Caller-supplied TrustedHTMLParserOptions explicitly authorizes the parse operation, with script execution and sanitization dictated by the policy that minted it.
|
"html"
| Dictionary (caller provides sanitizer)
| TrustedHTML
| createParserOptions returns a dictionary configuring a policy sanitizer
| Returns (stringified |input|, |compliantOptions|).
| Configured by createParserOptions
| Policy vets or replaces caller’s sanitizer on TrustedHTML: Even though input is an attested TrustedHTML instance, createParserOptions runs and receives the caller’s sanitizer in argument["sanitizer"]. The policy can inspect, enforce, or replace the sanitizer configuration (as well as control script execution), ensuring unvetted caller-supplied options cannot bypass policy review.
|
Dictionary (caller provides sanitizer)
| createParserOptions returns {} (omits sanitizer)
| Returns (stringified |input|, |compliantOptions|).
| null
| Policy strips caller’s sanitizer: The default policy determines the final parser options. If the policy returns no sanitizer, no sanitization is performed during parsing, overriding the caller’s request. | ||
| Dictionary that is not author-supplied or does not need vetting | No createParserOptions (or no default policy)
| Returns (stringified |input|, |options|).
| null
| TrustedHTML without parser policy: When no policy defines createParserOptions, an existing TrustedHTML instance satisfies Trusted Types directly (bypassing createHTML), as long as author-supplied options do not need vetting.
| ||
| Author-supplied dictionary that needs vetting | Throws a TypeError.
| N/A | Unvetted options rejected: TrustedHTML can become unsafe with an unvetted sanitizer or script execution, so these options need a TrustedHTMLParserOptions or a default policy’s createParserOptions.
| |||
"html"
| Dictionary | String | createParserOptions returns a dictionary
| Returns (stringified |input|, |compliantOptions|).
| Configured by createParserOptions (or null)
| Parsing raw string authorized by parser policy: The default policy returns compliant parser options, authorizing raw string parsing and configuring sanitization and script execution without requiring createHTML.
|
| Dictionary | String or TrustedHTML
| createParserOptions throws an exception
| Rethrows the exception. | N/A | Exceptions in policy callbacks propagate immediately to the caller, regardless of whether input is a string or TrustedHTML.
| |
createParserOptions returns null or undefined
| Throws a TypeError.
| N/A | Returning null or undefined from a policy callback rejects the value, triggering a CSP violation error, regardless of whether input is a string or TrustedHTML.
| |||
| Author-supplied dictionary that needs vetting | String | No createParserOptions (or no default policy)
| Throws a TypeError.
| N/A | Unvetted options rejected: createHTML is not invoked, as its result would be parsed with unvetted options.
| |
| Dictionary that is not author-supplied or does not need vetting | String | No createParserOptions; createHTML returns TrustedHTML
| Returns (stringified |convertedInput|, |options|).
| null
| Provides backwards compatibility: when no policy manages parser options, the sink falls back to vetting or sanitizing the markup string via createHTML.
| |
No createParserOptions; createHTML throws an exception
| Rethrows the exception. | N/A | Exceptions in policy callbacks propagate immediately to the caller. | |||
No createParserOptions; createHTML returns null or undefined
| Throws a TypeError.
| N/A | Rejection by createHTML triggers a CSP violation error.
| |||
| No default policy (or neither callback defined) | Throws a TypeError.
| N/A | Under enforcing CSP, a raw string cannot be parsed without a policy authorizing either the parser options or the markup string. | |||
"xml"
| Any | TrustedHTML
| (Any) | Returns (stringified |input|, |options|).
| None (ignored) | XML sinks require trusted markup; a TrustedHTML instance satisfies this requirement directly. XML fragment parsing does not support sanitization and never executes scripts.
|
"xml"
| Any | String | createHTML returns TrustedHTML
| Returns (stringified |convertedInput|, |options|).
| None (ignored) | XML fragment sinks do not support parser options bypass or sanitization; markup strings must always be converted via createHTML. XML fragment parsing does not support sanitization and never executes scripts.
|
createHTML throws an exception
| Rethrows the exception. | N/A | Exceptions in policy callbacks propagate immediately to the caller. | |||
No createHTML or no default policy (or returns null/undefined)
| Throws a TypeError.
| N/A | Untrusted strings cannot be injected into XML sinks without createHTML, regardless of parser options.
|
TrustedHTML, runScripts, and sanitization: Sinks enforcing Trusted Types handle options and scripts as follows:
TrustedHTML instance, a default policy’s createParserOptions still vets any caller-supplied options dictionary, allowing the policy to inspect, configure, or override the sanitizer configuration (as well as control script execution) despite the input already being TrustedHTML. If createParserOptions throws or returns null or undefined, the operation is rejected. When createParserOptions is absent, an author-supplied options dictionary that needs vetting is rejected, whether input is a TrustedHTML instance or a string converted by createHTML. Options that a sink constructs itself, like createContextualFragment()’s runScripts set to true, are not rejected.
TrustedHTMLParserOptions, script execution and sanitization are governed by the policy that created the options object. When options are passed as a dictionary, a default policy’s createParserOptions determines the final script execution behavior, overriding the caller’s requested runScripts setting.
createParserOptions is missing, throws, or returns null or undefined, a TypeError is thrown (or rethrown) immediately.
To create a trusted type policy, given a TrustedTypePolicyFactory (factory),
a string (policyName), TrustedTypePolicyOptions dictionary (options), and a
global object (global) run these steps:
Let allowedByCSP be the result of executing should Trusted Type policy creation be blocked by content security policy? algorithm with global, policyName and factory’s created policy names value.
If allowedByCSP is "Blocked", throw a TypeError and abort further steps.
If policyName is default and the factory’s default policy
value is not null, throw a TypeError and abort further steps.
Let policy be a new TrustedTypePolicy object.
Set policy’s name property value to policyName.
Set policy’s options value to «[
"createHTML" -> options["createHTML"],
"createScript" -> options["createScript"],
"createScriptURL" -> options["createScriptURL"],
"createParserOptions" -> options["createParserOptions"]
]».
If the policyName is default, set the factory’s default policy value to policy.
Append policyName to factory’s created policy names.
Return policy.
To create a trusted type given a TrustedTypePolicy policy, a type name trustedTypeName,
a string or dictionary value and a list arguments, perform the following steps:
Let policyValue be the result of executing get trusted type policy 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.
If trustedTypeName is "TrustedHTMLParserOptions":
If policyValue is null, throw a TypeError.
Note: Returning null from a named policy’s createParserOptions callback throws a TypeError here, whereas returning null or undefined from createHTML, createScript, or createScriptURL yields the empty string.
Let sanitizerConfig be the result of getting a sanitizer configuration from policy’s relevant realm and policyValue.
Let runScripts be policyValue["runScripts"] with default false.
Return a new instance of TrustedHTMLParserOptions in policy’s relevant realm with its
sanitizer configuration set to sanitizerConfig, and its
runScripts set to runScripts.
Let dataString be the result of stringifying policyValue.
If policyValue 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.
To get trusted type policy value given a TrustedTypePolicy policy, a type name trustedTypeName,
a string or dictionary value, a list arguments, and a boolean throwIfMissing, perform 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" |
| "createParserOptions" | "TrustedHTMLParserOptions" |
Let function be policy’s options[functionName].
If function is null, then:
If throwIfMissing throw a TypeError.
Else return null.
If trustedTypeName is "TrustedHTMLParserOptions":
Set value to the result of creating a parser options callback argument given policy’s relevant realm and value.
Let args be « value ».
Append each item in arguments to args.
Let policyValue be the result of invoking function with
args and "rethrow".
Return policyValue.
Note: See § 2.4.3 Summary of input enforcement for a summary of this algorithm’s behavior for various combinations of arguments and default policy callbacks.
To get trusted type compliant input given a global object global, a string or TrustedHTML input,
a TrustedHTMLParserOptions, ParseHTMLUnsafeOptions or SetHTMLUnsafeOptions options, a string sink, an optional "html" or "xml" documentType (default "html"), and an optional boolean optionsFromAuthor (default true):
Let compliantOptions be options.
If documentType is "html":
Set compliantOptions to the result of calling get trusted type compliant parser options, passing global, options, false, sink, and optionsFromAuthor.
Note: Sinks that construct options themselves, rather than taking them from the author, pass false for optionsFromAuthor.
For example, createContextualFragment() sets runScripts to true.
If compliantOptions is an instance of TrustedHTMLParserOptions, return (stringified input, compliantOptions).
Let compliantHTML be the result of calling get trusted type compliant string, passing TrustedHTML, global, input, sink, and "script".
If the algorithm threw an error, rethrow the error.
Return (compliantHTML, compliantOptions).
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.
To get trusted type compliant string 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, sinkGroup, and true.
If requireTrustedTypes is false, return stringified input and abort these steps.
Let convertedInput be the result of executing Process value with a default policy 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 or undefined, execute the following steps:
Let disposition be the result of executing should sink type mismatch violation be blocked by content security policy? algorithm, passing global, sink, sinkGroup, and stringified input as source.
If disposition is “Allowed”, return stringified input and abort further steps.
Note: This step assures that the default policy 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.
Note: throwIfMissing is false when called from get trusted type compliant input. Even then, author-supplied options that need vetting require a default policy with createParserOptions. For synchronous HTML fragment injection sinks, a TrustedHTMLParserOptions in the resulting options can satisfy Trusted Types enforcement without requiring createHTML on the input string.
When streaming or in contexts where the HTML string cannot be validated up front, callers pass true for throwIfMissing to ensure a default policy with createParserOptions is required.
For XML documents, parser options cannot satisfy Trusted Types enforcement; XML fragment sinks always require compliant string input via get trusted type compliant string.
To get trusted type compliant parser options given a global object global,
input, which is either a TrustedHTMLParserOptions, a SetHTMLUnsafeOptions, or a ParseHTMLUnsafeOptions,
a boolean throwIfMissing, a string sink, and an optional boolean optionsFromAuthor (default true):
If input is an instance of TrustedHTMLParserOptions, return input.
Let requireTrustedTypes be the result of executing Does sink type require trusted types? algorithm,
passing global, "script", and true.
If requireTrustedTypes is false, return input.
Let requirePolicy be throwIfMissing.
If optionsFromAuthor is true and input needs vetting, set requirePolicy to true.
Note: Markup vetted as TrustedHTML can become unsafe when parsed with an unvetted sanitizer (e.g., one that uses replaceWithChildrenElements) or with script execution enabled.
Such options need to come from a TrustedHTMLParserOptions or a default policy’s createParserOptions.
Let defaultPolicy be the value of global’s trusted type policy factory’s default policy.
If defaultPolicy is null:
If requirePolicy is true:
Let disposition be the result of executing should sink type mismatch violation be blocked by content security policy? algorithm,
passing global, sink, "script", and the empty string as source.
If disposition is “Allowed”, return input.
Throw a TypeError.
Return input.
Let function be defaultPolicy’s options["createParserOptions"].
If function is null:
If requirePolicy is true:
Let disposition be the result of executing should sink type mismatch violation be blocked by content security policy? algorithm,
passing global, sink, "script", and the empty string as source.
If disposition is “Allowed”, return input.
Throw a TypeError.
Return input.
Let argument be the result of creating a parser options callback argument given global’s relevant realm and input.
Let policyValue be the result of invoking function with « argument, "TrustedHTMLParserOptions", sink » and "rethrow".
If the algorithm threw an error, rethrow the error and abort the following steps.
If policyValue is null or undefined:
Let disposition be the result of executing should sink type mismatch violation be blocked by content security policy? algorithm,
passing global, sink, "script", and the empty string as source.
If disposition is “Allowed”, return input.
Note: This step assures that the default policy rejection will be reported, but ignored in a report-only mode.
Throw a TypeError.
Let runScripts be policyValue["runScripts"], with default false.
Note: When invoked as a default policy, the createParserOptions callback determines the final script execution behavior, overriding the caller’s requested runScripts option.
Return a new TrustedHTMLParserOptions in global’s relevant realm
whose sanitizer configuration is set to the result of
getting a sanitizer configuration from
global’s relevant realm and policyValue,
and whose runScripts is set to runScripts.
A SetHTMLUnsafeOptions or ParseHTMLUnsafeOptions options needs vetting if
options["runScripts"] exists and is true, or if options["sanitizer"] exists and is not an empty SanitizerConfig.
Note: An empty SanitizerConfig does not change the parsed markup.
To create a parser options callback argument given a realm realm and a dictionary dictionary:
Let runScriptsInput be dictionary["runScripts"], with default false.
Let argument be the ordered map «[ "runScripts" → runScriptsInput ]».
Let sanitizerInput be the result of getting a sanitizer from realm and dictionary.
If sanitizerInput is not null, set argument["sanitizer"] to sanitizerInput.
Return argument.
To get a sanitizer from dictionary given a realm realm and a dictionary dictionary:
Let sanitizerInput be dictionary["sanitizer"], defaulting to null.
If sanitizerInput is null, return null.
Let configuration be null.
If sanitizerInput is a SanitizerPresets:
Assert: sanitizerInput is "default".
Set configuration to the built-in safe default configuration.
Otherwise, if sanitizerInput is a Sanitizer:
Set configuration to sanitizerInput’s configuration.
Otherwise, if sanitizerInput is a SanitizerConfig:
Set configuration to sanitizerInput.
Assert: configuration is not null.
Let sanitizer be a new Sanitizer in realm.
Configure sanitizer given configuration and true.
Return sanitizer.
To get a sanitizer config copy from dictionary given a realm realm and a dictionary dictionary:
Let sanitizer be the result of getting a sanitizer from realm and dictionary.
If sanitizer is null, return null.
Return sanitizer’s configuration.
This algorithm routes a value to be assigned to an injection sink through a default policy, should one exist.
To process value with a default policy 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 policy factory’s default policy.
Let policyValue be the result of executing get trusted type policy value, with the following arguments:
defaultPolicy as policy
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 policyValue is null or undefined, return policyValue.
Let dataString be the result of stringifying policyValue.
Return a new instance of an interface with a type name trustedTypeName, with its associated data value set to dataString.
To prepare the script text given an HTMLScriptElement or SVGScriptElement (script), perform the following steps:
Let sink be "HTMLScriptElement text" if script is an HTMLScriptElement; otherwise "SVGScriptElement text".
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 as input,
sink,
'script' as sinkGroup.
If the algorithm threw an error, rethrow the error.
To get trusted type compliant attribute value given a string attributeName, string attributeNs, Element element and TrustedType or a string newValue, perform the following steps:
If attributeNs is the empty string, set attributeNs to null.
Set attributeData to the result of get Trusted Type data for attribute algorithm, with the following arguments:
element
attributeName
attributeNs
If attributeData is null, then:
If newValue is a string, return newValue.
Assert: newValue is TrustedHTML or TrustedScript or TrustedScriptURL.
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.
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, « HTML namespace, SVG namespace, MathML namespace » contains element’s namespace, and attribute is the name of an event handler content attribute:
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.
typedef (TrustedHTML or TrustedScript or TrustedScriptURL );TrustedType
Window and Worker objects have a trusted type policy factory,
which is a TrustedTypePolicyFactory object.
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 policy factory.
An HTMLScriptElement and SVGScriptElement have:
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.
To update script trustedness for HTMLScriptElement script given string value:
Set script’s script text value to value.
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:
...
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 must ensure they protect against this case. See https://github.com/w3c/trusted-types/issues/507.
There’s no proper definition for the processing of SVG script elements. However, implementations must apply a similar change to the processing of SVGScriptElements.
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 the async 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.
There’s no proper definition for the processing of SVG script elements. However, implementations must apply a similar change to the processing of SVGScriptElements.
This document defines require-trusted-types-for - a new Content Security Policy directive.
require-trusted-types-for directive configures the Trusted Types framework 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-Security-Policy: require-trusted-types-for 'script'
require-trusted-types-for Pre-Navigation checkGiven a request (request), a string navigation type and a policy (policy), 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 policy’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 policy 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".
This document defines trusted-types - a new Content Security 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-policy-name / tt-keyword / tt-wildcard tt-wildcard = "*" tt-policy-name = 1*( ALPHA / DIGIT / "-" / "#" / "=" / "_" / "/" / "@" / "." / "%") tt-keyword = "'allow-duplicates'" / "'none'"
Content-Security-Policy: require-trusted-types-for 'script'; trusted-types one two
Content-Security-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 policy named default is present in the list, it refers to the default policy.
All strings passed to injection sinks will be passed through it instead of being rejected outright.
This algorithm returns true if the injection sink requires a Trusted Type, and false otherwise.
The does sink type require trusted types? algorithm, given a global object (global), a string (sinkGroup) and a boolean (includeReportOnlyPolicies), performs these steps:
For each policy in global’s CSP list:
If policy’s directive set does not contain a directive
whose name is "require-trusted-types-for", skip to the next policy.
Let directive be the policy’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 policy.
Let enforced be true if policy’s disposition is "enforce", and false otherwise.
If enforced is true, return true.
If includeReportOnlyPolicies is true, return true.
Return false.
This algorithm returns "Blocked" if the injection sink requires a Trusted Type, and "Allowed" otherwise.
The should sink type mismatch violation be blocked by content security policy? algorithm, given a global object (global), a string (sink), a string (sinkGroup) and a string (source), performs the following steps:
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 policy in global’s CSP list:
If policy’s directive set does not contain a directive
whose name is "require-trusted-types-for", skip to the next policy.
Let directive be the policy’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 policy.
Let violation be the result of executing
Create a violation object for global, policy, and directive
on global, policy 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 policy’s disposition is "enforce", then set result to
"Blocked".
Return result.
This algorithm returns "Blocked" if the TrustedTypePolicy should not be created, and "Allowed" otherwise.
The Should Trusted Type policy creation be blocked by content security policy? algorithm, given a global object (global), a string (policyName) and a list of strings (createdPolicyNames), performs the following steps:
Let result be "Allowed".
For each policy in global’s CSP list:
Let createViolation be false.
If policy’s directive set does not contain a directive
which name is "trusted-types", skip to the next policy.
Let directive be the policy’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 policy names are present.
If createdPolicyNames contains policyName 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 policyA policyB 'allow-duplicates' allows authors to create policies with
duplicated names.
If directive’s value does not contain a tt-policy-name, which value is policyName, 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, use
trusted-types * 'allow-duplicates' or don’t set the trusted-types directive at all.
If createViolation is false, skip to the next policy.
Let violation be the result of executing
Create a violation object for global, policy, and directive on global, policy and
"trusted-types"
Set violation’s resource to "trusted-types-policy".
Set violation’s sample to the substring of policyName, containing its first 40 characters.
Execute Report a violation on violation.
If policy’s disposition is "enforce", then set result to
"Blocked".
Return result.
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 security bugs, and not to defend against first-party malicious code actively trying to bypass policy restrictions. Below we enumerate already identified vectors that remain risky even in environments with enforced Trusted Types.
While the code running in a window in which Trusted Types are enforced cannot
dynamically create nodes that would bypass the policy 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 Security 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 security rules are applied for the whole
origin.
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:
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 policy. Authors need to ascertain that the data passed to Trusted Type policies is indeed trustworthy, if the policy rules don’t enforce constraints or validate the data themselves.
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 security decisions a policy makes effectively become the policy, and should be guarded & reviewed together.
A createParserOptions callback that returns a configuration that does not remove unsafe markup (e.g., scripts or event handlers) provides no protection against DOM XSS.
Policy authors should also carefully inspect any caller-supplied sanitizer in the argument["sanitizer"] passed to createParserOptions.
Blindly trusting or passing through a caller’s sanitizer allows unvetted configurations to govern parsing.
Because createParserOptions executes even when the input markup is an existing TrustedHTML instance,
the default policy ensures that unvetted caller options cannot bypass application-wide sanitization or script execution constraints.
Without such a callback, TrustedHTML cannot be combined with a caller-supplied non-empty sanitizer or runScripts set to true, since those could make vetted markup unsafe.
Refer to the external document on secure policy design.
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 policy. 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 Security Policy reporting mechanisms.
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 policy execution, violation generation, or the rejection of the value.