vm2 has a NodeVM require.root bypass via symlink traversal that allows sandbox escape
NodeVM's require.root path restriction can be bypassed using filesystem symlinks, allowing sandboxed code to load modules from outside the allowed root directory in host context. Because path validation uses path.resolve() (which does not dereference symlinks) but module loading uses Node's native require() (which does), an attacker can load arbitrary host-realm modules and achieve remote code execution.
High (CVSS 3.1: 8.5)
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H
lib/resolver-compat.js — CustomResolver.isPathAllowed() (line 53-60)lib/resolver-compat.js — CustomResolver.loadJS() (line 62-66)lib/filesystem.js — DefaultFileSystem.resolve() (line 8-10)The isPathAllowed method validates whether a resolved filename falls within the allowed root paths using a string-prefix check:
```js
// lib/resolver-compat.js:53-60
isPathAllowed(filename) {
return this.rootPaths === undefined || this.rootPaths.some(path => {
if (!filename.startsWith(path)) return false;
const len = path.length;
if (filename.length === len || (len > 0 && this.fs.isSeparator(path[len-1]))) return true;
return this.fs.isSeparator(filename[len]);
});
}
```
The filename passed to this check is resolved via DefaultFileSystem.resolve(), which uses path.resolve():
```js
// lib/filesystem.js:8-10
resolve(path) {
return pa.resolve(path);
}
```
path.resolve() normalizes the path (resolves ., .., and makes it absolute) but does NOT dereference symlinks. A symlink at /root/node_modules/safe pointing to /outside/root/malicious resolves to /root/node_modules/safe — passing the prefix check.
However, the actual module loading uses Node's native require(), which does follow symlinks:
```js
// lib/resolver-compat.js:62-66
loadJS(vm, mod, filename) {
if (this.pathContext(filename, 'js') !== 'host') return super.loadJS(vm, mod, filename);
const m = this.hostRequire(filename);
mod.exports = vm.readonly(m);
}
```
A search for realpath, readlink, lstat, or any symlink-aware function across the entire lib/ directory returns zero results. Neither DefaultFileSystem nor VMFileSystem provides a realpath method. The root paths themselves are also resolved without dereferencing symlinks:
```js
// lib/resolver-compat.js:218
const checkedRootPaths = rootPaths ? (Array.isArray(rootPaths) ? rootPaths : [rootPaths]).map(f => fsOpt.resolve(f)) : undefined;
```
1. Host creates NodeVM with require: { external: ['safe'], root: '/tmp/root', context: 'host' }
2. A symlink exists: /tmp/root/node_modules/safe → /outside/root/vm2/ (e.g., via pnpm, npm link, or workspaces)
3. Sandbox code calls require('safe')
4. DefaultResolver.resolveFull() resolves to /tmp/root/node_modules/safe/index.js
5. tryFile() calls this.fs.resolve(x) → path.resolve() → /tmp/root/node_modules/safe/index.js (symlink NOT followed)
6. isPathAllowed() checks if path starts with /tmp/root/ → PASSES
7. loadJS() detects context: 'host', calls this.hostRequire(filename)
8. Node's require() follows the symlink, loads from /outside/root/vm2/index.js
9. Module executes in host realm; exports proxied to sandbox
10. Sandbox uses loaded module to escalate (e.g., creates a new privileged NodeVM with child_process)
```js
const path = require('path');
const fs = require('fs');
const os = require('os');
const { NodeVM } = require('vm2');
// Create an "allowed" root directory
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'vm2-root-'));
fs.mkdirSync(path.join(root, 'node_modules'), { recursive: true });
// Symlink inside root pointing to vm2 package outside root
// In real deployments: pnpm, npm link, workspaces create these automatically
const link = path.join(root, 'node_modules', 'safe');
fs.symlinkSync(path.resolve(__dirname),
This issue can be reached over the network, attack complexity is high, an attacker needs low-level privileges on the target. No user interaction is required. The scope is changed, meaning a successful attack can affect components beyond the vulnerable one. Rated impact: confidentiality high, integrity high, availability high.
The score comes from this vector: CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H
CVE-2026-43998 is classified as CWE-59: Link Following. The software follows symbolic or hard links without verifying their target, so a planted link can redirect an operation to a sensitive file.
CVE-2026-43998 is recorded against 1 package.
Published on 7 May 2026 and last revised on 6 August 2026. A public exploit is known to exist, which raises the urgency of patching considerably. Record sourced from OSV.
github.com (Web)
nvd.nist.gov (Advisory)
github.com (Package)
github.com (Web)
vm2 has other advisories on record. If you are patching this one, these are worth checking on the same host:
These advisories are the same class of weakness (CWE-59: Link Following) in other software:
Each distribution ships its own build and its own fixed version. Pick the one you run:
Details
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H
Affected Packages
| Software | From version | Fixed in |
|---|---|---|
| vm2 | — | — |
References
Similar Threats
Exploit Protection
CVE-2026-43998 carries CVSS 8.0 High rating and a public exploit already exists. BotEraser checks your installation against this and other known CVE records, and blocks IPs associated with exploit activity.
Check My Site For CVE-2026-43998 →No credit card required · Results in minutes
ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.
Stay up to date with the latest from Boteraser.
We use cookies to improve your experience on our site. By using our site, you consent to cookies.
Manage your cookie preferences below:
Essential cookies enable basic functions and are necessary for the proper function of the website.
CloudFlare provides web performance and security solutions, enhancing site speed and protecting against threats.
Service URL: developers.cloudflare.com (opens in a new window)
These cookies are needed for adding comments on this website.
These cookies are used for managing login functionality on this website.
Statistics cookies collect information anonymously. This information helps us understand how visitors use our website.
Google Analytics is a powerful tool that tracks and analyzes website traffic for informed marketing decisions.
Service URL: policies.google.com (opens in a new window)
You can find more information in our Cookie Policy and Privacy Policy.