0

I'm trying to sandbox a function in a way to prevent it from doing anything that is considered malicious. Simple example:

const fn = (window, setTimeout) => {
    console.log(`window: ${typeof window}`);
    console.log(`setTimeout: ${typeof setTimeout}`);
};

fn (undefined, undefined);

// console output:
// window: undefined
// setTimeout: undefined

The function fn does not have any access to the window or setTimeout functions, because they're hidden by the arguments of the same name.

To make this more useful, I'd like to write a higher-order function to do the sandboxing:

const sandbox = (fn) => (...args) => {
    return ((window, setTimeout) => {
        return fn.call(args);
    })();
};

const maliciousFn = (a, b) => {
    console.log(`a: ${a}`);
    console.log(`b: ${b}`);
    console.log(`window: ${typeof window}`);
    console.log(`setTimeout: ${typeof setTimeout}`);
    return 42;
};

const safeFn = sandbox(maliciousFn);

console.log (`maliciousFn returns: ${maliciousFn(13, 27)}`);
console.log (`safeFn returns: ${safeFn(13, 27)}`);

This doesn't work as the maliciousFn has already captured the references of window and setTimeout, and the additional wrapper can't change that.

Is it possible to do this properly?

Background: The reason behind this is that I'd like to write a sandboxed eval function that could evaluate any given script safely without the risk of doing anything malicious. Of course, I'd have to hide all globals, not just window and setTimeout. But once it works for window and setTimeout, I can easily add all the other globals as well.

const safeEval = sandbox(eval);
const result = safeEval(someScriptComingFromAnUnsafeSource);
digory doo
  • 1,978
  • 2
  • 23
  • 37

0 Answers0