Components.utils.Sandbox

Components.utils.Sandbox is used to create a sandbox object for use with evalInSandbox().

Creating a sandbox

To create a new sandbox, call Components.utils.Sandbox:

var sandbox = Components.utils.Sandbox(principal[, options]);

Using new Components.utils.Sandbox(...) to create a sandbox has the same effect as calling Sandbox(...) without new.

The created sandbox is simply an empty JavaScript object marked as having been created by the restricted privilege principal. You can then use it with evalInSandbox() to make it the global scope object for the specified script.

principal

The security principal defined for a sandbox determines what code running in that sandbox will be allowed to do. The principal may be one of four types: the system principal, a content principal, an expanded principal, or a null principal.

See Security checks for more information on security principals.

System principal

To specify the system principal, you can create it using code like:

 Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal);

Content principal

You can specify a content principal for a particular origin in one of three ways:

  • as an nsIPrincipal, for example by using the nodePrincipal property of a DOM node
  • as an nsIDOMWindow, such as that returned by the DOM window property
  • as a string URI like "http://www.example.com/" (discouraged)

When possible, specify a window or an nsIPrincipal object instead of using a string URI. Window objects and nsIPrincipal carry additional information such as origin attributes and same-origin privilege changes caused by setting document.domain.

Example of obtaining content principal from the window:

var principal = gBrowser.selectedTab.linkedBrowser.contentPrincipal;
var sandbox = Components.utils.Sandbox(principal);

Expanded principal

An expanded principal is specified as an array of the principals it subsumes. Each item in the array should be an nsIPrincipal, a DOM window, or a URI. So this can be simply an array with a single element. For example the content principal above can be made expanded/extended like so:

var principal = [gBrowser.selectedTab.linkedBrowser.contentPrincipal]; // this is now an expanded (aka extended) principal
var sandbox = Components.utils.Sandbox(principal);

Null principal

You can create a null principal using code like:

Cc["@mozilla.org/nullprincipal;1"].createInstance(Ci.nsIPrincipal);

From Firefox 37 onwards, you can also specify the null principal by simply passing null as the principal argument.

options

The constructor accepts an optional parameter. This parameter is an object with the following optional properties:

 

freshZone Requires Gecko 40.0
If true creates a new GC region separate from both the calling context's and the sandbox prototype's region. Addons creating sandboxes whose expected lifetime is tied to that of a content window object will want to use sameZoneAs instead.
sameZoneAs
A JavaScript object in whose garbage collection region the sandbox should be created in. This helps to improve memory usage by allowing sandboxes to be discarded when that zone goes away. Content scripts should pass the window they're running in as this parameter, in order to ensure that the script is cleaned up at the same time as the content itself.
sandboxName

A string value which identifies the sandbox in about:memory (and possibly other places in the future). This property is optional, but very useful for tracking memory usage of add-ons and other JavaScript compartments. A recommended value for this property is an absolute path to the script responsible for creating the sandbox. As of Gecko 13 (Firefox 13.0 / Thunderbird 13.0 / SeaMonkey 2.10), if you don't specify a sandbox name it will default to the caller's filename.

sandboxPrototype

A prototype object for the sandbox. The sandbox will inherit the contents of this object if it's provided.
Passing a content window object, setting wantXrays:true (default) and using an extended principal provides a clean, isolated execution environment in which javascript code that needs Web APIs (such as accessing the window's DOM) can be executed without interference from untrusted content code.

wantComponents

A Boolean indicating whether the Components object is available or not in the sandbox. Default: true.
If the sandbox interacts with untrusted content this should be set to false when possible to further reduce possible attack surface.

wantExportHelpers

A Boolean: if true, then createObjectIn(), evalInWindow(), and exportFunction() are available in the sandbox. Default: false.

wantGlobalProperties
An array of strings. Each string is the name of an object that you want to make available as a global to code running in the sandbox.
The exception is "-Promise": the Promise constructor is available by default for sandboxes, and you use this option to remove it from the sandbox. Note that "-Promise" is removed in Firefox 37.
The following objects are supported:
-Promise (removed in Firefox 37)
CSS
indexedDB (Web Worker only)
XMLHttpRequest
TextEncoder
TextDecoder
URL
URLSearchParams
atob
btoa
Blob
File
crypto
rtcIdentityProvider
fetch (added in Firefox 41)
caches
FileReader

For example:

var sandboxScript = 'var encoded = btoa("Hello");' +
                    'var decoded = atob(encoded);';
var options = {
  "wantGlobalProperties": ["atob", "btoa"]           
}
var sandbox = Components.utils.Sandbox("https://example.org/", options);
Components.utils.evalInSandbox(sandboxScript, sandbox);
console.log(sandbox.encoded);  // "SGVsbG8="
console.log(sandbox.decoded);  // "Hello"
wantXHRConstructor
This option was removed in Gecko version 26. Use wantGlobalProperties instead.
wantXrays

A Boolean value indicating whether the sandbox wants Xray vision with respect to same-origin objects outside the sandbox. Default: true.

Setting wantXrays to false also causes Xrays to be waived on objects in the sandbox.  If you are creating a sandbox with lower privileges than the current compartment, this is probably not what you want.

“Xray vision” is exactly the same Xray behavior that script always gets, by default, when working with DOM objects across origin boundaries. This is primarily visible for chrome code accessing content. However, it also occurs during cross-origin access between two content pages, since each page sees a "vanilla" view of the other. The protection is bidirectional: the caller sees the bonafide DOM objects without being confused by sneakily-redefined properties, and the target receives appropriate privacy from having its expandos inspected by untrusted callers. In situations where only unidirectional protection is needed, callers have the option to waive the X-ray behavior using wrappedJSObject or XPCNativeWrapper.unwrap().

In general, when accessing same-origin content, script gets a Transparent wrapper rather than an Xray wrapper. However, sandboxes are often used when chrome wants to run script as another origin, possibly to interact with the page. In this case, same-origin Xrays are desirable, and wantXrays should be set to true.

See Safely accessing content DOM from chrome for more details.

Methods available on the Sandbox object

dump() - Similar to window.dump().
debug()

For more information on the built-in Sandbox functions, please consult the source code.

Importing functions or objects into the sandbox

You can import functions or objects into the sandbox simply by assigning them to the sandbox object.  For example:

mysandbox.doSomething = function() { ... };

Complex objects can be cloned into the sandbox using Components.utils.cloneInto:

mysandbox.someObject = Components.utils.cloneInto({ a: 'string', b: 21 }, mysandbox);

Obviously you need to consider the security implications of the functions you import. This technique isn't limited to functions - it can be used to import objects or values.

Freeing the sandbox

When you have finished using a sandbox, it should be freed to avoid memory leaks. Generally the JavaScript garbage collector will take care of this when there are no remaining references to the sandbox or the code it contains. However, in some cases it can be difficult to remove all references. For example, the code in the sandbox might be a third-party library that sets expando properties or adds event listeners to a window. In this case, Components.utils.nukeSandbox can be used to force the sandbox to be freed immediately.

Example

Executing in current tab scope

More ways to load scripts into a sandbox can be found on the Loading Scripts page.

This example is to be run from scratchpad with environemnt set to browser. It alerts the dollar sign function. This code was tested on twitter.com and gets access to the jQuery $.

var sandboxScript = 'alert($)';
var options = {
    sandboxPrototype: content,
    wantXrays: false // only set this to false if you need direct access to the page's javascript. true provides a safer, isolated context.
};
var sandbox = Cu.Sandbox(content, options);
Cu.evalInSandbox(sandboxScript, sandbox);
Cu.nukeSandbox(sandbox);

See also