Skip to content

Instantly share code, notes, and snippets.

@shhnjk
Created December 2, 2021 19:24
Show Gist options
  • Save shhnjk/146e687c0fa163d34ea9058ae5f7a603 to your computer and use it in GitHub Desktop.
Save shhnjk/146e687c0fa163d34ea9058ae5f7a603 to your computer and use it in GitHub Desktop.
How I interpreted the concept of Trusted Types

Digesting the Concept of Trusted Types

This document describes how I interpreted the concept of Trusted Types, and why I think it's important. This is not the universal truth and is subject to change (because the API will likely extend in the future).

Trusted Types enforce developers to define a type for a string, when the string assigment to a sink will result in type conversion (by the browser).

Insecure Defaults

TypeScript is a very popular choice for JS development these days. This is because when you have a strongly typed system, you can catch bugs before it occurs in the wild.

Similar thing can be said for security. Since the beginning of the Web, we use Strings for almost everything.

We use String for:

element.textContent = "<s>hello</s>";

AND

element.innerHTML = "<s>hello</s>";

However, the latter example will result in re-parse of the String, and will be treated as an HTML.

This is the whole problem. A String assignment to textContent and innerHTML should never be treated the same. The latter requires an HTML. Similarly, a Sting shouldn't be assigned to scriptElement.text, it should be a Script instead.

As explained above, Web development has been insecure by default. But Trusted Types provides TrustedHTML, TrustedScript, and TrustedScriptURL types, and perform runtime checks against sinks where the browser applies type conversion to these types.

Why isn't CSP's script-src sufficient?

CSP's script-src allows developers to specify scripts that are intentionally loaded by them, and blocks script execution of any other scripts. However, Script Gadgets showed that commonly used frameworks/libraries contains a code that could lead to a DOM-based XSS. So the believe of CSP's script-src mitigating all XSS was gone.

Why can Trusted Types solve this problem?

Trusted Types' type enforcement applies to all code running in the document. Therefore, if a third-party library loaded in the document has a DOM-based XSS, it will be blocked by the runtime type checks. This means, as long as Trusted Type policies allowed in the document are reviewed and safe, there is mostly no chance of DOM-based XSS in the page.

Will Strict CSP and Trusted Types mitigates all XSS?

There are few known issues.

While Dynamic import should require a TrustedScriptURL, TC39 maintains Dynamic import (while Trusted Types applies in the DOM). Therefore, it needs a solution in the ECMAScript's spec. Dynamic Import Host Adjustment is being proposed for this problem. This can be mitigated by adding allow-list of script URLs in script-src on top of Strict CSP.

Strcit CSP allows 'strict-dynamic', which means if there is a gadget in libraries that tries to add scripts with URL obtained from the DOM, those scripts will be allowed to execute. However, a String assignment to script element's src requires TrustedScriptURL. So normal script gadgets won't work under Strict CSP + Trusted Types enforcement.

But, because things inside a template element (from the intial load of the document) is already parsed, there will be no String to HTML conversion using DOM API. And therefore, Trusted Types won't care about those (i.e. parsed HTML == Stored/Reflected XSS).

Finally, if there is a gadget that look for template element, and append content inside it to the DOM, that will also pass the check for 'strict-dynamic'. Ta-da! XSS 😊 This issue can be mitigated by moving to Nonce-only CSP.

Preventing Futuristic DOM-based XSS

Attacks like Prototype Pollution can introduce a DOM-based XSS in an application by changing the flow of a program.

Trusted Types will still be effective in many cases (assuming that the code in Trusted Type policies are secure).

This is because:

  1. Migration to Trusted Types will remove a lot of code which calls dangerous sinks.
  2. Type enforcement in Trusted Types is a runtime check. Therefore, it can still perform type check against program modified by Prototype Pollution.

For example, exploit like this will set a String to innerHTML, so that will be blocked by Trusted Types.

However, attacks against sanitizers will be hard, as those sanitizers will be allowed to return TrustedHTML. We can still solve this problem with Sanitizer API, because it's guaranteed to return XSS free output.

It's important to note that while DOM-based XSS could be prevented, Prototype Pollution will be able to exploit an application in some other ways.

Conclusion

Frameworks and libraries will keep increasing, and reviewing everything (including changes to those) isn't scalable. Instead, we should move to a world where many websites enforces Trusted Types, and new libraries are expected to be compatible with Trusted Types. That reduces the amout of audit required for JS code against DOM-based XSS.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment