Trusted Types Spec WIP

Editor’s Draft,

This version:
https://wicg.github.io/trusted-types/dist/spec/
Issue Tracking:
GitHub
Inline In Spec
Editors:
(Google LLC)
(Google LLC)

Abstract

An API that allows applications to lock down DOM XSS injection sinks to only accept non-spoofable, typed values in place of strings.

Status of this document

This specification was published by the Web Platform Incubator Community Group. It is not a W3C Standard nor is it on the W3C Standards Track. Please note that under the W3C Community Contributor License Agreement (CLA) there is a limited opt-out and other conditions apply. Learn more about W3C Community and Business Groups.

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

1.2. Non-goals

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.

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:

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.

Authors may define a policy that will sanitize an HTML string, allowing only a subset of tags and attributes that are known not to cause JavaScript execution. Any 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.

Library initialized with a policy allowing it to load additional scripts from a given host.
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).

Unsafe no-op policy reachable only from within a single code block to ascertain that it’s called only with no attacker-controlled values.
(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
const exposedPolicy = TrustedTypes.createPolicy('foo', {}, true);
exposedPolicy === TrustedTypes.getExposedPolicy('foo'); // true

const unexposedPolicy = TrustedTypes.createPolicy('bar', {});
unexposedPolicy instanceof TrustedTypesPolicy // true
TrustedTypes.getExposedPolicy('bar') === null // true
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.

const html = policy.createHTML('<div>');
TrustedTypes.isHTML(html) // true

const fake = Object.create(TrustedHTML.prototype);
TrustedTypes.isHTML(fake) // false
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 unknownPolicyName = "allow";
  StringAtSinkDisposition? domSinks;
  sequence<DOMString> allowedNames;
  DOMString reportingGroup = "default";
};

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.

Types are enforced at sinks, and only policies name “one” and “two” may be created.
Trusted-Types: "one", "two"
A value of 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.

Trusted-Types: "*"

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.

Trusted-Types: "one", "two", "default"

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.

Only reports violations in injection sinks, but allow strings passed to them (similar to Content-Security-Policy-Report-Only).
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:

  1. Let factory be a new TrustedTypePolicyFactory object, with an empty [[PolicyMap]] map.

  2. Set the factory's [[Configuration]] internal slot to configuration.

  3. 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:

  1. If factory's [[PolicyMap]] internal slot has an entry with the key policyName, then throw a TypeError.

  2. Let policyAllowed be the result of running Is policy name allowed algorithm.

  3. If policyAllowed is False, throw a TypeError.

  4. If Is a default policy algorithm returns True and exposed is False, then throw a TypeError.

  5. Let policy be a new TrustedTypePolicy object.

  6. Set policy’s name property value to policyName.

  7. Let policyOptions be a new TrustedTypePolicyOptions object.

  8. Set policyOptions createHTML property to option's createHTML property value.

  9. Set policyOptions createScript property to option's createScript property value.

  10. Set policyOptions createScriptURL property to option's createScriptURL property value.

  11. Set policyOptions createURL property to option's createURL property value.

  12. Set policy's [[options]] internal slot value to policyOptions.

  13. Set the value for the policyName entry of factory's [[PolicyMap]] to policy.

  14. Return policy.

3.1.3. Get exposed policy

  1. Let policyName and factory be the same variables as those of the same name in the algorithm that invoked these steps.

  2. If factory's [[PolicyMap]] internal slot does not have an entry with the key policyName, return null.

  3. Otherwise, let policy be the value of the policyName entry of factory's [[PolicyMap]].

  4. If policy's [[options]]'s exposed attribute is false, return null.

  5. Return policy.

3.1.4. Get default policy

To get the default policy for a factory, execute the following steps:
  1. Set policyName to "default".

  2. 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.

  1. Let configuration be the value of factory's internal [[Configuration]] slot.

  2. If configuration's unknownPolicyName's is "allow", return true.

  3. Otherwise, if factory's [[Configuration]]'s allowedNames set contains policyName, return true.

  4. 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.

  1. If policyName equals "default", return true.

  2. 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:

  1. 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"
  2. Let options be the value of policy's [[options]] slot.

  3. Let function be the value of the property in options named functionName.

  4. If function is null, throw a TypeError.

  5. Let policyValue be the result of invoking function with value as a first argument, and callback **this** value set to null.

  6. If policyValue is an error, return policyValue and abort the following steps.

  7. Let dataString be the result of stringifying policyValue.

  8. Let trustedObject be a new instance of an interface with a type name trustedTypeName, with its [[Data]] internal slot value set to dataString.

  9. 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:

  1. Let config be a new TrustedTypeConfiguration.

  2. Let defaultSinkDisposition be “unsafe-allow”.

  3. Let hasWildcardPolicy be true

  4. Let header be the value of the header in response’s header list whose name is “Trusted-Types”

  5. 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.

  6. If list is not empty, then set hasWildcardPolicy to false and set defaultSinkDisposition to “reject”.

  7. For each item in list:

    1. If item is a string :

      1. If item is equal to “*”, then set hasWildcardPolicy to true.

      2. Otherwise, add item to config's allowedNames set.

    2. Otherwise, if item is an object, for each namevalue of item, execute the following steps:

      1. Let propertyName be the result of running ASCII lowercase on name.

      2. Execute the first statement, switching on propertyName:

        1. case “dom”: If value is a valid StringAtSinkDisposition, set defaultSinkDisposition to that value. Otherwise, throw an error.

        2. case “report”: If value is a string, set config's reportingGroup to that value. Otherwise, throw an error.

        3. Otherwise, continue.

    3. Otherwise, throw an error.

  8. If hasWildcardPolicy is false, then set config's unknownPolicyName to “reject”.

  9. If config’s domSinks is null, set config’s domSinks to defaultSinkDisposition’s value.

  10. 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.

  1. Let disposition be document’s TrustedTypeConfiguration’s domSinks.

  2. If disposition is “unsafe-allow”, then run these steps:

    1. If passThroughFunctions is true and input is a Function, return input and abort these steps.

    2. Otherwise, return stringified input and abort these steps.

  3. If input has type expectedType, return stringified input and abort these steps.

  4. If passThroughFunctions is true and input is a Function, return input and abort these steps.

  5. Otherwise, execute the following steps:

    1. Let defaultPolicy be the result of executing Get default policy algorithm on document’s browsing context's Window object.

    2. If defaultPolicy is null, abort these steps.

      Do we need some "resume below" language?

    3. 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

    4. If convertedInput is an error, then return error and abort the following steps.

    5. If convertedInput has type expectedType, then return stringified convertedInput and abort the following steps.

    6. If passThroughFunctions is true and convertedInput is a Function, then return convertedInput and abort the following steps.

    7. Set input to convertedInput’s value.

  6. Execute Report sink type mismatch violation algorithm.

  7. If disposition is “report”, then return stringified input and abort these steps.

  8. 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.

  1. 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
  2. If the previous algorithm throws an exception, rethrow the exception, and abort these steps.

    can we use "compliantValue is an error" language here?

  3. 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

TODO: write and link to it

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.

  1. Enqueue a task to run the following steps:

    1. Let group be violation’s configuration’s reportingGroup.

    2. Let settings be violation’s global object’s relevant settings object.

    3. 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:

  1. 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.

  2. Set *document*'s TrustedTypePolicyConfiguration to configuration.

  3. Let factory be the result of executing the Initialize policy factory algorithm on configuration.

  4. Set browsingContext’s WindowProxy object’s TrustedTypes 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 url = "about:blank",
      optional DOMString target = "_blank",
      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:

  1. 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.

  2. 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:

  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.

  2. 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:

  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.

  2. 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.

Sink setter Parameter type Notes
ShadowRoot.innerHTML HTMLString Non-standard property
HTMLScriptElement.innerText ScriptString Issue: Might require modifying the more-generic HTML Standard §dom-innertext setter algorithm.
HTMLScriptElement.textContent ScriptString Issue: Might require modifying the more-generic DOM Standard §dom-node-textcontent setter algorithm.
HTMLIFrameElement.srcdoc HTMLString HTML5 §attr-iframe-srcdoc
HTMLEmbedElement.src ScriptURLString HTML5 §attr-embed-src
HTMLObjectElement.data ScriptURLString
HTMLObjectElement.codeBase ScriptURLString
HTMLScriptElement.src ScriptURLString
HTMLLinkElement.href URLString
HTMLFrameElement.src URLString
HTMLIFrameElement.src URLString
HTMLImageElement.src URLString
HTMLFormElement.action URLString
HTMLInputElement.src URLString
HTMLInputElement.formAction URLString Issue: IDL linking does not recognize HTMLInputElement/formAction even though it is defined in [HTML5].
HTMLAnchorElement.href URLString href actually defined via include
HTMLAreaElement.href URLString href actually defined via include
HTMLBaseElement.href URLString
HTMLButtonElement.formAction URLString
HTMLMediaElement.src URLString
WICG/portals’s HTMLPortalElement.src URLString
HTMLSourceElement.src URLString
HTMLTrackElement.src URLString

4.1.8. Enforcement in timer functions

To the timer initialization steps algorithm, add a step between 7.1 and 7.2:

  1. 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:

  1. 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.

  2. 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:

  1. Let value be the result of executing the Get Trusted Type compliant string algorithm, with:

  2. 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
// SupportedType
enum 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.

Conformance

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[CSP-3]
Content Security Policy Level 3 URL: https://www.w3.org/TR/CSP3/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[FETCH]
Anne van Kesteren. Fetch Standard. Living Standard. URL: https://fetch.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[WebIDL]
Cameron McCormack; Boris Zbarsky; Tobie Langel. Web IDL. 15 December 2016. ED. URL: https://heycam.github.io/webidl/

Informative References

[DOM-Parsing]
Travis Leithead. DOM Parsing and Serialization. 17 May 2016. WD. URL: https://www.w3.org/TR/DOM-Parsing/
[HTML-DESIGN-PRINCIPLES]
Anne van Kesteren; Maciej Stachowiak. HTML Design Principles. 26 November 2007. WD. URL: https://www.w3.org/TR/html-design-principles/
[HTML5]
Ian Hickson; et al. HTML5. 27 March 2018. REC. URL: https://www.w3.org/TR/html5/
[HTTP-JFV]
J. Reschke. A JSON Encoding for HTTP Header Field Values. 24 October 2017. Active Internet-Draft. URL: https://tools.ietf.org/html/draft-reschke-http-jfv

IDL Index

[Exposed=Window]
interface TrustedHTML {
  stringifier;
};

[Exposed=Window]
interface TrustedScript {
  stringifier;
};

[Exposed=Window]
interface TrustedScriptURL {
  stringifier;
};

[Exposed=Window]
interface TrustedURL {
  stringifier;
};

[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);
};

[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);
};

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);

enum StringAtSinkDisposition {
  "reject",
  "report",
  "unsafe-allow",
};

enum UnknownPolicyNameDisposition {
  "reject",
  "allow",
};

dictionary TrustedTypeConfiguration {
  UnknownPolicyNameDisposition unknownPolicyName = "allow";
  StringAtSinkDisposition? domSinks;
  sequence<DOMString> allowedNames;
  DOMString reportingGroup = "default";
};

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;

partial interface mixin Window {
  [Unforgeable] readonly attribute
      TrustedTypePolicyFactory TrustedTypes;
  WindowProxy? open(
      optional URLString url = "about:blank",
      optional DOMString target = "_blank",
      optional /* [TreatNullAs=EmptyString] */ DOMString features = "");
};

partial interface mixin Document {
   WindowProxy? open(URLString url, DOMString name, DOMString features);
  [CEReactions] void write(HTMLString... text);
  [CEReactions] void writeln(HTMLString... text);
};

partial interface Element {
  [CEReactions/*, TreatNullAs=EmptyString */] attribute HTMLString innerHTML;
  [CEReactions/*, TreatNullAs=EmptyString */] attribute HTMLString outerHTML;
  [CEReactions] void insertAdjacentHTML(DOMString position, HTMLString text);
};

partial interface Range {
  [CEReactions, NewObject] DocumentFragment createContextualFragment(HTMLString fragment);
};

[Constructor, Exposed=Window]
interface DOMParser {
  [NewObject] Document parseFromString(HTMLString str, SupportedType type);
};

// Not modified by this document, but bikeshed is not recognizing
// SupportedType
enum SupportedType {
  "text/html",
  "text/xml",
  "application/xml",
  "application/xhtml+xml",
  "image/svg+xml"
};

Issues Index

mention other solutions, like templating systems, or CSP for mitigating
figure out if we need this section here. CSP has none, SRI has one and it looks useful.
Something about reducing the review surface
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>
Add TrustedHTML.EMPTY. <https://github.com/WICG/trusted-types/issues/95>
Consider adding new set of types, e.g. related to CSS. <https://github.com/WICG/trusted-types/issues/104>
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>
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?
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.
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.
How does a policy violation get reported (both at the sink level, and when creating a policy).
does configuration need to be defensively copied.
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.
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.
Do we need some "resume below" language?
can we use "compliantValue is an error" language here?
TODO: write and link to it
Check that this algorithm is complete.
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 ..."
Issue: Might require modifying the more-generic HTML Standard §dom-innertext setter algorithm.
Issue: Might require modifying the more-generic DOM Standard §dom-node-textcontent setter algorithm.
Issue: IDL linking does not recognize HTMLInputElement/formAction even though it is defined in [HTML5].
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>
IDL linkage broken for SupportedType but I don’t want DOMParser to not show up in the IDL summary.
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?
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>
Mention the policy is global state-dependant. <https://github.com/WICG/trusted-types/issues/78>
Refer to the external document on secure policy design.