Download as pdf or txt
Download as pdf or txt
You are on page 1of 11

Cross-Origin JavaScript Capability Leaks:

Detection, Exploitation, and Defense


Adam Barth Joel Weinberger Dawn Song
UC Berkeley UC Berkeley UC Berkeley
abarth@eecs.berkeley.edu jww@cs.berkeley.edu dawnsong@cs.berkeley.edu

Abstract a script attempts to access the cookie database, the


DOM checks whether the script’s security origin
We identify a class of Web browser implementation has sufficient privileges to access the cookies.
vulnerabilities, cross-origin JavaScript capability leaks, • Object-Capabilities. The JavaScript engine en-
which occur when the browser leaks a JavaScript pointer forces the same-origin policy using an object-
from one security origin to another. We devise an algo- capability discipline that prevents one Web site
rithm for detecting these vulnerabilities by monitoring from obtaining JavaScript pointers to sensitive ob-
the “points-to” relation of the JavaScript heap. Our algo- jects that belong to a foreign security origin. With-
rithm finds a number of new vulnerabilities in the open- out JavaScript pointers to sensitive objects in for-
source WebKit browser engine used by Safari. We pro- eign security origins, malicious scripts are unable
pose an approach to mitigate this class of vulnerabilities to interfere with those objects.
by adding access control checks to browser JavaScript
engines. These access control checks are backwards- Most modern Web browsers, including Internet Ex-
compatible because they do not alter semantics of the plorer, Firefox, Safari, Google Chrome, and Opera, use
Web platform. Through an application of the inline this design. However, the design’s mismatch in en-
cache, we implement these checks with an overhead of forcement paradigms leads to vulnerabilities whenever
1–2% on industry-standard benchmarks. the browser leaks a JavaScript pointer from one secu-
rity origin to another. Once a malicious script gets a
1 Introduction JavaScript pointer to an honest JavaScript object, the at-
In this paper, we identify a class of Web browser im- tacker can leverage the object-capability security model
plementation vulnerabilities, which we refer to as cross- of the JavaScript engine to escalate its DOM privileges.
origin JavaScript capabilities leaks, and develop sys- With escalated DOM privileges, the attacker can com-
tematic techniques for detecting, exploiting, and defend- pletely compromise the honest security origin by inject-
ing against these vulnerabilities. An attacker who ex- ing a malicious script into the honest security origin.
ploits a cross-origin JavaScript capability leak can in- To study this class of vulnerabilities, we devise an al-
ject a malicious script into an honest Web site’s secu- gorithm for detecting individual cross-origin JavaScript
rity origin. These attacks are more severe than cross- capability leaks. Using this algorithm, we uncover new
site scripting (XSS) attacks because they affect all Web instances of cross-origin JavaScript capability leaks in
sites, including those free of XSS vulnerabilities. Once the WebKit browser engine used by Safari. We then il-
an attacker can run script in an arbitrary security origin, lustrate how an attack can abuse these leaked JavaScript
the attacker can, for example, issue transactions on the pointers by constructing proof-of-concept exploits. We
user’s bank account, regardless of any SSL encryption, propose defending against cross-origin JavaScript capa-
cross-site scripting filter, or Web application firewall. bility leaks by harmonizing the security models used by
We observe that these cross-origin JavaScript capa- the DOM and the JavaScript engine.
bility leaks are caused by an architectural flaw shared • Leak Detection. We design an algorithm for au-
by most modern Web browsers: the Document Object tomatically detecting cross-origin JavaScript ca-
Model (DOM) and the JavaScript engine enforce the pability leaks by monitoring the “points-to” rela-
same-origin policy using two different security models. tion among JavaScript objects in the heap. From
The DOM uses an access control model, whereas the this relation, we define the security origin of each
JavaScript engine uses object-capabilities. JavaScript object by tracing its “prototype chain.”
• Access Control. The DOM enforces the same- We then search the graph for edges that connect ob-
origin policy using a reference monitor that pre- jects in one security origin with objects in another
vents one Web site from accessing resources allo- security origin. These suspicious edges likely rep-
cated to another Web site. For example, whenever resent cross-origin JavaScript capability leaks.
• Vulnerabilities and Exploitation. We implement leaks as a class of vulnerabilities. Section 3 presents our
our leak detection algorithm and find two new high- algorithm for detecting cross-origin JavaScript capabil-
severity cross-origin JavaScript capability leaks in ity leaks. Section 4 details the individual vulnerabili-
WebKit. Although these vulnerabilities are imple- ties we uncover with our algorithm and outlines tech-
mentation errors in WebKit, the presence of the niques for exploiting these vulnerabilities. Section 5
bugs illustrates the fragility of the general architec- proposes defending against cross-origin JavaScript ca-
ture. (Other browsers have historically had similar pability leaks by adding access control checks to the
vulnerabilities [17, 18, 19].) We detail these vulner- JavaScript engine. Section 6 relates our work to the lit-
abilities and construct proof-of-concept exploits to erature. Section 7 concludes.
demonstrate how an attacker can leverage a leaked
JavaScript pointer to inject a malicious script into 2 JavaScript Capability Leaks
an honest security origin. In this section, we describe our interpretation of
• Defense. We propose that browser vendors proac- JavaScript pointers as object-capabilities and identify
tively defend against cross-origin JavaScript capa- cross-origin JavaScript capability leaks as a class of im-
bility leaks by implementing access control checks plementation vulnerabilities in browsers. We then sketch
throughout the JavaScript engine instead of reac- how these vulnerabilities are exploited and the conse-
tively plugging each leak. Adding access control quences of a successful exploit.
checks to the JavaScript engine addresses the root
cause of these vulnerabilities (the mismatch be- 2.1 Object-Capabilities
tween the security models used by the DOM and In modern Web browsers, the JavaScript engine en-
by the JavaScript engine) and provides defense-in- forces the browser’s same-origin policy using an object-
depth in the sense that both an object-capability capability discipline: a script can obtain pointers only
and an access control failure are required to create to JavaScript objects created by documents in its se-
an exploitable vulnerability. This defense is per- curity origin. A script can obtain JavaScript point-
fectly backwards-compatible because these access ers to JavaScript objects either by accessing prop-
checks do not alter the semantics of the Web plat- erties of JavaScript object to which the script al-
form. Our implementation of these access control ready has a JavaScript pointer or by conjuring cer-
checks in WebKit incurs an overhead of only 1–2% tain built-in objects such as the global object and
on industry-standard benchmarks. Object.prototype [14]. As in other object-
Contributions. We make the following contributions: capability systems, the ability to influence an object is
tied to the ability to designate the object. In browsers,
• We identify a class of Web browser implementa-
a script can manipulate a JavaScript object only if the
tion vulnerabilities: cross-origin JavaScript capa-
script has a pointer to the object. Without a pointer to
bility leaks. These vulnerabilities arise when the
an object in a foreign security origin, a malicious script
browser leaks a JavaScript pointer from one secu-
cannot influence honest JavaScript objects and cannot
rity origin to another security origin.
interfere with honest security origins.
• We introduce an algorithm for detecting cross-
One exception to this object-capability discipline is
origin JavaScript capability leaks by monitoring the
the JavaScript global object. According to the HTML 5
“points-to” relation of the JavaScript heap. Our al-
specification [10], the global object (also known as the
gorithm uses a graph-based definition of the secu-
window object) is visible to foreign security origins.
rity origin of a JavaScript object.
There are a number of APIs for obtaining pointers to
• We reveal cross-origin JavaScript capability leaks
global objects from foreign security origins. For exam-
and demonstrate techniques for exploiting these
ple, the contentWindow property of an <iframe>
vulnerabilities. These exploits rely on the mis-
element is the global object of the document contained
match between the DOM’s access control security
in the frame. Unlike most JavaScript objects, the global
model and the JavaScript engine’s object-capability
object is also a DOM object (called window) and is
security model.
equipped with a reference monitor that prevents scripts
• We propose that browsers defend against cross-
in foreign security origins from getting or setting arbi-
origin JavaScript capability leaks by implement-
trary properties of the object. This reference monitor
ing access control checks in the JavaScript engine.
does not forbid all accesses because some are desirable.
This defense is perfectly backwards-compatible
For example, the postMessage method [10] is ex-
and achieves a low overhead of 1–2%.
posed across origins to facilitate mashups [1]. These
Organization. This paper is organized as follows. exposed properties complicate the enforcement of the
Section 2 identifies cross-origin JavaScript capability same-origin policy, which can lead to vulnerabilities.
2.2 Capability Leaks Most Web sites contains innumerable laundries. We
Browsers occasionally contain bugs that leak JavaScript illustrate how an attacker can abuse a laundry by ex-
pointers from one security origin to another. These amining a representative laundry from the Prototype
vulnerabilities are easy for developers to introduce JavaScript library [22]: invoke. The invoke method
into browsers because the DOM contains pointers to is used to call a method, specified by name, on each
JavaScript objects in multiple security origins and de- object contained in an array. The attacker can use this
velopers can easily select the wrong pointer to disclose function to trick the honest page into calling a univer-
to a script. We identify these vulnerabilities as a class, sal DOM method, such as setTimeout. Suppose
which we call cross-origin JavaScript capabilities leaks, the attacker has a JavaScript pointer to an array named
because they follow a common pattern. Identifying this honest_array from an honest document that uses
class lets us analyze the concepts common to these vul- the Prototype library (for how this might occur, see Sec-
nerabilities in all browsers. tion 4.3) and that honest_window is the honest docu-
ment’s global object. The attacker can inject a malicious
The JavaScript language makes pointer leaks particu-
script into the honest security origin as follows:
larly devastating for security because JavaScript objects
inherit many of their properties from a prototype ob- honest_array.push(honest_window);
ject. When a script accesses a property of an object, the honest_array.invoke("setTimeout",
JavaScript engine uses the following algorithm to look "... malicious script ...", 0);
up the property:
The attacker first adds the honest_window object
• If the object has the property, return its value.
to the array and then asks the honest principal to call
• Otherwise, look up the property on the ob-
the setTimeout method of the honest_window.
ject’s prototype (designated by the current object’s
When the JavaScript engine attempts to call the
__proto__ property).
setTimeout DOM API, the DOM permits the call be-
These prototype objects, in turn, inherit many of cause the honest invoke method (acting as a confused
their properties from their prototypes in a chain that deputy) issued the call. The DOM then runs the mali-
leads back to the Object.prototype object, whose cious script supplied by the attacker in the honest secu-
__proto__ property is null. All the objects associ- rity origin.
ated with a given document have a prototype chain that
leads back to that document’s Object.prototype 2.4 Consequences
object. Given a JavaScript pointer to an object, a script Once the attacker is able to run a malicious script in the
can traverse this prototype chain by accessing the ob- honest security origin, all the browser’s cross-origin se-
ject’s __proto__ property. In particular, if an at- curity protections evaporate. The situation is as if every
tacker obtains a pointer to an honest object, the at- Web site contained a cross-site scripting vulnerability:
tacker can obtain a pointer to the honest document’s the attacker can steal the user’s authentication cookie or
Object.prototype object and can influence the be- password, learn confidential information present on the
havior of all the other JavaScript objects associated with Web site (e.g., read email messages on a webmail site),
the honest document. and issue transactions on behalf of the user (e.g., trans-
fer money out of the user’s bank account). Because these
2.3 Laundries cross-origin JavaScript capability leaks are browser vul-
Once the attacker has obtained a pointer to the nerabilities, there is little a Web site can do to defend
Object.prototype of an honest document, the at- itself against these attacks.
tacker has several avenues for compromising the hon-
est security origin. One approach is to abuse pow- 3 JavaScript Capability Leak Detection
erful functions reachable from Object.prototype, In this section, we describe the design and implementa-
which we refer to as laundries because they let the at- tion of an algorithm for detecting cross-origin JavaScript
tacker “wash away” his or her agency (analogous to capability leaks. Although the algorithm has a modest
laundering money). These functions often call one or overhead, our instrumented browser performs compara-
more DOM APIs, letting the attacker call these APIs in- bly to Safari 3.1, letting us analyze complex Web appli-
directly. Because these functions are defined by the hon- cations.
est document, the DOM’s reference monitor allows the
access [10]. However, if the attacker calls these func- 3.1 Design
tions with unexpected arguments, the functions might Assigning Security Origins. To detect cross-origin
become confused deputies [9] and inadvertently perform JavaScript capability leaks, we monitor the heap graph,
the attacker’s misdeeds. the “points-to” relation between JavaScript objects in the
JavaScript heap (see Section 3.2 for details about the 3.2 The “Points-To” Relation
“points-to” relation). We annotate each JavaScript ob- In our heap graph, we include two kinds of points in
ject in the heap graph with a security origin indicating the “points-to” relation: explicit pointers that are stored
which security origin “owns” the object. We compute as properties of JavaScript objects and implicit pointers
the security origin of each object directly from the “is- that are stored internally by the JavaScript engine.
prototype-of” relation in the heap graph using the fol-
lowing algorithm: Explicit Pointers. A script can alter the properties of
an object using the get, set, and delete operations.
1. Let obj be the JavaScript object in question.
2. If obj was created with a non-null prototype, as- • get looks up the value of an object property.
sign obj the same origin as its prototype. • set alters the value of an object property.
3. Otherwise, obj must be the object prototype for • delete removes a property from an object.
some document d. In that case, assign obj the se- To monitor the “points-to” relation between JavaScript
curity origin of d (i.e., the scheme, host, and port of objects in the JavaScript heap, we instrument the set
that d’s URL). operation. Whenever the JavaScript engine invokes the
set operation to store a JavaScript object in a prop-
This algorithm is unambiguous because, when created,
erty of another JavaScript object, we add an edge be-
each JavaScript object has a unique prototype, identi-
tween the two objects in our representation of the heap
fied by its __proto__ property. Although an object’s
graph. If the set operation overwrites an existing prop-
__proto__ can change over time, we fix the security
erty, we remove the obsolete edge from the graph. To
origin of an object at creation-time.
improve performance, we ignore JavaScript values be-
Minimal Capabilities. This algorithm for assigning cause JavaScript values cannot hold JavaScript pointers
security origins to objects is well-suited to analyzing and therefore are leaves in the heap graph. We remove
leaks of JavaScript pointers for two reasons. First, JavaScript objects from the heap graph when the objects
the algorithm is defined largely without reference to are deleted by the JavaScript garbage collector.
the DOM, letting us catch bugs in the DOM. Second, Implicit Pointers. The above instrumentation does
the algorithm reflects an object-capability perspective not give us a complete picture of the “points-to” relation
in that each JavaScript object is a strictly more pow- in the JavaScript heap because the operational seman-
erful object-capability than the Object.prototype tics of the JavaScript language [14] rely on a number of
object that terminates its prototype chain. An attacker implicit JavaScript pointers, which are not represented
with a JavaScript pointer to the object can follow the explicitly as properties of a JavaScript object. For exam-
object’s prototype chain by repeatedly dereferencing the ple, consider the following script:
object’s __proto__ property and eventually obtain a
JavaScript pointer to the Object.prototype object. var x = ...
In these terms, we view the Object.prototype ob- function f() {
ject as the “minimal object-capability” of an origin. var y = ...
function g() {
Suspicious Edges. After annotating the heap graph var z = ...
with the security origin of each object, we detect a function h() { ... }
leaked JavaScript pointer as an edge from an object in }
one security origin to an object in another security ori- }
gin. These suspicious edges represent failures of the
JavaScript engine to segregate JavaScript objects into Function h can obtain the JavaScript pointers stored in
distinct security origins. Not all of these suspicious variables x, y, and z even though there are no JavaScript
edges are actually security vulnerabilities because the pointers between h and these objects. The function h
HTML specification requires some JavaScript objects, can obtain these JavaScript pointers because the algo-
such as the global object, be visible to foreign security rithm for resolving variable names makes use of an im-
origins. To prevent exploits, browsers equip these ob- plicit “next” pointer that connects h’s scope object to
jects with a reference monitor that prevents foreign se- the scope objects of g, f, and the global scope. Instead
curity origins from getting or setting arbitrary properties of being stored as properties of JavaScript objects, these
of the object. In addition to the global object, a hand- implicit pointers are stored as member variables of na-
ful of other JavaScript objects required to be visible to tive objects in the JavaScript engine. To improve the
foreign security origins. These objects are annotated in completeness of our heap graph, we include these im-
WebKit’s Interface Description Language (IDL) with the plicit JavaScript pointers explicitly as edges between the
attribute DoNotCheckDomainSecurity. JavaScript scope objects.
Global Object - 1c700040

@SCOPECHAIN GLOBAL window window Math Math document local - document document decodeURI encodeURIComponent isNaN NaN NaN undefined undefined Infinity Infinity

__proto__ Window Shell - 1c700000 object - 1c700f60 object - 1c701340 decodeURIComponent escape kjsprint parseFloat 1c710090 a 1c7100a0

__proto__ __proto__ RangeError EvalError URIError TypeError ReferenceError SyntaxError object - 1c701140 dumpHeap object - 1c701200 eval object - 1c701040 parseInt

Date Number Boolean Array object - 1c700020 object - 1c701320 String Error RegExp encodeURI isFinite object - 1c701280 unescape

__proto__ object - 1c701180 object - 1c7010c0 object - 1c701000

object - 1c701300 object - 1c700e20 object - 1c700de0 object - 1c700f20 object - 1c700ee0 object - 1c700e60 object - 1c700ea0

Object __proto__ __proto__ prototype constructor constructor prototype prototype constructor prototype constructor constructor prototype prototype constructor object - 1c701240 object - 1c700f80 object - 1c700fc0

object - 1c700c60 object - 1c700c20 object - 1c700be0 object - 1c700b20 __proto__ object - 1c7012e0 object - 1c700b60 object - 1c7008c0 object - 1c700da0 object - 1c700860 object - 1c700a40 object - 1c7009e0 object - 1c700920 object - 1c700980 object - 1c700d60

Function now parse UTC constructor constructor prototype prototype constructor prototype prototype constructor __proto__ prototype constructor fromCharCode __proto__ constructor prototype __proto__ __proto__ __proto__ __proto__ __proto__ prototype constructor __proto__ object - 1c7011c0 __proto__ object - 1c701080 __proto__ object - 1c701100

number prototype - 1c7004e0 date prototype - 1c700680 boolean prototype - 1c700440 array prototype - 1c700400 object - 1c7012c0 string prototype - 1c700420 error prototype - 1c7007c0 regExp prototype - 1c7006a0 __proto__ __proto__ __proto__ __proto__

object - 1c700d20 object - 1c700ca0 object - 1c700ce0 valueOf toExponential toFixed toLocaleString toPrecision toString __proto__ __proto__ toString valueOf __proto__ __proto__ __proto__ __proto__ __proto__ object - 1c700ba0 __proto__ toString __proto__ __proto__ __proto__ __proto__ __proto__ __proto__ exec test toString compile __proto__ __proto__ __proto__

__proto__ object - 1c700580 object - 1c700500 __proto__ __proto__ __proto__ object prototype - 1c7000a0 __proto__ __proto__ object - 1c700700 object - 1c700740 object - 1c700780 object - 1c7006c0 __proto__ __proto__ __proto__ __proto__

__proto__ __proto__ __proto__ object - 1c700600 object - 1c7005c0 object - 1c700540 object - 1c700640 object - 1c700460 object - 1c7004a0 toLocaleString toString valueOf prototype constructor __defineGetter__ __defineSetter__ __lookupGetter__ __lookupSetter__ hasOwnProperty isPrototypeOf propertyIsEnumerable __proto__ object - 1c700820

__proto__ __proto__ __proto__ __proto__ __proto__ __proto__ __proto__ __proto__ object - 1c700100 object - 1c7000c0 object - 1c700140 object - 1c700aa0 object - 1c700240 object - 1c700280 object - 1c7002c0 object - 1c700300 object - 1c700180 object - 1c700200 object - 1c7001c0 __proto__ __proto__ __proto__ __proto__ __proto__

__proto__ __proto__ __proto__ __proto__ __proto__ __proto__ __proto__ __proto__ __proto__ __proto__ __proto__

function prototype - 1c700060

__proto__ prototype constructor apply __proto__ call __proto__ toString __proto__

object - 1c700ae0 object - 1c700380 object - 1c7003c0 object - 1c700340

Figure 1: The heap graph of an empty document.

3.3 Implementation
Attacker Global Object@0x1a9e1420 Victim Global Object@0x1a9e2940
We implemented our leak detection algorithm in a 1,393 document document Object

line patch to WebKit’s Nitro JavaScript engine. Our al- object@0x1a9e3c20

gorithm can construct heap graphs of complex Web ap- __proto__ object@0x1a9e3380

plications, such as Gmail or the Apple Store. For exam- object@0x1a9e3c00

ple, one heap graph of a Gmail inbox contains 54,140 __proto__

nodes and 130,995 edges. These graphs are often vi- object@0x1a9e3be0

sually complex and difficult to interpret manually. Fig- __proto__ prototype

ure 1 illustrates the nature of these graphs by depicting object@0x1a9e3bc0

__proto__
the heap graph of an empty document. Although our in-
object@0x1a9e3ba0
strumentation slows down the browser, the instrumented __proto__
browser is still faster than Safari 3.1, demonstrating that Object Prototype@0x1a9e2980

our algorithm scales to complex Web applications.

4 Vulnerabilities and Exploitation Figure 2: Selected nodes from a heap graph showing a
In this section, we use our leak detector to detect cross- cross-origin JavaScript capability leak of the document
origin JavaScript capability leaks in WebKit. After object, object@0x1a9e3c20, after a navigation.
discovering two new vulnerabilities, we illuminate the
vulnerabilities by constructing proof-of-concept exploits
using three different techniques. In addition, we apply The layoutTestController contains a number of
our understanding of JavaScript pointers to breaking the objects that are shared between all security origins. Our
Subspace [11] mashup design. instrumentation flags JavaScript pointers to these objects
as suspicious, and, in fact, these pointers are exploitable
4.1 Test Suite in the test configuration of the browser. However, these
To find example cross-origin JavaScript capability leaks, pointers are not present in the release configuration of
we run our instrumented browser through a test suite. the browser because the layoutTestController
Ideally, to reduce the number of false negatives, we itself is present only during testing. We white listed
would use a test suite with high coverage. Because our these objects as visible to multiple security origins.
goal is to find example vulnerabilities, we use the We-
bKit project’s regression test suite. This test suite exer-
cises a variety of browser security features and tests for 4.2 Navigation and Document
the non-existence of past security vulnerabilities. Using
this test suite, our instrumentation found two new high- Vulnerability. When the browser navigates a window
severity cross-origin JavaScript capability leaks. Instead from one Web page to another, the browser replaces the
of attempting to discover and patch all these leaks, we document originally displayed in the window with a new
recommend a more comprehensive defense, detailed in document retrieved from the network. Our instrumen-
Section 5. tation found that WebKit leaks a JavaScript pointer to
WebKit’s regression test suite uses a JavaScript ob- the new document object every time a window navi-
ject named layoutTestController to facilitate its gates because the DOM updates the document prop-
tests. For example, each tests notifies the testing harness erty of the old global object to point to the new doc-
that the test is complete by calling the notifyDone ument occupying the frame. This leak is visible in
method of the layoutTestController. We mod- the heap graph (see Figure 2) as a dashed line from
ified this notifyDone method to store the JavaScript Attacker Global Object@0x1a9e1420 to the
heap graph in the file system after each test completes. honest document object, object@0x1a9e3c20.
Exploit. Crafting an exploit for this vulnerability is
Attacker Global Object@0x1c1d0040 Victim Global Object@0x1c1d13e0
subtle. An attacker cannot simply hold a JavaScript
location location Object
pointer to the old global object and access its object@0x1c1d2720 object@0x1c1d2740
document property because all JavaScript pointers to
__proto__ __proto__ object@0x1c1d1e20
global objects are updated to the new global object when
object@0x1c1d2700 prototype
a frame is navigated navigation [10]. However, the prop- __proto__
erties of the old global object are still visible to func- Object Prototype@0x1c1d1420

tions defined by the old document via the scope chain


as global variables. In particular, an attacker can exploit
this vulnerability as follows: Figure 3: Selected nodes from a heap graph showing
1. Create an <iframe> to http://attacker. a cross-origin JavaScript capability leak of the location
com/iframe.html, which defines the following prototype, object@0x1c1d2700, to the attacker af-
function in a malicious document: ter the victim attempts to frame bust.
function exploit() {
var elmt = document. This line of JavaScript changes the location of the top-
createElement("script"); most frame, navigating that frame to a trusted Web site.
elmt.src = The browser permits cross-origin access to a frame’s
"http://attacker.com/atk.js"; location object to allow navigation [1]. If this script
document.body.appendChild(elmt); is the first script to access the location object of the
} top frame, then WebKit will mistakenly connect the
top frame’s newly constructed location object to the
Notice that the exploit function refers to
Object.prototype of the child frame (instead of
the document as a global variable, document,
to the Object.prototype of the top frame) because
and not as a property of the global object,
the child frame is currently in scope lexically.
window.document.
2. In the parent frame, store a pointer to the exploit Exploit. To exploit this cross-origin JavaScript capa-
function by running the following JavaScript: bility leak, the attacker proceeds in two phases: (1)
window.f = frames[0].exploit; the attacker obtains a JavaScript pointer to the hon-
est Object.prototype, and (2) the attacker abuses
3. Navigate the frame to http://example.com/. the honest Object.prototype to inject a malicious
4. Call the function: window.f(). script into the honest security origin. To obtain a
After the attacker navigates the child frame to http:// JavaScript pointer to the honest Object.prototype,
example.com/, the DOM changes the document the attacker create an <iframe> to an honest document
variable in the function exploit to point to the honest that frame busts and runs the following script in response
document object instead of the attacker’s document ob- to the beforeunload event:
ject. The exploit function can inject arbitrary script
into the honest document using a number of standard var location_prototype =
DOM APIs. Once the attacker has injected script into window.location.__proto__;
the honest document, the attacker can impersonate the var honest_object_prototype =
honest security origin to the browser. location_prototype.__proto__;

4.3 Lazy Location and History Because the beforeunload event handler runs af-
ter the child frame has attempted to frame bust, the at-
Vulnerability. For performance, WebKit instantiates tacker’s location object has been instantiated by the hon-
the window.location and window.history ob- est document and is mistakenly attached to the honest
jects lazily the first time they are accessed. When instan- Object.prototype (see Figure 3). The attacker ob-
tiating these objects, the browser constructs their proto- tains a pointer to the honest Object.prototype by
type chains. In some situations, WebKit constructs an traversing this prototype chain.
incorrect prototype chain that connects these objects to Once the attacker has obtained a JavaScript pointer
the Object.prototype of a foreign security origin, to the honest Object.prototype, there are a num-
creating a vulnerability if, for example, a document uses ber of techniques the attacker can use to compromise the
the following script to “frame bust” [12] in order to avoid honest security origin completely. We describe two rep-
clickjacking [7] attacks: resentative examples:
top.location.href = 1. Many Web sites use JavaScript libraries to smooth
"http://example.com/"; over incompatibilities between browsers and reuse
common code. One of the more popular JavaScript The JavaScript engine will call the attacker’s setter
libraries is the Prototype library [22], which is used function instead of storing honest_dom_node
by CNN, Apple, Yelp, Digg, Twitter, and many oth- into the foo property of obj, causing the
ers. If the honest page uses the Prototype library, variable x to contain a JavaScript pointer to
the attacker can inject arbitrary script into the hon- honest_dom_node. Once the attacker’s func-
est page by abusing the powerful invoke function tion is called with a pointer to the honest DOM
defined by the Prototype library. For example, the node, the attacker can inject malicious script into
attacker can use the follow script: the honest document using the innerHTML API.
var honest_function = 4.4 Capability Leaks in Subspace
honest_object_prototype.
__defineGetter__; The Subspace mashup design [11] lets a trusted integra-
var honest_array = tor communicate with an untrusted gadget by passing a
honest_function. JavaScript pointer from the integrator to the gadget:
argumentNames(); A Subspace JavaScript object is created in
honest_array.push(frames[0]); the top frame and passed to the mediator
honest_array.invoke("setTimeout", frame... The mediator frame still has access to
"... malicious script ..."); the Subspace object it obtained from the top
In the Prototype library, arrays contain a method frame, and passes this object to the untrusted
named invoke that calls the method named frame. [11]
by its first argument on each element of its ar-
ray, passing the remaining arguments to the in- Unfortunately, the Subspace design relies on leaking
voked method. To abuse this method, the at- a JavaScript pointer from a trusted security origin to
tacker first obtains a pointer to an honest ar- an untrusted security origin, creating a cross-origin
ray object by calling the argumentNames JavaScript capability leak. By leaking the communica-
method of an honest function reachable from tion object, Subspace also leaks a pointer to the trusted
the honest_object_prototype object. The Object.prototype via the prototype chain of the
attacker then pushes the global object of the communication object.
child frame onto the array and calls the honest To verify this attack, we examined CrossSafe [25], a
document’s setTimeout method via invoke. public implementation of Subspace. We ran a Cross-
The honest global object has a reference mon- Safe tutorial in our instrumented browser and examined
itor that prevents the attacker from accessing the resulting heap graph. Our detector found a cross-
setTimeout directly, but the reference monitor origin JavaScript capability leak: the channel object
allows invoke to access setTimeout because is leaked from the integrator to the gadget. By repeat-
invoke is defined by the honest document. edly dereferencing the __proto__ property, the un-
2. Even if the honest Web page does not use a complex trusted gadget can obtain a JavaScript pointer to the
JavaScript library, the attacker can often find a snip- trusted Object.prototype object. The untrusted
pet of honest script to trick. For example, suppose gadget can then inject a malicious script into the trusted
the attacker installs a “setter” function for the foo integrator using one of the techniques described in Sec-
property of the honest Object.prototype as tion 4.3.
follows:
5 Defense
function evil(x) {
In this section, we propose a principled defense for
x.innerHTML =
cross-origin JavaScript capability leaks. Our defense ad-
’<img src="about:blank"’ +
dresses the root cause of these vulnerabilities and incurs
’ onerror="... script ...">’;
a minor performance overhead.
});
honest_object_prototype. 5.1 Approach
__defineSetter__(’foo’, evil);
Currently, browser vendors defend against cross-origin
Now, if the honest script stores a DOM node in a JavaScript capability leaks by patching each individual
property of an object as follows: leak after the leak is discovered. We recommend an-
var obj = new Object(); other approach for defending against these vulnerabili-
obj.foo = honest_dom_node; ties: add access control checks throughout the JavaScript
engine. We recommend this principled approach over
ad-hoc leak plugging for two reasons:
• This approach addresses the core design issue un- Although we recommend that browsers adopt the access
derlying cross-origin JavaScript capability leak vul- control paradigm for Web content, other projects, such
nerabilities: the mismatch between the DOM’s ac- as Caja [16] and ADsafe [3], take the opposite approach
cess control security model and the JavaScript en- and elect to enforce an object-capability discipline on
gine’s object-capability security model. the DOM. These projects succeed with this approach be-
• This approach provides a second layer of defense: cause the preceding considerations do not apply: these
if the browser is leak-free, all the access con- projects target new code (freeing themselves from back-
trol checks will be redundant and pass, but if the wards compatibility constraints) that is written in a sub-
browser contains a leak, the access control checks set of JavaScript (freeing themselves from problematic
prevent the attacker from exploiting the leak. language features). For further discussion, see Section 6.
In a correctly implemented browser, Web content will be 5.2 Design
unable to determine whether the browser implements the
access control checks we recommend. The additional We propose adding access control checks to the
access control checks enhance the mechanism used to JavaScript engine by inserting a reference monitor into
enforce the same-origin policy but do not alter the policy each JavaScript object. The reference monitor interposes
itself, resulting in zero compatibility impact. on each get and set operation (described in Section 3)
and performs the following access control check:
Another plausible approach to mitigating these vul-
nerabilities is to adopt an object-capability discipline 1. Let the active origin be the origin of the document
throughout the DOM. This approach mitigates the sever- that defined the currently executing script.
ity of cross-origin JavaScript capability leaks by limiting 2. Let the target origin be the origin that “owns” the
the damage an attacker can wreak with the leaked capa- JavaScript object being accessed, as computed by
bility. For example, if the browser leaks an honest his- the algorithm in Section 3.1.
tory object to the attacker, the attacker would be able to 3. Allow the access if the browser considers the active
manipulate the history object, but would not be able to origin and the target origin to be the same origin
alter the document object. Conceptually, either adding (i.e., if their scheme, hosts, and ports match).
access control checks to the JavaScript engine or adopt- 4. Otherwise, deny access.
ing an object-capability discipline throughout the DOM If the access is denied, the JavaScript engine returns the
resolves the underlying architectural security issue, but value undefined for get operations and simply ig-
we recommend adopting the access control paradigm for nores set operations. In addition to adding these ac-
two main reasons: cess control checks, we record the security origin of each
• Adopting an object-capability discipline through- JavaScript object when the object is created. Our imple-
out the DOM requires “taming” [15] the DOM API. mentation does not currently insert access control checks
The current DOM API imbues every DOM node for delete operations, but these checks could be added
with the full authority of the node’s security origin at a minor performance cost. Some JavaScript objects,
because the API exposes a number of “universal” such as the global object, are visible across origins. For
methods, such as innerHTML that can be used these objects, our reference monitor defers to the refer-
to run arbitrary script. Other researchers have de- ence monitors that already protect these objects.
signed capability-based DOM APIs [4], but taming
5.3 Inline Cache
the DOM API requires a number of non-backwards
compatible changes. A browser that makes these The main disadvantage of performing an access control
changes will be unpopular because the browser will check for every JavaScript property access is the run-
be unable to display a large fraction of Web sites. time overhead of performing the checks. Sophisticated
• The JavaScript language itself has a number of fea- Web applications access JavaScript properties an enor-
tures that make enforcing an object-capability dis- mous number of times per second, and browser vendors
cipline challenging. For example, every JavaScript have heavily optimized these code paths. However, we
object has a prototype chain that eventually leads observe that the proposed access checks are largely re-
back to the Object.prototype, making it dif- dundant and amenable to optimization because scripts
ficult to create a weaker object-capability than virtually always access objects from the same origin.
the Object.prototype. Unfortunately, the Cutting-edge JavaScript engines, including Sa-
Object.prototype itself represents a power- fari 4’s Nitro JavaScript Engine, Google Chrome’s
ful object-capability with the ability to interfere V8 JavaScript engine, Firefox 3.5’s TraceMonkey
with the properties of every other object from the JavaScript engine, and Opera 11’s Carakan JavaScript
same document (e.g., the exploit in Section 4.3.) engine, optimize JavaScript property accesses using an
3.0%
inline cache [24]. (Of the major browser vendors, only
Microsoft has yet to announce plans to implement this 2.5%
optimization.) These JavaScript engines group together
JavaScript objects with the same “structure” (i.e., whose 2.0%

Slowdown
properties are laid out the same order in memory). When 1.5%
a script accesses a property of an object, the engine
caches the object’s group and the memory offset of the 1.0%

property inline in the compiled script. The next time


0.5%
that compiled script accesses a property of an object, the
inline cache checks whether the current object has the 0.0%
Dromaeo SunSpider V8 Suite
same structure as the original object. If the two objects
Benchmark
have the same structure, a cache hit, the engine uses the
memory offset stored in the cache to access the prop-
Figure 4: Overhead for access control checks as measure
erty. Otherwise, a cache miss, the engine accesses the
by industry-standard JavaScript benchmarks (average of
property using the normal algorithm.
10 runs, 95% confidence).
Notice that two objects share the same structure only
if their prototypes share the same structure. Addi-
tionally, the Nitro JavaScript engine initializes each 12%

Object.prototype with a unique structure identi-


10%
fier, preventing two object from different security ori-
gins (as defined by our prototype-based algorithm) from 8%

being be grouped together as sharing the same structure.


Slowdown

6%
(Other JavaScript engines, such as V8, do contain struc-
ture groups that span security origins, but this design 4%

is not necessary for performance.) Whenever the inline 2%


cache has a hit, we observe the following:
0%
• The current object is from the same security origin Read Write Read Write

as the original object that created the cache entry -2%


Inline Cache No Inline Cache
because the two objects share the same structure.
• The script has the same security origin as when the Figure 5: Overhead for reading and writing properties of
cache entry was created because the cache is inlined JavaScript objects both with and without an inline cache
into the script and the security origin of the script is as measured by microbenchmarks (average of 10 runs,
fixed at compile time. 95% confidence).
Taken together, these properties imply that the current
access control check will return the same result as the
original check because both of the origins involved in the by computing the currently active origin from the lexical
check are unchanged. Therefore, we need not perform scope, which can be reduced with further engineering.
an access control check during a cache hit, greatly reduc-
ing the performance overhead of adding access control
Overall Performance. Our implementation incurs a
checks to the JavaScript engine.
small overhead on industry-standard JavaScript bench-
marks (see Figure 4). On Mozilla’s Dromaeo bench-
5.4 Evaluation
mark, we observed a 0.57% slowdown for access con-
To evaluate performance overhead of our defense, trol versus an unmodified browser (average of 10 runs,
we added access control checks to Safari 4’s Nitro ±0.58%, 95% confidence). On Apple’s SunSpider
JavaScript engine in a 394 line patch. We verified that benchmark, we observed a 1.16% slowdown (average
our access control checks actually defeat the proof-of- of 10 runs, ±0.45%, 95% confidence). On Google’s V8
concept exploits we construct in Section 4. To speed up benchmark, we observed a 1.94% slowdown (average of
the access control checks, we represented each security 10 runs, ±0.61, 95% confidence). We hypothesize that
origin by a pointer, letting us allow the vast majority of the variation in slowdown between these benchmarks is
accesses using a simple pointer comparison. In some due to the differing balance between arithmetic opera-
rare cases, including to deny access, our implementation tions and property accesses in the different benchmarks.
performs a more involved access check. The majority of Note that these overhead numbers are tiny in comparison
performance overhead in our implementation is caused with the 338% speedup of Safari 4 over Safari 3.1 [24].
Benefits of Inline Cache. We attribute much of the browsers. We face the opposite constraints: we cannot
performance of our access checks to the inline cache, alter legacy content but we can change the browser. For
which lets our implementation skip redundant access these reasons, we recommend the opposite design point.
control checks for repeated property accesses. To evalu-
ate the performance benefits of the inline cache, we cre- Opus Palladianum. The Opus Palladianum (OP) Web
ated two microbenchmarks, “read” and “write.” In the browser [6] isolates security origins into separate sand-
read benchmark, we repeatedly performed a get opera- boxed components. This component-based browser
tion on one property of a JavaScript object in a loop. In architecture makes it easier to reason about cross-
the write benchmark, we repeatedly performed a set origin JavaScript capability leaks because these capa-
operation on one property of a JavaScript object in a bility leaks must occur between browser components
loop. We then measured the slowdown incurred by the instead of within a single JavaScript heap. We can
access control checks both with the inline cache enabled view the sandbox as a coarse-grained reference mon-
and with the inline cache disabled (see Figure 5). With itor. Unfortunately, the sandbox alone is too coarse-
the inline cache enabled, we observed a −0.08% slow- grained to implement standard browser features such
down (average of 50 runs, ±0.22%, 95% confidence) as postMessage. To support these features, the
on the read benchmark and a 0.55% slowdown (aver- OP browser must allow inter-component references, but
age of 50 runs, ±0.74%, 95% confidence) on the write without a public implementation, we are unable to eval-
benchmark. By contrast, with the inline cache disabled, uate whether these inter-component references give rise
we observed a 9.41% slowdown (average of 50 runs, to cross-origin JavaScript capability leaks.
±1.11%, 95% confidence) on the read benchmark and
a 10.25% slowdown (average of 50 runs, ±1.00%, 95% Script Accenting. Script accenting [2] is a technique
confidence) on the write benchmark. for adding defense-in-depth to the browser’s enforce-
From these observations we conclude that browser ment of the same-origin policy. To mitigate mistaken
vendors can implement access control checks for ev- script execution, the browser encrypts script source code
ery get and set operation with a performance over- with a key specific to the security origin of the script.
head of less than 1–2%. To reap these security bene- Whenever the browser attempts to run a script in a secu-
fits with minimal overhead, the JavaScript engine should rity origin, the browser first decrypts the script with the
employ an inline cache to optimize repeated property security origin’s key. If decryption fails, likely because
accesses, and the inline cache should group structurally of a vulnerability, the browser refuses to execute the
similar JavaScript objects only if those objects are from script. Script accenting similarly encrypts the names of
the same security origin. JavaScript properties ostensibly preventing a script from
manipulating properties of objects from another origin.
6 Related Work Unfortunately, this approach is not expressive enough to
represent the same-origin policy (e.g., this design does
The operating system literature has a rich history
not support document.domain). In addition, script
of work on access control and object-capability sys-
accenting requires XOR encryption to achieve sufficient
tems [13, 21, 23, 8]. In this section, we focus on com-
performance, but XOR encryption lacks the integrity
paring our work to related work on access control and
protection required to make the scheme secure.
object-capability systems in Web browsers.
FBJS, Caja, and ADsafe. Facebook, Yahoo!, and Cross-Origin Wrappers. Firefox 3 uses cross-origin
Google have developed JavaScript subsets, called wrappers [20] to mitigate security vulnerabilities caused
FBJS [5], ADsafe [3], and Caja [16], respectively, by cross-origin JavaScript capability leaks. Instead of
that enforce an object-capability discipline by remov- exposing JavaScript objects directly to foreign security
ing problematic JavaScript features (such as prototypes) origins, Firefox exposes a “wrapper” object that me-
and DOM APIs (such as innerHTML). These projects diates access to the wrapped object with a reference
take the opposite approach from this paper: they extend monitor. Implementing cross-origin wrappers correctly
the JavaScript engine’s object-capability security model is significantly more complex than implementing ac-
to the DOM instead of extending the DOM’s access cess control correctly because the cross-origin wrappers
control security model to the JavaScript engine. These must wrap and unwrap objects at the appropriate times
projects choose this alternative design point for two rea- in addition to implementing all the same access con-
sons: (1) the projects target new social networking gad- trol checks. Our access control design can be viewed
gets and advertisements that are free from compatibil- as a high-performance technique for reducing this com-
ity constraints and (2) these projects are unable to al- plexity (and the attendant bugs) by adding the reference
ter legacy browsers because they must work in existing monitor to every object.
7 Conclusions [4] Douglas Crockford. ADsafe DOM API.
In this paper, we identify a class of vulnerabilities, cross- [5] Facebook. Facebook Markup Language (FBML).
origin JavaScript capability leaks, that arise when the [6] Chris Grier, Shuo Tang, and Samuel T. King. Se-
browser leaks a JavaScript pointer from one security cure web browsing with the OP web browser. In
origin to another. These vulnerabilities undermine the IEEE Symposium on Security and Privacy, 2008.
same-origin policy and prevent Web sites from secur-
[7] Jeremiah Grossman. Clickjacking: Web pages can
ing themselves against Web attackers. We present an
see and hear you, October 2008.
algorithm for detecting cross-origin JavaScript capabil-
ity leaks by monitoring the “points-to” relation between [8] Norm Hardy. The keykos architecture. Operating
JavaScript objects in the JavaScript heap. We imple- Systems Review, 1985.
ment our detection algorithm in WebKit and use it to [9] Norm Hardy. The confused deputy: (or why capa-
find new cross-origin JavaScript capability leaks by run- bilities might have been invented). SIGOPS Oper.
ning the WebKit regression test suite in our instrumented Syst. Rev., 22(4):36–38, 1988.
browser. Having discovered these leaked pointers, we [10] Ian Hickson et al. HTML 5 Working Draft.
turn our attention to exploiting these vulnerabilities. We
construct exploits to illustrate the vulnerabilities and find [11] Collin Jackson and Helen J. Wang. Sub-
that the root cause of the these vulnerabilities is the space: Secure cross-domain communication for
mismatch in security models between the DOM, which web mashups. In Proceedings of the 16th Interna-
uses access control, and the JavaScript engine, which tional World Wide Web Conference. (WWW), 2007.
uses object-capabilities. Instead of patching each leak, [12] Peter-Paul Koch. Frame busting, 2004.
we recommend that browser vendors repair the under- http://www.quirksmode.org/js/
lying architectural issue by implementing access con- framebust.html.
trol checks throughout the JavaScript engine. Although [13] Butler Lampson. Protection and access control in
a straight-forward implementation that performed these operating systems. Operating Systems: Infotech
checks for every access would have a prohibitive over- State of the Art Report, 14:309–326, 1972.
head, we demonstrate that a JavaScript engine optimiza- [14] Sergio Maffeis, John C. Mitchell, and Ankur Taly.
tion, the inline cache, reduces this overhead to 1–2%. An operational semantics for JavaScript. In Pro-
Acknowledgements. We thank Chris Karloff, Oliver ceedings of the 6th Asian Programming Language
Hunt, Collin Jackson, John C. Mitchell, Rachel Parke- Symposium (APLAS), December 2008.
Houben, and Sam Weinig for their helpful suggestions [15] Mark Miller. A theory of taming.
and feedback. This material is based upon work par-
[16] Mark Miller. Caja, 2007.
tially supported by the National Science Foundation un-
der Grants No. 0311808, No. 0448452, No. 0627511, [17] Mitre. CVE-2008-4058.
and CCF-0424422, and by the Air Force Office of Scien- [18] Mitre. CVE-2008-4059.
tific Research under MURI Grant No. 22178970-4170. [19] Mitre. CVE-2008-5512.
Any opinions, findings, and conclusions or recommen-
dations expressed in this material are those of the au- [20] Mozilla. XPConnect wrappers.
thor(s) and do not necessarily reflect the views of the http://developer.mozilla.org/en/
Air Force Office of Scientific Research, or the National docs/XPConnect_wrappers.
Science Foundation. [21] Sape J. Mullender, Guido van Rossum, Andrew
Tannenbaum, Robbert van Renesse, and Hans van
References Staveren. Amoeba: A distributed operating system
[1] Adam Barth, Collin Jackson, and John C. Mitchell. for the 1990s. Computer, 23(5):44–53, 1990.
Securing frame communication in browsers. In [22] Prototype JavaScript framework.
Proceedings of the 17th USENIX Security Sympo- http://www.prototypejs.org/.
sium, 2008. [23] Jonathan S. Shapiro, Jonathan M. Smith, and
[2] Shuo Chen, David Ross, and Yi-Min Wang. An David J. Farber. Eros: a fast capability system. In
analysis of browser domain-isolation bugs and a 17th ACM Symposium on Operating System Prin-
light-weight transparent defense mechanism. In ciples, New York, NY, USA, 1999. ACM.
CCS ’07: Proceedings of the 14th ACM conference [24] Maciej Stachowiak. Introducing SquirrelFish Ex-
on Computer and communications security, pages treme, 2008.
2–11, New York, NY, USA, 2007. ACM.
[25] Kris Zyp. CrossSafe.
[3] Douglas Crockford. ADsafe.

You might also like