Executive brief
vm2 is a popular Node.js sandbox that restricts code execution by limiting which external modules can be loaded. This vulnerability bypasses those restrictions by exploiting flawed string matching logic—code in an allowlisted module can load a sibling package with a similar name, even though that sibling was never authorized. An attacker could read or modify files and data that should have been restricted by the sandbox.
Technical details
The vulnerability exists in the isPathAllowedForModule function (lib/resolver-compat.js, lines 122–132), which uses String.startsWith() to verify whether a resolved module path belongs to an allowlisted module. This allows a package like `node_modules/foo2` to pass validation when `node_modules/foo` is allowlisted, because the path prefix matches. An attacker exploits this by performing a relative require from an allowlisted package to reach a non-allowlisted sibling. The attack requires three preconditions: (1) transitive loading must be disabled, (2) the package layout with prefix-sharing names must already exist, and (3) the allowlisted package must have a reachable code path executing the relative require. The fix is to enforce a path separator boundary after the prefix, so only actual subdirectories of an allowlisted module are granted access. Patched in version 3.11.7.
Affected products
- vm2 vm2 before 3.11.7
Timeline
- 2026-08-24: disclosed
- 2026-09-17: advisory
- 2026-09-17: patched: Version 3.11.7