Exposing add-on objects to content safely

Jorge Villalobos

21

Add-ons often need to interact with page content, and mixing privileged and unprivileged code can be tricky thing to get right without compromising security. Unintentionally exposing privileged objects to web content is a major security concern, which is why bug 553102 came about.

The idea behind this bug is simple: if you need to share an object to a script in the content, you need to add it to a whitelist. Starting with version 15, Firefox will show an error in the Error Console whenever a privileged object property or function is accessed from the content without it being added to the whitelist. The code will continue to work, but the error is there to let add-on developers know that they need to change this as soon as possible. In Firefox 17, the whitelist will become mandatory and the shared object members will cease to be visible from content.

How It Works

If you wanted to share an object to the content, from your add-on code you would do something like this:

var sharedObject = { foo : "Hello!" };
contentWindow.wrappedJSObject.sharedObject = sharedObject;

Then from a script in the content you can do something like this:

alert(window.sharedObject.foo);

And this would alert the text “Hello!” in the page. Starting with Firefox 17, this won’t work. The page will be able to see window.sharedObject, but none of its properties or functions will be visible. For it to work, you now must do this in your add-on code:

var sharedObject = { foo : "Hello!", __exposedProps__ : { foo : "r"} };
contentWindow.wrappedJSObject.sharedObject = sharedObject;

The __exposedProps__ property is the whitelist that tells Firefox it’s okay to share foo with the content. The value can be “r” (read-only), “w” (write-only), or “rw” (read and write). You generally want to use “r”.

Note that this only affects your add-on if you’re sharing objects with the content. If all you’re doing is passing values like numbers, booleans or strings, they should continue to work.

Still, it is recommended that all add-on devs thoroughly test their add-ons in Firefox 15 (beta at the moment) and look for the deprecation error in the Error Console. Then test it in Firefox 17 (nightly at the moment) and see if anything breaks when interacting with content.

If your add-on is based on the Add-ons SDK, you should update your add-on to the latest release of the SDK and test. You probably won’t need to change any code, since the SDK should take care of this for you.

If you have any questions about this, please share them in the comments.

21 responses

  1. Matt wrote on :

    How can you tell from the following message which extension is the culprit? I have dozens of Jetpack extensions installed

    Error: Exposing chrome JS objects to content without __exposedProps__ is insecure and deprecated. See https://developer.mozilla.org/en/XPConnect_wrappers for more information.
    Source File: resource://jid0-agjxxzys0rt1uudxcyinrjbgttc-at-jetpack/api-utils/lib/cuddlefish.js -> resource://jid0-agjxxzys0rt1uudxcyinrjbgttc-at-jetpack/api-utils/lib/sandbox.js -> resource://jid0-agjxxzys0rt1uudxcyinrjbgttc-at-jetpack/api-utils/data/worker.js
    Line: 130

    1. Jorge Villalobos wrote on ::

      The “jid0-agjxxzys0rt1uudxcyinrjbgttc-at-jetpack” bit in the URL identifies the add-on. Some googling points to this add-on: Flip or Rotate Image.

  2. adrian wrote on :

    Has the error been removed from 17, and the plugins just fail silently? This is what seems to be happening to my plugins, no more error, just silent fail.

    1. Jorge Villalobos wrote on ::

      The deprecation error doesn’t appear on 17. It’s easier to debug the error on 15 or 16. The object members are just not exposed anymore, and the error, if any, would occur in the content.

      1. Kris wrote on :

        That’s kind of annoying. We should just throw.

  3. Renkema wrote on :

    I am getting this error (FF15) , and it points to jQuery. (jquery/1.7.2/jquery.min.js)

    Exposing chrome JS objects to content without __exposedProps__ is insecure and deprecated. See https://developer.mozilla.org/en/XPConnect_wrappers for more information.
    [Break On This Error]

    …ction(a,b){var c=b[0],e=b[1],g;f.isFunction(c)?i[a](function(){g=c.apply(this,ar…

    Does that mean that jQuery does not conform to the standard? Do I simply lean back and wait for an update on JQuery?

    Or am I doing something wrong? In that case, I do no see any hint as what my mistake might be…

    1. Jorge Villalobos wrote on ::

      Can you try with an unminified version? Then the error would be easier to track down.

  4. Drew Stoddard wrote on ::

    In our add-on we open a child browser window, show a web page to get some user input, then close the window. This has worked fine until FF15. Now we’re getting this error:

    Error: Exposing chrome JS objects to content without __exposedProps__ is insecure and deprecated. See https://developer.mozilla.org/en/XPConnect_wrappers for more information.
    Source File: http://.appspot.com/sharedlg.jsp

    The jsp file is simply the content file for the child browser window. It does nothing special but it has content scripts which operate controls using jQuery for appearance. That code used to operate prior to FF15 but now fails.

    Any idea what the error message is trying to say regarding that .jsp file? I don’t understand how I would add a __exposedProps__ property to an entire .jsp file. Any guidance would be very much appreciated.

    1. Jorge Villalobos wrote on ::

      Could it be related to this other bug?

  5. Renkema wrote on :

    (following up on my post of August 30th.)

    Hi Jorge,

    Thanks for your response.

    When I switch to jQuery 1.7.2. unminified, I get:

    src = target[ name ]; jquery.js (line 355)

    This seems to be part of the extend() function-definition …

    1. Renkema wrote on :

      The error seems to pop up when I am dragging a div which is .draggable().

      1. Jorge Villalobos wrote on ::

        Was the div generated from a chrome script? Did you set any special JS properties to it? Is there anywhere I can see the code you’re using?

        1. Renkema wrote on :

          Yes, you can. The site is http://www.time-proof.org; but it is under construction.

          Make an account for yourself and then visit
          http://www.time-proof.org/site/workspace

          Please email me if you run into issues.

          Thanks,

          1. Jorge Villalobos wrote on ::

            Wait. Are you getting this error just by using the website? I thought this was an add-on you were developing.

            Do you have any add-ons installed? Have you tried disabling them to see if the error disappears?

  6. Stefan wrote on :

    Hi Jorge,

    Can you help me, i try to add the __exposedProps__ code.
    But it still give me the same error. :(
    https://forums.mozilla.org/addons/viewtopic.php?t=11262&p=23979

  7. Andy Wright wrote on :

    The FireQuery Firebug plugin seems to be causing this for me!

  8. Paul Broman wrote on :

    So I have released a Jetpack extension which uses page-mod, and it seems ANYTHING which is being injected via page-mod is causing this error message to appear. I started to look into this today, with the hopes of changing everything to use __exposedProps__, but no luck.

    I was able to repro this just by doing something like:

    var pageAttach=
    {
    include: ["http://*],
    contentScriptWhen: “ready”,
    contentScript: “var foo= ‘bar’;”,
    }
    require(“page-mod”).PageMod(pageAttach);

    Sure enough, I see “Exposing chrome JS objects to content without __exposedProps__ …” and it flags:
    javascript:var foo= ‘bar’; (Line: 1)

    I even tried using a contentScript of “var foo= { bar: “baz”, __exposedProps__: { bar: “rw” } };” and it still shows this error.

  9. upit wrote on :

    Hi,
    I have,

    var sharedObject = { foo : “Hello!” };
    contentWindow.wrappedJSObject.sharedObject = sharedObject;

    in a sample Hello World extension downloaded from Mozilla website.
    and,
    alert(window.sharedObject.foo); in my webpage script, but it doesn’t work. I have firefox 16.0.2.
    The log says window.sharedObject.foo is undefined.

    Would you be able to tell what the problem is ? Do I have to migrate to FF 17 ?

  10. adam-p wrote on :

    It would be helpful to have examples for nested objects and arrays. Neither is instantly obvious, and especially arrays.

    Also, with arrays, they seem to stop being arrays when going from background to content. That is, Array.isArray fails and there’s no length (even if I add an exposedProps entry for length). You end up with something like {0:’a’, 1:’b’, etc.}.

    Here’s my brute-force blunt-instrument code for adding __exposedProps__.

    function addExposedProps(obj) {
    var key, i;

    if (typeof(obj) === ‘undefined’ || obj === null) {
    return;
    }

    // Note that this code path is for Objects and Arrays
    if (typeof(obj) === ‘object’) {
    if (!(‘__exposedProps__’ in obj)) {
    obj['__exposedProps__'] = {};
    }

    // WARNING: I don’t actually use this if-block in my code, since it doesn’t work.
    // But for interest’s sake…
    if (Array.isArray(obj)) {
    obj['__exposedProps__']['length'] = ‘rw’;
    }

    for (key in obj) {
    if (key === ‘__exposedProps__’) {
    continue;
    }
    obj['__exposedProps__'][key] = ‘rw’;
    addExposedProps(obj[key]);
    }
    }
    }

  11. skomorokh wrote on :

    Is there any way to permit code using evalInSandbox() to create new properties with arbitrary names? It’s easy enough to explicitly expose exising properties I want to share, but rather inefficient to expose all combinations of characters that constitute a valid property name.

    My particular case is a facility to mutate nested key/value data from a user script while maintaining deep references. The best workaround I can see at this point is passing it in and out of the sandbox via JSON strings and doing some recursive copying from scalar-to-scalar to get things out of the deserialised object.

    However, it doesn’t seem like properties created within a sandbox run the risk of “unintentionally exposing privileged objects” (provided the xray wrapper is working to prevent a sneaky .toString from being triggered by a stray == or other such chicanery).

    Also, while I can see the need for extreme caution with assumed-malicious web content, sandbox objects can have a variety of applications. It would be nice to be able to create a sandbox without this requirement (pre ff16 style), at the moment it’s all-or-nothing and prevents some opportunistic application of sandboxing to reduce attack surface.

    1. Jorge Villalobos wrote on ::

      I don’t think there’s a way to do this, but I couldn’t tell you for sure. You would need to either look at the code or ask the devs if there’s any way to accomplish it.