If you think a bug might affect users in the 57 release, please set the correct tracking and status flags for Release Management.

toSource seems to confuse origins

RESOLVED INVALID

Status

()

Firefox
Untriaged
RESOLVED INVALID
2 months ago
2 months ago

People

(Reporter: Abdulrahman Alqabandi, Unassigned)

Tracking

56 Branch
Points:
---

Firefox Tracking Flags

(Not tracked)

Details

Attachments

(1 attachment)

(Reporter)

Description

2 months ago
User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36

Steps to reproduce:

Note: I have not found a way to exploit this but just in case I am missing something, I will hide it as security sensitive. 

Repro (straight from web console):

a=open('https://www.mozilla.org')//create x-origin object
Window about:blank

a.toSource()
SecurityError: Permission denied to access property "toSource" on cross-origin object

this.toSource()//<----- Why is it saying 'this' is a cross origin object? [1]
SecurityError: Permission denied to access property "toSource" on cross-origin object

window.toSource()
SecurityError: Permission denied to access property "toSource" on cross-origin object

toSource.call(this)
SecurityError: Permission denied to access property "toSource" on cross-origin object

toSource.call(a)//<------ Why is it working here? [2]
"({get window() {
    [native code]
}, get location() {
    [native code]...


Actual results:

Two things:
There seems to be confusion regarding 'this' being cross origin + for some reason calling toSource on a cross origin object using the .call function works, but doesnt work on 'this' or 'window' objects (which im pretty sure always point to the main same origin window)


Expected results:

window.toSource() should work and not give out a security error

toSource.call(crossOriginObject) should fail due to security error

In general there seems to be some confusion here (unless im missing something) and given that this has to do with which origin an object is, im marking as security sensitive in case the same confusion is somewhere else.

Comment 1

2 months ago
The web console executes things in a sandbox. Are the results the same when you run the same code in script code in the actual page?
Flags: needinfo?(qab)
(Reporter)

Comment 2

2 months ago
(In reply to :Gijs from comment #1)
> The web console executes things in a sandbox. Are the results the same when
> you run the same code in script code in the actual page?

Yes, works on web as well. (using latest nightly)
Flags: needinfo?(qab)
(Reporter)

Comment 3

2 months ago
Created attachment 8891740 [details]
PoC FWIW

Attached is a PoC showing the weird behavior
>this.toSource()//<----- Why is it saying 'this' is a cross origin object? [1]
>SecurityError: Permission denied to access property "toSource" on cross-origin object

It's not saying 'this' is a cross origin object.  It's saying that there was an attempt to get a property named "toSource" on a cross origin object, and that threw.

In this case that would be because there's a property named "a" on `this`.  And toSource does js::ValueToSource on all the property values of the object, and ValueToSource does, in the case when the value is an object:

    RootedObject obj(cx, &v.toObject());
    if (!GetProperty(cx, obj, obj, cx->names().toSource, &fval))

That does the equivalent of "a.toSource", which throws; that exception is propagated out.

>window.toSource()
>toSource.call(this)

Same thing for both of these.

> toSource.call(a)//<------ Why is it working here? [2]

I was going to say that I get "({})" here, and I do in Firefox 54.  But on trunk I get what you see.  That's because toSource is basically implemented like so:

  var keys = Reflect.ownKeys(obj);
  // Filter out the non-enumerable keys
  // For the remaining ones, get the property descriptor and convert it to source.

Cross-origin properties, the ones that are _exposed_ cross-origin, were made enumerable in bug 1381408 so in a recent nightly they show up in the toSource output.  Again, you could produce identical output using Reflect.ownKeys (or Object.getOwnPropertyNames/Object.getOwnPropertySymbols) and Object.getOwnPropertyDescriptor, in both shipping Firefox and nighty.

So given that, the expectations:

> window.toSource() should work and not give out a security error

No, it should throw, because it ends up doing a get of a property named "toSource" on a cross-origin object, which is not allowed.  In particular, nothing says that "a.toSource", if the get were allowed, would be Object.prototype.toSource.

> toSource.call(crossOriginObject) should fail due to security error

We could make it do so, but there's no obvious need for it: toSource is not doing anything here that you can't do with reflection APIs from JS.  In particular, there are no calls to either CheckedUnwrap or UncheckedUnwrap in anything toSource is doing, so it never pierces the security membrane.  Therefore, any information it can get its hands on is already available to script.

The only reason to do this is if we want a sort of belt-and-suspenders thing here, in case the ToSource implementation ever changes to pierce security membranes.
Group: firefox-core-security
Status: UNCONFIRMED → RESOLVED
Last Resolved: 2 months ago
Resolution: --- → INVALID
You need to log in before you can comment on or make changes to this bug.