Skip to content

Add keyword to prevent parser-based JS APIs from adding new scripts  #191

@arturjanc

Description

@arturjanc

Context
whatwg/html#2300 (particularly the comment thread)
https://codereview.chromium.org/2657623005

Summary
Let's add a new script-src keyword ('safe-dynamic-markup') which will prevent the execution of scripts added to the DOM via a parser-pased JS API (Element.innerHTML, document.write, etc). When a new script element is added, the user-agent should check if its parser-inserted flag is set, and if the element has been added via a JS API, and if both conditions are met and the 'safe-dynamic-markup' keyword is specified, block the execution of the script and report a violation.

To be effective, this also has to apply to scripts inside frames which inherit the policy of the embedding page (iframe#srcdoc).

Background
There are three main kinds of DOM APIs which lead to DOM XSS bugs:

  • eval() & co. which directly execute scripts based on their arguments
  • window.open(), assignments to location.href, etc which allow script execution via javascript: URIs.
  • Parser-based APIs such as innerHTML, document.write and related functions.

CSP already mitigates the first two types (via a policy without 'unsafe-eval' and 'unsafe-inline' respectively), and it prevents the execution of inline event handlers ('onclick', etc) if an injection into a parser-based API happens. However, an injection into such an API can still lead to script execution: in whitelist-based CSP, if the policy contains a domain with a "bypassable endpoint" (e.g. a JSONP endpoint or a hosted copy of AngularJS) an attacker will be able to source it as a script (<iframe srcdoc='<script src=//cdn.org/angular.js></script>'></iframe> and bypass the policy; in a nonce-based policy, an attacker who exfiltrates the nonce via dangling markup or another technique will be able to use the stolen nonce (<iframe srcdoc='<script nonce=[stolen]>alert()</script>'></iframe>).

If we allow developers to block the execution of all scripts added via parser-based JS APIs, it will get us fairly close to preventing the exploitation of DOM XSS via native platform APIs (though some JS libraries might still open up their own new attack vectors).

Compatibility
In a lucky turn of events, many applications with a useful CSP (without 'unsafe-inline') are already compatible with the proposed keyword because adding new script elements at runtime usually happens via programmatic APIs (createElement('script')). The patterns which would need to be refactored are:

Overall it seems like it could be a useful defense-in-depth against DOM XSS bugs and bypasses of CSP, with a reasonably high chance of being adoptable in many applications without significant effort.

Metadata

Metadata

Assignees

No one assigned

    Labels

    addition/proposalNew features or enhancementsneeds concrete proposalMoving the issue forward requires someone to figure out a detailed plan

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions