Caja host page API documentation

This is the main API for host pages to use Caja for embedding untrusted guest code. A host page includes the caja.js script, for example:

<script src="http://caja.appspot.com/caja.js"></script>

This places a singleton object, caja, in the host page's global namespace. The API of the caja object and the objects reachable from it is described here.

caja

The entry point for access to the Caja host page API.

Properties
policy

A pre-configured set of policies (see policy) for use by host code, as an alternative to constructing a uriPolicy from scratch.

Methods
initialize ( params )

Sets the default parameters for Caja.

This method must be called before any calls to whenReady or load. If either of these is called first, a built-in set of parameters will be used and any subsequent calls to initialize will throw. The resulting exceptions leave Caja in a consistent state.

params

a map of configuration parameters. These include:

  • server: a string giving the URL of the Caja server. This must match the location from which the caja.js script was sourced. For example, if the script was from http://caja.appspot.com/caja.js, then cajaServer must, correspondingly, be http://caja.appspot.com/.
  • resources: a string giving the URL of the location at which the Caja JavaScript runtime resources are found. If unspecified, this location is deduced from the server parameter.
  • debug: a boolean indicating whether to configure Caja for debugging. At this time, debugging support means that the code loaded into the browser will be pretty-printed for readability, rather than minified for speed.
  • console: an object that the Caja runtime is to use in place of the native browser's console global object. If unspecified, Caja will fall back to the native console, and silently suppress console logging if that is unavailable.
  • log: a function that the Caja runtime is to use in place of the native browser's console.log function. If unspecified, Caja will fall back to the log function in the supplied console object (see above). If unspecified, Caja will fall back to the browser's native console.log function. If that is unavailable, Caja will silently suppress console logging.
whenReady ( callback )

Registers a function to be called back when Caja is ready to provide services.

callback

a callback function.

load ( div, uriPolicy, callback )

Load a new virtual Caja frame in which to run guest code.

div

an HTML <div> which will contain the guest code's virtual HTML document

The caller may pass undefined, which causes the guest code to run with no virtual document (e.g., for running plain JavaScript without a UI).

Experimental: It is also possible to provide a HTML document node, such as an <iframe>'s contentDocument, instead of an element. This mode of operation has not been fully tested and may have missing functionality. Note that the provided document cannot be the same as the one in which caja.js was loaded, as this would overwrite Caja's internal iframes.

uriPolicy

a uriPolicy object that is called whenever guest code attempts to gain access to an external URI.

The caller may pass undefined, which disables all guest code's access to URIs, including via HTML such as <img src="..."> markup.

callback

a function(frame) which will be called back with a frame object when ready.

tame ( aDefensiveObject )

Tames a graph of defensive objects rooted at the supplied object. The result of taming is provided to guest code via the apis method of the frame object.

For the most part, Caja automatically tames objects in a safe manner respecting the most common API choices.

Records and arrays. Records and arrays are tamed as read-only objects. Therefore, if you tame the record:

/* host page code */
var f = {
  x: 3,
  y: 4
};

/* then provide to guest code: */
aFrame.api({ tamedF: caja.tame(f) })

guest code using the tamed form tamedF will be able to read the values of x and y, but will not be able to modify them:

/* guest code */
print(tamedF.x);
print(tamedF.y);
tamedF.x = 42;   // Error
tamedF.foo = 19; // Error

Functions: Functions are tamed as pure functions that are not supplied with a this variable. This means that, if you tame the function:

/* host page code */
function f(x) { alert(this); alert(x); }
var t = caja.tame(f);

guest code using the tamed form t will be able to call your function, pass it arguments, and receive its returned value. However, the this value seen by your code will be a useless, empty record provided by Caja. The reason is that a function which modifies its this could be used by malicious guest code as a tool to manipulate objects that the guest code would not otherwise have had the authority to manipulate, and it is not common for JavaScript functions to check the progeny of their this variable on each invocation.

Recursion: Caja recursively traverses records and arrays and tames the values found inside them. Arguments passed from guest code to host functions are un-tamed, then the return value of the host function is tamed.

aDefensiveObject

a defensive object to be tamed. This object may have taming annotations on some of its components.

Returns

a tamed object suitable for presenting to guest code, representing the supplied defensive object.

untame ( aTamedObject )

Obtain the original defensive object corresponding to a tamed object.

aTamedObject

a tamed object obtained via calling tame.

Returns

the original defensive object underlying aTamedObject.

markReadOnlyRecord ( f )

Marks a record such that guest code cannot make modifications to the properties of the tamed form of the record. Only the supplied record is affected -- not any other object that may be connected to it. For example, in the following:

/* host page code */
var rw = { x: 3 };
var ro = { x : 4 }
caja.markReadOnlyRecord(ro);
var rot = caja.tame(ro);
var rwt = caja.tame(rw);

guest code using the tamed value rwt would be allowed to modify the value of x or delete the property, or add a new property y. However, guest code using the tamed value rot would encounter an exception.

f

a record in the host page.

Returns

the supplied f.

markFunction ( f )

Marks a host function to be made callable from guest code when tamed. For example, in the following:

/* host page code */
function ping(x) { alert('pinged ' + x); }
caja.markFunction(ping);

/* then provide to guest code: */
aFrame.api({ ping: caja.tame(ping) })

guest code would be able to use the value ping as a function, for example:

/* guest code */
ping('hello world');

By default, functions from the host page are tamed as inert objects that have no useful behavior. This is a safety feature, because functions in the host page generally represent authority to affect the world. By calling markFunction, a host page author affirms that they have audited the behavior of the target function and have determined (a) that the authority it has is indeed okay to provide to the guest code; and (b) that the invariants upon which the correctness of the function depends cannot be violated by passing the function corrupted arguments. That last point requires, for example, that numeric indices are checked for bounds, and that strings passed from guest code are not used in a manner that could grant access to internal data structures.

f

a function in the host page.

Returns

the supplied f.

markXo4a ( f )

Mark a host function as suitable for taming as an exophora, meaning, a function that receives any this value it is called on. Use only with care.

Consider the following host code:

/* host page code */
function f(x) { this.dangerous = x; }
caja.markXo4a(f);

/* then provide to guest code: */
aFrame.api({ tamedF: caja.tame(f) })

Guest code using the function tamedF would be able to set the property dangerous on any object of its choosing, regardless of any policies to the contrary. So, if victim were an object that relied on its dangerous property and did not make that available to external clients, the following guest code:

/* guest code */
victim.method = tamedF;
victim.method(42);

or even:

/* guest code */
tamedF.apply(victim, [42]);

would set the dangerous property of victim to the value 42, regardless of policies to the contrary.

The rule for when an exophora is safe is that it only gets or sets whitelisted properties of the this value on which it is called, in other words, properties that do not interfere with any object's internals. It may do so because the property (such as dangerous above) is known to always be safe, or because the function itself (like f above) contains enough internal checks to make sure it never does the wrong thing.

In general, true reasons for using exophora are rare. We advise the use of other, safer mechanisms, with exophora as a last resort.

f

a function in the host page.

Returns

the supplied f.

markCtor ( c )

Marks a host function as a constructor that, when tamed, can be used by guest code using the new operator, with correct behavior of instanceof. Consider the following host code:

/* host page code */
function Ctor(x) { this.x = x; }
Ctor.prototype.getX = function() { return this.x; };
Ctor.prototype.setX = function(x) { this.x = x; };

function SubCtor(x, y) { Ctor.call(this, x); this.y = y; }
SubCtor.prototype = new Ctor(0);
SubCtor.prototype.getY = function() { return this.y; };
SubCtor.prototype.setY = function(y) { this.y = y; };

In a case where Ctor and SubCtor are to be made available to guest code, it is necessary to annotate them so that Caja can tame them correctly. Each constructor must be marked with markCtor and, if a constructor has a superclass, that must be provided as the second argument to markCtor. For example:

/* host page code */
caja.markCtor(Ctor);
caja.markCtor(SubCtor, Ctor);

/* then provide to guest code: */
aFrame.api({
  TamedCtor: caja.tame(Ctor),
  TamedSubCtor: caja.tame(SubCtor)
})

When guest code creates instances of these constructors, e.g., by calling:

/* guest code */
var o = new TamedCtor(19);

Caja will ensure that the instances, like o in the example, are tamed correctly.

c

a constructor in the host page.

Returns

the supplied c.

grantMethod ( o, name )

Marks a function property on an object and its prototype chain descendants such that tamed code can call it as a method on its parent object. A method (as opposed to a pure function) is called with a properly bound this value.

By default, to prevent confusion and enhance defensibility, if guest code has access to a tamed object o, and there exists a property p on o such that the value of o.p is a function, then if guest code invokes the function by writing o.p(), the implementation of the function pointed to by o.p does not receive o as its value of this (it receives some useless value instead).

Host code can use grantMethod to override this default. A common use case is when taming idiomatic JavaScript classes. Consider the host code:

/* host page code */
function Ctor(x) { this.x = x; }
Ctor.prototype.getX = function() { return this.x; };
Ctor.prototype.setX = function(x) { this.x = x; };

Assume the host page wishes to allow guest code to call getX and setX on instances of Ctor and for this in these functions to be bound correctly. The host page should do:

/* host page code */
caja.markCtor(Ctor);
caja.grantMethod(Ctor.prototype, "getX");
caja.grantMethod(Ctor.prototype, "setX");

/* then provide to guest code: */
aFrame.api({
  TamedCtor: tame(Ctor),
})

Guest code can then make the following calls to getX and setX and expect them to work:

/* guest code */
var o = new TamedCtor(19);
o.getX();
o.setX(22);
o

an object (often but not always the prototype of a constructor).

name

the name of a property on object o (or anticipated objects having o as their prototype).

Returns

the supplied o.

grantRead ( o, name )

Marks a property on an object and its prototype chain decendants such that tamed code can read the property on its parent object. A common use case is when taming idiomatic JavaScript classes. Consider the host code:

/* host page code */
function Ctor(x) { this.x = x; }

Assume the host page wishes to allow guest code to read the x property on instances of Ctor. The host page should do:

/* host page code */
caja.markCtor(Ctor);
caja.grantRead(Ctor.prototype, "x");

/* then provide to guest code: */
aFrame.api({
  TamedCtor: tame(Ctor),
})

Guest code can then read x as follows and expect the read operation to work:

/* guest code */
var o = new TamedCtor(19);
o.x;
o

an object (often but not always the prototype of a constructor).

name

the name of a property on object o (or anticipated objects having o as their prototype).

Returns

the supplied o.

grantReadWrite ( o, name )

Marks a property on an object and its prototype chain decendants such that tamed code can read and write the property on its parent object. A common use case is when taming idiomatic JavaScript classes. Consider the host code:

/* host page code */
function Ctor(x) { this.x = x; }

Assume the host page wishes to allow guest code to read and write the x property on instances of Ctor. The host page should do:

/* host page code */
caja.markCtor(Ctor);
caja.grantReadWrite(Ctor.prototype, "x");

/* then provide to guest code: */
aFrame.api({
  TamedCtor: tame(Ctor),
})

Guest code can then read and write x as follows and expect the read and write operations to work:

/* guest code */
var o = new TamedCtor(19);
o.x = 23;
o.x;
o

an object (often but not always the prototype of a constructor).

name

the name of a property on object o (or anticipated objects having o as their prototype).

Returns

the supplied o.

Examples
Setting defaults
/* host page code */
caja.initialize({
  cajaServer: 'http://caja.appspot.com/',
  debug: false
});

Sets the defaults to point to caja.appspot.com without debug support.

Erroneous initialize
/* host page code */
caja.whenReady(function() { /* ... */ });
caja.initialize({ /* ... */ });

The call to initialize throws since whenReady has already been called.

Erroneous initialize
/* host page code */
caja.load( /* ... */ );
caja.initialize({ /* ... */ });

The call to initialize throws since load has already been called.

Incorrect taming
/* host page code */
/* in a top-level script */
caja.markFunction( /* ... */ );
caja.tame( /* ... */ );

Both calls to the caja object throw since, when the main scripts in the page are being evaluated, the caja object is not yet ready.

Successful taming
/* host page code */
/* in a top-level script */
caja.whenReady(function() {
  caja.markFunction( /* ... */ );
  caja.tame( /* ... */ );
});

The calls to markFunction and tame succeed.

Running guest HTML from a URL

Assume the host page has some HTML like the following:

<!-- host page markup -->
<div id="guestDiv"></div>

Then the following code in the page:

/* host page code */
caja.initialize({ cajaServer: 'http://caja.appspot.com' });
caja.load(
    document.getElementById('guestDiv'),
    undefined,  // no network access
    function(frame) {
      frame.code('http://foo.com/guest.html')
           .run(function() {
             alert('Guest code is running!');
           });
    });

loads http://foo.com/guest.html as a guest page into the pre-arranged <div> and alerts when the guest page is loaded.

Running guest JavaScript from content

The following code in a host page:

/* host page code */
caja.initialize({ cajaServer: 'http://caja.appspot.com' });
caja.load(
    undefined,  // no DOM access
    undefined,  // no network access
    function(frame) {
      frame.code(
               'http://example.com/default.js',  // dummy URL
               'application/javascript',
               '(x + y);')  // input source code
           .api({ x: 3, y: 4 })
           .run(function(result) {
             alert(result);
           });
    });

will run the provided source, pass it the supplied values of x and y, and alert the result of the computation, which would be the number 7.

Providing a restricted user alert function

Imagine a host page wishes to give guest code the ability to call alert, but not to abuse it by calling it too many times. Assume the host page has HTML like the following:

<!-- host page markup -->
<div id="guestDiv"></div>

Then the following code:

/* host page code */
var alertCount = 0;
var restrictedAlert = function(s) {
  if (alertCount === 2) { return; }
  alertCount++;
  alert(String(s));
};

caja.initialize({ cajaServer: 'http://caja.appspot.com' });
caja.whenReady(function() {
  caja.markFunction(restrictedAlert);
});

caja.load(
    document.getElementById('guestDiv'),
    undefined,  // no network access
    function(frame) {
      frame.code('http://foo.com/guest.html')
           .api({ alert: caja.tame(restrictedAlert) })
           .run(function() {
             alert('Guest code is running!');
           });
    });

will run the provided source, allowing it to call an alert function that will seem like the browser-provided version, but all but the first three attempts to call it will be silent no-ops.

frame

Object representing a virtual frame in which Caja runs guest code. Contains a confined ECMAScript 5 JavaScript context, with an optional confined DOM document.

Methods
code ( uri, mimeType, content )

Specifies that this frame is to run code supplied by the host. The Caja system in the page will use its connection to the server to compile ("cajole") the supplied code.

uri

The URI of the original (un-cajoled) content.

mimeType

Optional. The MIME type of the original (un-cajoled) content. Accepted values are text/html and application/javascript.

content

Optional. The literal content to be run. If not supplied, Caja will retrieve the content using the uri parameter.

Returns

this frame object.

api ( o )

Specifies the APIs that will be provided to the guest code.

o

an object containing named fields, each of which becomes a top-level API that guest code can use. Each such object should be tamed using the tame method.

Returns

this frame object.

run ( callback )

Runs code in the frame according to the information provided by previous calls to some combination of code, cajoled and api.

callback

a function(result) wich will be called back with the completion value of the code executed in this frame. HTML has no completion value, while the completion value of JavaScript is the same as the result of evaluating it using the standard eval operator.

Returns

this frame object.

policy

A pre-configured set of policies for use by host code.

Properties
net.NO_NETWORK

A uriPolicy that disallows all network access.

net.ALL

A uriPolicy that allows all network access.

Methods
net.only ( uri )

Constructs a uriPolicy that allows only access to a specified URI.

uri

the sole URI to be allowed.

Returns

a uriPolicy allowing access only to the specified URI.

uriPolicy

An object that is called to determine whether, and how, guest code should be allowed to gain access to external URIs.

Methods
rewrite ( uri )

Determines whether the given URI should be permitted.

uri

a fully qualified candidate URI, represented as a string.

Returns

a truthy value iff the candidate URI is one which should be accessible to the guest code.

Examples
Restricted domain
/* host page code */
var aPolicy = {
  rewrite: function(uri) {
    return /http:\/\/example\.com/\.*/.test(uri);
  }
};

Constructs a uriPolicy which only allows access to HTTP URL paths under the example.com domain.

Unrestricted
/* host page code */
var aPolicy = {
  rewrite: function(uri) { return true; }
};

Constructs a uriPolicy which allows unrestricted access.