How to safely run user-supplied Javascript code inside the browser?

After much consideration and with the help of other posters in this thread (thank you so much for your help!), I found a first bunch of answers to my questions. I am re-writing my answer here though, because it summarizes the concepts and also gives you some actual code to experiment with.

Generally, there are two solutions to this problem: We can either use iframe or Worker to run code in an isolated environment, thus making it impossible to read or write the current page’s information (which is my first major security concern).

Caja + Closure

There are more complete sandbox solutions such as Google Caja, which (by default) also runs its code in an iframe. Caja does not only sandbox JS, but also HTML and CSS. However, it does not seem very actively maintained anymore.

Update: Caja has been deprecated since the original posting. It has been replaced with the Closure Toolkit, specifically Closure Library and Closure Templates.

WebWorker + Blacklisting

As proposed by Juan Garcia, I am going with the web worker API, but that is not the complete story. Even though, the worker cannot directly access anything from the hosting page, there are still quite a few security risks. This site lists all built-ins available in a Worker’s context.

This JSFiddle demonstrates a way to run a string of code outside the window‘s context without having to go through the server, which is still unsafe, as pointed out in the comments.

I have extended on that and employed a black-list based approach to disable all outside communication by taking away all of the following:

  • Worker
  • WebSocket
  • XMLHttpRequest
  • importScripts

Webworker + Whitelisting

The actually safest approach however, is a white-list approach, (mentioned here), as it will stay safe into the future (given that the semantics of any whitelisted globals will never change in such a way that they allow more access in any future release; which is a somewhat reasonable assumption).

I ended up implementing the whitelist approach in my in-browser WumpusGame that allows you to write your own AI script while playing the game, a few years back. Source code here. You can see that the Whitelist is maintained in GuestScriptContext while the workers are managed by the HostScriptContext.

The GameScriptContext shows how you can use it.

It has several features, including guest<->host communication, guest can execute non-privileged actions (and if it has a security token even privileged actions) on the host, and a lot more.

NOTE: It does not play well with some extensions, as they will prevent overriding globals (when I try to run it, it complains about TEMPORARY being one of them). The fix would be to either whitelist those, or figure out how to make it play nice with modern browser security features, or just security-focused extensions, such as AdBlock etc.

The game is theoretically playable here, but because of reasons above it does not seem to work in Chrome (and I haven’t tried other browsers yet).

Some more references:

  • The W3Schools web worker tutorial.
  • This thread and this html5rocks tutorial on how to run a Worker without separate files.

Leave a Comment