Last Comment Bug 522430 - (CVE-2009-3986) window.opener allows chrome access from unprivileged pages
: window.opener allows chrome access from unprivileged pages
: verified1.9.0.16, verified1.9.1
Product: Core
Classification: Components
Component: DOM (show other bugs)
: Trunk
: All All
: P2 critical (vote)
: mozilla1.9.2
Assigned To: Blake Kaplan (:mrbkap)
: Andrew Overholt [:overholt]
Depends on:
Blocks: 554410
  Show dependency treegraph
Reported: 2009-10-14 23:43 PDT by David James
Modified: 2010-03-24 12:06 PDT (History)
13 users (show)
jst: blocking1.9.2+
samuel.sidler+old: blocking1.9.0.16+
samuel.sidler+old: wanted1.9.0.x+
See Also:
Crash Signature:
QA Whiteboard:
Iteration: ---
Points: ---
Has Regression Range: ---
Has STR: ---

Proposed fix (2.72 KB, patch)
2009-10-20 15:31 PDT, Blake Kaplan (:mrbkap)
jst: review+
jonas: superreview+
dveditz: approval1.9.1.6+
dveditz: approval1.9.0.16+
Details | Diff | Splinter Review
Assertion (1.49 KB, patch)
2009-10-20 15:33 PDT, Blake Kaplan (:mrbkap)
jst: review+
Details | Diff | Splinter Review

Description David James 2009-10-14 23:43:52 PDT
User-Agent:       Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv: Gecko/20091007 Firefox/3.5.4
Build Identifier: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv: Gecko/20091007 Firefox/3.5.4

When new windows are opened in Firefox, the new window has a reference to the window that created it using window.opener. If window.opener is a ChromeWindow, then any webpage opened in this window will be able to access the functions inside the ChromeWindow.

Both Firefox itself and many extensions for Firefox often open windows from within chrome code. With this security hole, windows opened by chrome code are unsafe.

Reproducible: Always

Steps to Reproduce:
1. Select Help -> About Mozilla Firefox
2. Click on "Licensing Information"
3. A new window will open with licensing information. In this window, go to
4. In the URL bar, type javascript:window.opener.URLBarSetURI({spec:""},true)
5. In the URL bar, type javascript:window.opener.BrowserOffline.toggleOfflineStatus()
6. Browse to a web page that contains the above code in a script tag. Note that Firefox's security model does not prevent this code from running.
Actual Results:  
1. The URL bar of the opening window is set to ""
2. The browser is set to work offline
3. Web pages can access and run chrome code

Expected Results:  
The new window should not be able to access properties of the chrome window.

This bug likely effects not just Firefox itself, but also many extensions which open windows using
Comment 1 Samuel Sidler (old account; do not CC) 2009-10-15 13:25:06 PDT
Blake: Weren't XOW supposed to protect us from this? (Note: The JS in step 4 doesn't actually work for me, but step 5 definitely does.)
Comment 2 Benjamin Smedberg [:bsmedberg] 2009-10-16 07:01:31 PDT
Once you've done this it's trivial to exploit to gain sg:crit access. Is this sg:moderate only because you have to do something "unusual" to get the browser to do this bad

(To exploit, call openURI with a chrome URI and then a javascript URI).

I thought we nulled out window.opener when a chrome-privileged page calls without the "chrome" feature, but I can't find the code to actually do that.
Comment 3 Daniel Veditz [:dveditz] 2009-10-16 12:17:44 PDT
It's "moderate" because we don't know of any Firefox dialogs that will open random pages in this way. There is quite a bit of mitigation value if an attacker has to tell the user
 1) open the about dialog
 2) click the license link
 3) now please come visit my page in that window
    (type the URL, paste it, use a bookmark)

It's more likely that some add-on somewhere is doing something like this although we don't know of any specific examples. It would be an sg:critical bug for users of that add-on. Does that make it sg:critical overall? Always? Only if the addon is really popular? I don't know, maybe.

I guess that's a long-winded "yes" to your question.
Comment 4 Daniel Veditz [:dveditz] 2009-10-16 12:37:03 PDT
It's not 'any' window opened by 'any' chrome dialog. New windows opened from the bookmarks/history dialog don't do this, for instance. Is it limited to XUL <label class="text-link"> links?
Comment 5 David James 2009-10-16 13:54:45 PDT
This bug doesn't affect 'any' windows opened from chrome, but it does impact common ways of opening windows from chrome.

Here are some more examples:

Reproduction Recipe A:
  1) Install LiveHTTPHeaders
  2) Go to Tools -> LiveHttpHeaders
  3) Select About -> Check for update
  4) In the new window, type the URL: "javascript:window.opener"

This shows that LiveHTTPHeaders opens a hole with this code:;

Reproduction Recipe B:
  1) Go to Tools -> Options -> Tabs and deselect "Open new windows in a new tab instead"
  2) Install YSlow
  3) Run YSlow on your favourite website
  4) Open the YSlow Panel and click an external link
  5) In the new window, type the URL: "javascript:window.opener"

This shows that YSlow opens a hole with the following code:, " blank");
Comment 6 Blake Kaplan (:mrbkap) 2009-10-20 15:29:37 PDT
(In reply to comment #1)
> Blake: Weren't XOW supposed to protect us from this? (Note: The JS in step 4
> doesn't actually work for me, but step 5 definitely does.)

Sort of -- the problem is that the object we're handing out is *so* wrong, XOWs don't even notice.
Comment 7 Blake Kaplan (:mrbkap) 2009-10-20 15:31:32 PDT
Created attachment 407407 [details] [diff] [review]
Proposed fix

Easy fix: don't return an opener if we're not chrome and the window that we're returning is a chrome window (even content windows with chrome privileges get wrapped and protected).
Comment 8 Blake Kaplan (:mrbkap) 2009-10-20 15:33:28 PDT
Created attachment 407408 [details] [diff] [review]

I don't want to land this at the same time as attachment 407407 [details] [diff] [review] because I think this assertion + that fix make the problem here extremely obvious to interested onlookers. This assertion checks to make sure that we don't ever try to wrap a chrome window in a content scope. As a belt and braces, we could either throw in these cases, or wrap all [object ChromeWindow]s in SystemOnlyWrappers.
Comment 9 Johnny Stenback (:jst, 2009-11-03 09:25:27 PST
Blake, can you land this for trunk and 1.9.2?
Comment 11 Daniel Veditz [:dveditz] 2009-11-04 15:47:23 PST
Comment on attachment 407407 [details] [diff] [review]
Proposed fix

Does the lack of a approval request mean we need a different back-port? Or just an oversight?
Comment 12 Blake Kaplan (:mrbkap) 2009-11-06 02:45:21 PST
Comment on attachment 407407 [details] [diff] [review]
Proposed fix

In this case it means that I forgot to request approval.
Comment 13 Daniel Veditz [:dveditz] 2009-11-06 11:09:07 PST
Comment on attachment 407407 [details] [diff] [review]
Proposed fix

Approved for and, a=dveditz for release-drivers
Comment 14 Johnny Stenback (:jst, 2009-11-10 12:37:40 PST
Comment 15 Johnny Stenback (:jst, 2009-11-13 15:35:14 PST
Fixed in CVS.
Comment 16 Al Billings [:abillings] 2009-11-20 12:58:49 PST
Verified fixed in with Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv: Gecko/20091119 Shiretoko/3.5.6pre (.NET CLR 3.5.30729) using steps in comment 0. 

Used steps in comment 5 for since the licensing link doesn't exist in 1.9.0. Verified fixed for with Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv: Gecko/2009111921 GranParadiso/3.0.16pre (.NET CLR 3.5.30729).
Comment 17 Blake Kaplan (:mrbkap) 2010-03-22 16:39:36 PDT
Comment 18 Blake Kaplan (:mrbkap) 2010-03-22 17:10:26 PDT
I had to back that out because we hit it on tinderbox alive tests...
Comment 19 Blake Kaplan (:mrbkap) 2010-03-24 12:06:03 PDT
Comment on attachment 407408 [details] [diff] [review]

Sadly, we can't do this. Given code like:
    var chromeWin = aWindow 

on a content window (through an XPCNativeWrapper, even), we start in a content scope (the window)... when GI to docshelltreeitem, we create a docshell JS object in the scope we think we're in (i.e. the content window), then when we get the DOMWindow from that, we wrap it in the current scope, which is still the content window... But it's not *really* in that scope, we just think it is.

Note You need to log in before you can comment on or make changes to this bug.