Prevent DOM-based XSS with Trusted Types and Content Security Policy with report-uri
Once Trusted Types are enabled, then when a plain string is being passed to a so-called sink like the innerHTML
or the document.write()
method without it being escaped by the Trusted Types policy, a report is generated by the browser.
The string will not actually be passed to the sink, if the policy is enforced. This will protect your app against DOM-based cross-site scripting (XSS) attacks.
However, you may need to update your application to call the policy.createHTML()
method when assigning data to a sink like the innerHTML
property.
But you can also create a policy called default
, which will be automatically called whenever a string is used in a sink that only accepts Trusted Types.
The CSP response header:
Content-Security-Policy: require-trusted-types-for 'script'; report-uri https://ride.has.report/report
Trusted Types with a default policy
#html
sink: …
<script>
trustedTypes.createPolicy('default', {
createHTML: string => string.replaceAll('<', '<'),
});
document.getElementById('prompt-html').onclick = function() {
const html = prompt('Enter any HTML', 'foo <strong>bar</strong>');
if (html) {
document.getElementById('html').innerHTML = html;
}
}
</script>
The #html
sink:
- Is allowed in a way that it will display the HTML you've entered, automatically escaped by the default policy
-
Behind the scenes, it uses the
createHTML()
method of thedefault
policy created bytrustedTypes.createPolicy()
- … to replace all
<
("less than") characters with<
entity, a very simple and naive escaping function
- … to replace all
-
If you enter let's say
<em>
, this is what happens automatically, behind the scenes:createHTML()
will convert it to<em>
- Wrap it in a
TrustedHTML
object - And pass it to the
innerHTML
sink
- Note that your browser, not the policy, will convert
>
to>
as well, so in Developer Tools you will see<em>
Related specs & documents
- My article about DOM XSS and Trusted Types (also available in Czech)
- Trusted Types Editor's Draft
- Prevent DOM-based cross-site scripting vulnerabilities with Trusted Types on web.dev
- Trusted Types API on MDN