Severity by source
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Primary rating from Vendor (https://github.com/patriksimek/vm2).
CVSS VectorVendor: https://github.com/patriksimek/vm2
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Lifecycle Timeline
7DescriptionCVE.org
Summary
VM2 suffers from a sandbox breakout vulnerability. This allows attackers to write code which can escape from the VM2 sandbox and execute arbitrary commands on the host system.
Details
The __lookupGetter__ method allows to read the getter of an object. It is special in VM2 since it will switch between the host and sandbox version of the method when passed to the other context. This allows to access getters on an object in the host context if the method is called from the host context which can be achieved by using the host apply method which can be accessed through Buffer.apply. Afterwards, this function can be used to call the host version of __lookupGetter__ with Buffer and __proto__ resulting in the prototype lookup method from the host context. With this method the hosts Function.prototype object can be retrieved and the host Function acquired through the constructor property which allows to create and run code in the host context. This issue was attempted to be fixed with https://github.com/patriksimek/vm2/blob/4b009c2d4b1131c01810c1205e641d614c322a29/lib/bridge.js#L427. However, this can be circumvented by using Object.getOwnPropertyDescriptor to get the constructor property.
PoC
The following code demonstrates this issue by acquiring the host process object and executing touch pwned.
const {VM} = require("vm2");
const vm = new VM();
vm.run(`
const g = ({}).__lookupGetter__;
const a = Buffer.apply;
const p = a.apply(g, [Buffer, ['__proto__']]);
Object.getOwnPropertyDescriptor(p.call(a),'constructor').value('return process')().mainModule.require('child_process').execSync('touch pwned');
`);Impact
Attackers can perform Remote Code Execution under the assumption that arbitrary code can be executed inside the context of a vm2 sandbox.
Articles & Coverage 1
AnalysisAI
Remote code execution in VM2 sandbox (npm package) versions ≤3.10.4 allows attackers to escape the JavaScript isolation boundary and execute arbitrary system commands on the host. The vulnerability exploits prototype chain traversal through Buffer.apply and __lookupGetter__ to access the host Function constructor, bypassing VM2's context isolation. Publicly available exploit code exists, and vendor-released patch version 3.11.0 addresses the issue. This is a complete sandbox escape requiring no authentication or user interaction, making it critical for environments executing untrusted code within VM2 contexts.
Technical ContextAI
VM2 is a Node.js npm package (pkg:npm/vm2) designed to provide sandboxed JavaScript execution environments. The vulnerability stems from CWE-94 (Improper Control of Generation of Code) in VM2's context isolation mechanism. The flaw lies in how VM2's bridge layer handles prototype chain traversal when switching between host and sandbox contexts. The __lookupGetter__ method is special-cased in VM2 to switch between host and sandbox versions, but this switching can be exploited. By chaining Buffer.apply (accessible from sandbox) with __lookupGetter__ and Object.getOwnPropertyDescriptor, an attacker can traverse from sandbox Buffer through __proto__ to the host's Function.prototype, then extract the host Function constructor. Previous fix attempts at blocking direct constructor access were bypassed using Object.getOwnPropertyDescriptor to indirectly retrieve the constructor property descriptor. The vulnerability demonstrates a fundamental challenge in JavaScript sandboxing: preventing prototype chain traversal across security boundaries when built-in objects must be shared between contexts.
RemediationAI
Upgrade to VM2 version 3.11.0 or later, which includes patches from commits 2b5f3e3a060d9088f5e1cdd585d683d491f990a3 and f9b700b1c7d9ef2df416666cb24e0b659140cc74 that block the descriptor chain exploit. The release is available at https://github.com/patriksimek/vm2/releases/tag/v3.11.0. If immediate upgrade is not possible, compensating controls include disabling VM2 usage entirely and replacing with alternative isolation mechanisms such as running untrusted code in dedicated containers (Docker), separate processes with strict resource limits (child_process with V8 isolates), or WebAssembly sandboxes. These alternatives trade performance and complexity for stronger isolation boundaries but eliminate JavaScript prototype chain traversal attacks. Note that attempting to filter specific method names (__lookupGetter__, Object.getOwnPropertyDescriptor) is ineffective due to the many alternate access paths in JavaScript. There is no safe workaround that keeps VM2 ≤3.10.4 in use for untrusted code. Organizations should also audit logs for suspicious VM2 usage patterns such as repeated sandbox creation failures or code containing prototype traversal keywords.
Same weakness CWE-94 – Code Injection
View allVendor StatusVendor
Share
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-26984
GHSA-grj5-jjm8-h35p