Sandbox Escape in [email protected]
There exists a vulnerability in source code transformer (exception sanitization logic) of vm2 for versions up to 3.9.15, allowing attackers to bypass handleException()
and leak unsanitized host exceptions which can be used to escape the sandbox and run arbitrary code in host context.
const {VM} = require("vm2");
const vm = new VM();
const code = `
aVM2_INTERNAL_TMPNAME = {};
function stack() {
new Error().stack;
stack();
}
try {
stack();
} catch (a$tmpname) {
a$tmpname.constructor.constructor('return process')().mainModule.require('child_process').execSync('touch pwned');
}
`
console.log(vm.run(code));
As host exceptions may leak host objects into the sandbox, code is preprocessed with transformer()
(lib/transformer.js:49) in order to instrument the code with sanitizer function calls (lib/transformer.js:108).
Identifier name of catch clause is interpolated into insertions
as code
(lib/transformer.js:137) to sanitize caught exception, possibly a host exception.
This is subsequently post-processed to replace $tmpname
with the string value in tmpname
(originally VM2_INTERNAL_TMPNAME
) for ObjectPattern
case sanitization code (lib/transformer.js:189), which in turn allows an attacker to bypass handleException()
with identifiers containing the string $tmpname
.
An attacker may then use any method to raise a host exception (test/vm.js:1082 for example, via internal prepareStackTrace
) and use it to access host Function
constructor, escaping the sandbox and gaining arbitrary code execution in host context.
Remote Code Execution, assuming the attacker has arbitrary code execution primitive inside the context of vm2 sandbox.
Xion (SeungHyun Lee) of KAIST Hacking Lab