CVE-2026-22709 is a critical sandbox escape (CVSS 9.8) in vm2, the Node.js sandbox library, before version 3.10.2. Callback sanitization on Promise then and catch can be bypassed, which lets attackers run arbitrary code on the host. The fix is vm2 3.10.2, so upgrade and review how you isolate untrusted code.
What's affected
vm2 before 3.10.2. The fixed version is 3.10.2.
The advisory text I read says it was reported against 3.10.0. The record says the flaw lies in lib/setup-sandbox.js, where the callback of the local promise then is sanitized but the global promise then is not, and async functions return the global kind.
Any application that runs untrusted code through vm2 is affected, either directly or through another package that depends on it.
How to check if you're exposed
Look for vm2 across your projects, including nested dependencies.
npm ls vm2
npm ls vm2 --all
Check lockfiles for a resolved version below 3.10.2. Because vm2 is often a transitive dependency, a scan of the whole dependency tree is more reliable than a search of direct dependencies.
Then find where it is used. If vm2 only ever runs code your own team wrote, exposure is lower. If it runs user supplied code, expressions or plugins, treat it as a high priority.
What to do now
- Upgrade vm2 to 3.10.2 or later, and commit the updated lockfile.
- For transitive uses, update the parent package, or use your package manager overrides to force a patched vm2.
- Find every place your code runs untrusted input through vm2, and list who can supply it.
- For untrusted code, add a second layer of isolation, such as a separate process or container with no secrets and limited network access.
- Review your logs for unexpected child processes spawned by your Node.js services.
- Plan a move to a stronger isolation model, since in language sandboxes have a history of escapes.
Why it matters
The weaknesses are CWE-693, CWE-913 and CWE-94. In plain terms, the sandbox guarded one path that handed callbacks to code outside the sandbox and missed a second path that did the same thing. The record says the sanitised wrapper existed for the local Promise, while the global Promise, which is what async functions return, was left unsanitised.
A sandbox like this is a security boundary, so one missed path turns into full code execution on the host, which is why the score is 9.8. Libraries that evaluate untrusted JavaScript in the same process depend on every object that crosses the boundary being wrapped, and that is hard to keep complete over time.
The record does not say it is exploited in the wild, and it is not on the CISA KEV list. The advisory includes a proof of concept. This post does not repeat it.
Try it yourself
A dependency being present is not the same as your code calling it. This demo shows how reachability narrows the list.
Click through it at your own pace, or open it full screen.
Quick check
Is vm2 still the right tool for untrusted code?
That is a judgement call for your team. This record shows how a single missed path breaks the sandbox, so a process level boundary is a safer assumption for hostile input.
Can I be affected without importing vm2 myself?
Yes. Another package in your dependency tree may use it, which is why a full tree scan matters.
Which version fixes it?
3.10.2, per the record and the release page.
Sources
Last reviewed: 19 October 2026.