Summary
A path-prefix authorization flaw in vm2's NodeVM external-module resolver can let untrusted guest code access modules that were not intended to be allowlisted.
When a custom resolver uses host-context loading, an attacker may load a sibling module whose path shares the allowed module's prefix, causing its top-level code to execute in the host process and potentially escape the sandbox.
Affected context
The issue occurs in vm2 deployments that use NodeVM external-module configuration with:
- A custom external-module resolver
- Host-context resolution through
context: 'host' - Allowlisted module directories whose names are prefixes of other filesystem paths
The risk depends on untrusted guest code being able to invoke the external-module mechanism and on a non-allowlisted sibling module being reachable through the host filesystem.
Exploit preconditions
- Attack surface: NodeVM external-module resolution
- Required access: Ability to execute untrusted code inside the vm2 guest context
- Configuration requirement: A custom resolver must be configured with host-context loading and external-module restrictions
- Trigger point: A guest request to load an allowed module followed by a path referring to a sibling module with a matching prefix
- Why exploitation is possible: The resolver checks a prefix-based regular expression without requiring a path separator or end-of-string boundary, allowing a non-allowlisted path to pass authorization and reach
hostRequire
Why this happens
The underlying bug is an incomplete authorization boundary in path validation. LegacyResolver.customResolve records an allowed directory as a regular expression that matches the directory prefix but does not require the next character to be a path separator or the end of the path.
Consequently, paths such as an allowed directory and a similarly named sibling directory can be treated as equivalent for authorization purposes. This maps to CWE-863: Incorrect Authorization, because the resolver grants access to a resource that falls outside the intended allowlist. Loading through the host require mechanism also causes module initialization code to run with host-process privileges before exported values are restricted.
Potential impact
- Untrusted guest code may escape the vm2 sandbox
- Arbitrary JavaScript code may execute in the host process
- Sensitive host files, environment data, or services could be accessed
- The application process may be modified, disrupted, or used for further compromise
- Compromise may extend to other resources available to the host process
General mitigation guidance
Mitigation generally focuses on making module authorization path-aware and reducing trust in guest-controlled module requests.
Common defensive patterns include:
- Compare canonical path components rather than using unbounded string-prefix matching
- Require a path separator or exact path termination after an approved directory
- Resolve and validate the complete target path before loading it
- Prefer explicit module allowlists over broad directory-based permissions
- Avoid loading guest-selected modules in the host context where isolation is required
- Restrict filesystem permissions and process privileges available to the host application
- Treat module resolution configuration as protected deployment policy rather than guest-controlled data
How teams detect issues like this
Organizations can look for this class of issue through:
- Static analysis rules that identify authorization checks based only on raw path prefixes
- Code review checks for regular expressions lacking path-boundary or end-of-string constraints
- Tests using similarly named sibling directories and canonicalization edge cases
- Runtime auditing of host-context module loads initiated by sandboxed code
- Policy checks that flag custom resolvers and host-context loading in sandbox configurations
- Automated security review tools that model path authorization and confused-deputy behavior

