Search code examples
javascriptsecuritysandboxcode-injectionwith-statement

Is it safe to declare critical literals in "with (...) {...}" to sandbox code run within it?


I avoid using eval() or Functions created from a string. But when I need to run some subset of Javascript that can be entered by a user I'm tempted to use it just because it will save me much work writing a lexer/parser and interpreter.

Say I'd like to run this code:

a.toLowerCase() === 'xyz' || b == 1 || /pqr/.test(c)

the native approach would be to pass it into eval() like this:

with({a: ..., b: ..., c: ...}) {
    ret = eval(code);
}

I cannot be sure that code always contains uncritical code like the above. This opens the possibilities to run malicious code.

I thought of passing an object re-defining critical Browser objects to with besides the actual data like:

var obj = {
   // list incomplete ;)
   console: true, XMLHttpRequest: true, document: true, window: true, addEventListener: true, removeEventListener: true, parent: true, top: true, history: true, ..., 

   // actual data
   a: ..., b: ..., c: ...
};

with (obj) {
   ...
}

When running code within with access to the objects/methods is not possibe.

I know that it's still possible to indirectly access those methods if they are indirectly accessed though another object/function that is not re-defined. Let's assume I re-define these too.

Is it secure to sandbox code with a suffient list of objects and functions as content object?

What would be remaining the attack vectors in this case?

Edit 1:

The code should run within Firefox, Chrome, IE (10+), Opera, Safari.


Solution

  • No, this is not secure.

    No matter what you do with your code's execution environment using with, it is still possible to retrieve the "real" global object using the following trick:

    var window = (function(){ return this }).call(undefined);
    

    This works because Function.call will use the global object as the value of this if it is explicitly passed as undefined or null.