{"id":"CVE-2026-44005","aliases":["GHSA-vwrp-x96c-mhwq"],"url":"https://o3.security/vulnerability/CVE-2026-44005","summary":"vm2: Sandbox escape","details":"### Summary\nvm2's bridge exposes mutable proxies for real host-realm intrinsic prototypes and then forwards sandbox writes into the underlying host objects with otherReflectSet() and otherReflectDefineProperty(), which lets attacker-controlled JavaScript running in a default VM or inherited NodeVM mutate shared host Object.prototype, Array.prototype, and Function.prototype from inside the sandbox.\n\n### Details\nBaseHandler.apply() unwraps sandbox-controlled receivers and arguments with otherFromThis() / otherFromThisArguments() and then directly invokes the real host function with ret = otherReflectApply(object, context, args), so any default-exposed host function that can surface a prototype getter becomes a prototype-walking primitive ([lib/bridge.js:665-676](https://github.com/patriksimek/vm2/blob/408fc855f1cc1bbc2985b029465ee0e732ada433/lib/bridge.js#L665-L676)). BaseHandler.get() special-cases __proto__ and returns the host-side descriptor or proxy target prototype, which is enough for the attacker to reuse the host __lookupGetter__('__proto__') accessor repeatedly until the walk lands on host Object.prototype, Array.prototype, or Function.prototype ([lib/bridge.js:590-616](https://github.com/patriksimek/vm2/blob/408fc855f1cc1bbc2985b029465ee0e732ada433/lib/bridge.js#L590-L616)). Once the attacker has a proxy to a host intrinsic prototype, BaseHandler.set() performs value = otherFromThis(value); return otherReflectSet(object, key, value) === true;, which writes attacker-controlled data directly into the shared host object instead of keeping the mutation sandbox-local; BaseHandler.defineProperty() repeats the same design at otherReflectDefineProperty(object, prop, otherDesc) for descriptor-based writes ([lib/bridge.js:641-649](https://github.com/patriksimek/vm2/blob/408fc855f1cc1bbc2985b029465ee0e732ada433/lib/bridge.js#L641-L649), [lib/bridge.js:753-774](https://github.com/patriksimek/vm2/blob/408fc855f1cc1bbc2985b029465ee0e732ada433/lib/bridge.js#L753-L774)). Existing validation does not stop the attack because the constructor filter only blocks one dangerous-property access pattern, setPrototypeOf() only blocks prototype replacement rather than ordinary property assignment, and containsDangerousConstructor() only protects one later re-unwrapping path instead of the initial host-prototype write sink ([lib/bridge.js:494-530](https://github.com/patriksimek/vm2/blob/408fc855f1cc1bbc2985b029465ee0e732ada433/lib/bridge.js#L494-L530), [lib/bridge.js:595-610](https://github.com/patriksimek/vm2/blob/408fc855f1cc1bbc2985b029465ee0e732ada433/lib/bridge.js#L595-L610), [lib/bridge.js:660-662](https://github.com/patriksimek/vm2/blob/408fc855f1cc1bbc2985b029465ee0e732ada433/lib/bridge.js#L660-L662)).\n\n### PoC\nRun the following code snippet and observe that the value of vm2EscapeMarker is polluted:\n```\nconst { VM } = require('vm2');\nconst vm = new VM();\nvm.run(`\n  const g = ({}).__lookupGetter__;\n  const a = Buffer.apply;\n  const p = a.apply(g, [Buffer, ['__proto__']]);\n  const hostObjectProto = p.call(p.call(p.call(p.call(Buffer.of()))));\n  hostObjectProto.vm2EscapeMarker = 'polluted-object-prototype';\n`);\nconsole.log({}.vm2EscapeMarker)\n```\n\n### Impact\nSandbox escape and prototype pollution.","published":"2026-05-13T17:40:41.578Z","modified":"2026-09-09T03:30:43.524343372Z","cvss":{"score":10,"severity":"CRITICAL","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:H"},"epss":{"score":0.00831,"percentile":0.54827,"asOf":"2026-08-20"},"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"npm","name":"vm2","fixedVersion":"3.11.0"}],"fix":null,"references":[{"type":"WEB","url":"https://security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-44005.json"},{"type":"ADVISORY","url":"https://access.redhat.com/errata/RHSA-2026:50850"},{"type":"ADVISORY","url":"https://access.redhat.com/security/cve/CVE-2026-44005"},{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/44xxx/CVE-2026-44005.json"},{"type":"ADVISORY","url":"https://github.com/patriksimek/vm2/security/advisories/GHSA-vwrp-x96c-mhwq"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-44005"},{"type":"REPORT","url":"https://bugzilla.redhat.com/show_bug.cgi?id=2477205"},{"type":"PACKAGE","url":"https://github.com/patriksimek/vm2"},{"type":"WEB","url":"https://github.com/patriksimek/vm2/releases/tag/v3.11.0"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-09-09T03:30:43.524343372Z"}}