Closed Bug 1136238 Opened 5 years ago Closed 5 years ago

iFrame sandbox=allow-same-origin runs injected event handler without allow-scripts flag

Categories

(Core :: DOM: Security, defect)

36 Branch
x86
macOS
defect
Not set

Tracking

()

RESOLVED WORKSFORME

People

(Reporter: jon, Assigned: bobowen)

Details

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

Steps to reproduce:

Hi, the following JSFiddle executes Javascript on Firefox. I have tested versions 35 and 36 on Mac and Windows. The Javascript does not execute on Chrome, Safari, or IE11.

http://jsfiddle.net/sk9vwn72/12/


Actual results:

An attacker is able to craft an attack if he can set the contents of an iframe and later grab those contents.


Expected results:

The javascript would have not executed.
testcase copied from jsfiddle, need cleanup to run in browser.

<iframe id="testframe" sandbox="allow-same-origin"></iframe>
doc = document.getElementById('testframe').contentWindow.document;
doc.open();
doc.write("<img src='ojijaidsf' onerror='alert(\"I show up on Firefox, not in Chrome or Safari\");'/>");
doc.close();
$frame = $('#testframe');
c = $frame.contents().children();
$('<div>').append(c);


The sandbox has the allow-same-origin flag so the parent page can write into it. It does NOT have the allow-scripts flag, but the onerror on the <img> fires anyway. I guess it's picking up the non-sandboxed origin of the parent when the event handler is set? I hope we don't just execute on* handlers in sandboxes.

Steve: does your team own iframe sandbox? I think the work was originally done by seceng (imelven). If not please find an owner in the DOM team.
Status: UNCONFIRMED → NEW
Component: Untriaged → DOM: Security
Ever confirmed: true
Flags: needinfo?(sworkman)
Keywords: sec-moderate
Summary: iFrame contents executed through DOM manipulation → iFrame sandbox=allow-same-origin runs injected event handler without allow-scripts flag
Tanvi, do you want to take this one?
Flags: needinfo?(sworkman) → needinfo?(tanvi)
Spoke to Tanvi offline - Bob Owen might be better for this one. Bob, can you take this?
Flags: needinfo?(tanvi) → needinfo?(bobowen.code)
(In reply to Steve Workman [:sworkman] (please use needinfo) from comment #3)
> Spoke to Tanvi offline - Bob Owen might be better for this one. Bob, can you
> take this?

It's been a while since I looked at iframe sandbox code and I can't picture where this particular code is immediately.

However, I've probably looked at this more recently than anyone else and it will do me good to refresh my memory, so yes I'll take a look.
Assignee: nobody → bobowen.code
Status: NEW → ASSIGNED
Flags: needinfo?(bobowen.code)
(In reply to Daniel Veditz [:dveditz] from comment #1)
> testcase copied from jsfiddle, need cleanup to run in browser.
> 
> <iframe id="testframe" sandbox="allow-same-origin"></iframe>
> doc = document.getElementById('testframe').contentWindow.document;
> doc.open();
> doc.write("<img src='ojijaidsf' onerror='alert(\"I show up on Firefox, not
> in Chrome or Safari\");'/>");
> doc.close();
> $frame = $('#testframe');
> c = $frame.contents().children();
> $('<div>').append(c);

The behaviour is definitely different between Chrome and Firefox here, but I don't think it's to do with the sandbox.

The script isn't running in the context on the iframe, it's running in the context of the "result" iframe.
This seems to be because of the |$('<div>').append(c);| line.
When the doc.write happens I can see the event handler getting blocked at [1] as you'd expect.
But on the append to the scripted div it doesn't get blocked because the "result" iframe has "allow-forms allow-popups allow-scripts allow-same-origin".

You can see this more clearly if you give the test iframe a name and alert(window.name).
Like this: http://jsfiddle.net/b0ewpLny/

I'm not sure if this is how the copying of the contents is supposed to work with event handlers.
smaug - do you know how this is supposed to work?


If I remove the iframe sandbox attribute it still alerts "result".
If I then comment out the |$('<div>').append(c);| line, it alerts "testframe".
Almost as if the scripted div steals the error, which I guess is possible.

On Chrome, if I remove the sandbox attribute there is still no alert.
However, if I then comment out the |$('<div>').append(c);| line, it alerts "testframe".
Which if anything seems even more strange.


[1] https://hg.mozilla.org/mozilla-central/file/6608e0605dfc/dom/events/EventListenerManager.cpp#l684
Flags: needinfo?(bugs)
non-jquery test would be nice?
I don't know what
c = $frame.contents().children();
$('<div>').append(c);
do.

Assuming $('<div>').append(c); ends up create a <div> in the context of the parent document, which
doesn't have the sandbox flags, and append(c) then moves some elements from iframe's document to be
under the <div>, calling the event listener is right.
Flags: needinfo?(bugs)
(In reply to Olli Pettay [:smaug] from comment #6)
> non-jquery test would be nice?
> I don't know what
> c = $frame.contents().children();
> $('<div>').append(c);
> do.
> 
> Assuming $('<div>').append(c); ends up create a <div> in the context of the
> parent document, which
> doesn't have the sandbox flags, and append(c) then moves some elements from
> iframe's document to be
> under the <div>, calling the event listener is right.

Thanks smaug.

Dan - I think it looks like this is working as expected.
Flags: needinfo?(dveditz)
I agree, as intended. Given the various browser differences it may be an underspecified area, but given the event handler happens outside the sandbox and the outer page has legitimate access to the contents of the sandbox ('allow-same-origin') this is WFM.
Group: core-security
Status: ASSIGNED → RESOLVED
Closed: 5 years ago
Flags: needinfo?(dveditz)
Keywords: sec-moderate
Resolution: --- → WORKSFORME
You need to log in before you can comment on or make changes to this bug.