Back to Intelligence

CVE-2026-111497: Node2Shell RCE in Node.js Brotli Decoder — Detection and Remediation Guide

SA
Security Arsenal Team
October 23, 2026
10 min read

Researchers at Imperva have demonstrated a critical code execution path — dubbed Node2Shell — against the official Node.js 24.22.0 build for Linux arm64. By feeding crafted Brotli-compressed data into the Brotli decoder bundled with Node.js (tracked as CVE-2026-111497), an attacker can achieve arbitrary code execution on the target process with no debugger, no custom build, and no local access required. If your organization runs Node.js services that decompress attacker-controlled Brotli data — HTTP content-encoding, reverse-proxied APIs, file upload pipelines, or message queues — treat this as a drop-everything remediation item.

What Happened

Imperva's research team built a working proof-of-concept that takes malformed Brotli data from the network to code execution on the stock node:24.22.0 Linux arm64 image. That last point matters more than the CVE number itself: most memory-corruption writeups die in the gap between "crash in a fuzzer" and "reliable RCE." This one did not. The exploit ran against a pristine, unmodified official binary — the exact artifact most organizations pull from Docker Hub or package repositories.

Node.js bundles Brotli for two primary surfaces:

  1. Content-Encoding: br HTTP decompression — any Node.js server, framework middleware (Express, Fastify, Koa body parsers), or HTTP client that transparently decompresses Brotli responses.
  2. The zlib module API — brotliDecompressSync(), createBrotliDecompress(), and related calls used by applications to decompress user uploads, cached blobs, queue payloads, and archived assets.

Both surfaces are routinely exposed to attacker-controlled input in production. A web server accepting Brotli-encoded request bodies, an SSRF-reachable internal fetch, or a microservice decompressing queue messages all present a viable delivery channel.

Technical Analysis

Affected Products and Versions

  • Node.js 24.x — confirmed exploitable on the official 24.22.0 build for Linux arm64
  • Other architectures and earlier release lines (22.x LTS, 20.x LTS) should be treated as potentially affected until Node.js publishes its advisory scope — Brotli is bundled across all supported release lines, and the vulnerable decoder code is shared
  • CVE: CVE-2026-111497 (disclosed by Node.js alongside the Imperva research)

How the Vulnerability Works

From the defender's perspective, the attack chain is:

  1. Delivery: Attacker submits crafted Brotli-compressed data to any reachable Node.js code path that invokes the bundled decoder — an HTTP endpoint accepting Content-Encoding: br, an API ingesting compressed payloads, a file-processing worker, or a queue consumer.
  2. Trigger: The Node.js process passes the data to the Brotli decoder. The malformed stream corrupts memory inside the decoder — memory-safety flaws in decompression libraries are a historically rich exploitation class because decoders perform complex, attacker-influenced pointer arithmetic at native speed.
  3. Execution: The corruption is steered into attacker-controlled execution within the Node.js process context. The payload inherits the full privileges, environment variables, cloud metadata access, and network reachability of the Node.js runtime — which in containerized deployments typically means IAM role credentials, database connection strings, and lateral-movement reach into the cluster.

No authentication, no local foothold, no debugger, no modified binary. The only prerequisite is reaching a decompression code path.

Exploitation Status

  • Working PoC: Yes — Imperva demonstrated reliable code execution against the official node:24.22.0 Linux arm64 image
  • Active in-the-wild exploitation: Not confirmed at time of writing, but a public working PoC against an ecosystem as large as Node.js historically converts to exploitation quickly — expect weaponization within days, not months
  • CISA KEV: Check CISA's KEV catalog for updates; given the PoC quality, KEV addition is a realistic near-term outcome

The defensive assumption: if your Node.js workload decompresses untrusted Brotli data, consider it exposed now.

Detection & Response

Memory-corruption exploits inside a long-lived runtime are hard to detect at the point of trigger — the crash-free exploitation happens in-process. Your highest-fidelity detections focus on post-exploitation behavior: Node.js processes spawning shells or system binaries, unexpected child processes, and egress connections from application containers. These are the behaviors the Node2Shell payload must exhibit to be useful to an attacker.

Sigma Rules

YAML
---
title: Node.js Process Spawning Shell or System Utility
description: Detects a Node.js process spawning a shell or common post-exploitation system binary. Strong indicator of in-process RCE such as the Node2Shell Brotli decoder exploit (CVE-2026-111497), where attacker code executes inside the node process and typically launches a shell or download cradle.
references:
  - https://thehackernews.com/2026/10/researchers-demonstrate-node2shell-rce.html
  - https://attack.mitre.org/techniques/T1059/
author: Security Arsenal
date: 2026/10/15
status: experimental
tags:
  - attack.execution
  - attack.t1059
logsource:
  category: process_creation
  product: linux
detection:
  selection_parent:
    ParentImage|endswith:
      - '/node'
      - '/nodejs'
  selection_child:
    Image|endswith:
      - '/sh'
      - '/bash'
      - '/dash'
      - '/zsh'
      - '/curl'
      - '/wget'
      - '/nc'
      - '/ncat'
      - '/python'
      - '/python3'
      - '/perl'
      - '/base64'
  condition: selection_parent and selection_child
falsepositives:
  - Build tooling and npm lifecycle scripts (postinstall hooks) legitimately spawning shells — scope by container/service context
  - Node-based process managers and dev servers in development environments
level: high
---
title: Node.js Child Process Executing From World-Writable or Temp Path
description: Detects execution of binaries from /tmp, /dev/shm, or /var/tmp by a Node.js process tree — a common payload staging pattern after in-process code execution via memory corruption such as CVE-2026-111497 (Node2Shell).
references:
  - https://thehackernews.com/2026/10/researchers-demonstrate-node2shell-rce.html
  - https://attack.mitre.org/techniques/T1203/
author: Security Arsenal
date: 2026/10/15
status: experimental
tags:
  - attack.exploitation_for_client_execution
  - attack.t1203
logsource:
  category: process_creation
  product: linux
detection:
  selection_path:
    Image|startswith:
      - '/tmp/'
      - '/dev/shm/'
      - '/var/tmp/'
  selection_lineage:
    ParentCommandLine|contains:
      - 'node'
  condition: selection_path and selection_lineage
falsepositives:
  - Some build systems and self-updating tools stage helpers in temp paths — investigate parent chain and service context
level: high

KQL (Microsoft Sentinel / Defender)

If your Node.js workloads ship Syslog/auditd or Defender for Endpoint telemetry into Sentinel, this hunt surfaces Node.js processes spawning shells or staging payloads from temp paths — the post-exploitation fingerprint of Node2Shell-style in-process RCE.

KQL — Microsoft Sentinel / Defender
// Hunt: Node.js spawning shells or temp-path payloads (post-RCE behavior)
// Relevant to CVE-2026-111497 / Node2Shell Brotli decoder exploitation
union isfuzzy=true
(DeviceProcessEvents
| where InitiatingProcessFileName =~ "node"
   or InitiatingProcessCommandLine has "node"
| where FileName in~ ("sh","bash","dash","zsh","curl","wget","nc","ncat","python","python3","perl")
   or FolderPath has_any ("/tmp/","/dev/shm/","/var/tmp/")
| project TimeGenerated, DeviceName, InitiatingProcessCommandLine, ProcessCommandLine, FileName, FolderPath, AccountName
),
(Syslog
| where Facility == "auth" or SyslogMessage has "node"
| where SyslogMessage has_any ("node","/tmp/","/dev/shm/")
   and SyslogMessage has_any ("/bin/sh","/bin/bash","curl ","wget ","python")
| project TimeGenerated, Computer, ProcessName, SyslogMessage
)
| order by TimeGenerated desc

Velociraptor VQL

For live-response triage on Linux hosts and container nodes, this artifact identifies Node.js processes with suspicious child processes or listening/exec anomalies consistent with post-exploitation activity.

VQL — Velociraptor
-- Hunt for Node.js processes spawning shells or staging payloads from temp paths
-- Triage artifact for suspected CVE-2026-111497 (Node2Shell) exploitation
SELECT Pid, Ppid, Name, Exe, CommandLine, Username, CreateTime
FROM pslist()
WHERE (
    -- Node.js process with shell/system-utility children
    Name =~ '(?i)^node' 
    AND Ppid IN (
        SELECT Pid FROM pslist() WHERE Name =~ '(?i)^node'
    )
) OR (
    -- Any process executing from temp/world-writable paths under a node lineage
    Exe =~ '^/(tmp|dev/shm|var/tmp)/'
    AND CommandLine =~ '(?i)node'
) OR (
    -- Shells with a node parent PID
    Name =~ '(?i)^(sh|bash|dash|nc|ncat|curl|wget|python3?)$'
    AND Ppid IN (
        SELECT Pid FROM pslist() WHERE Name =~ '(?i)^node'
    )
)

Remediation and Verification Script

Use this Bash script to inventory Node.js versions across your hosts and container images, flag vulnerable builds, and enforce a safe baseline. Run it on build agents, container hosts, and in CI to block deployments of affected images.

Bash / Shell
#!/usr/bin/env bash
# CVE-2026-111497 (Node2Shell) — Node.js Brotli decoder RCE inventory & verification
# Usage: sudo bash node2shell_check.sh

set -euo pipefail

VULNERABLE_VERSION="24.22.0"
echo "=== Node2Shell / CVE-2026-111497 exposure check ==="

# 1. Check system-installed Node.js
if command -v node >/dev/null 2>&1; then
    SYSVER=$(node --version | tr -d 'v')
    echo "[+] System Node.js version: v${SYSVER} ($(command -v node))"
    if [ "${SYSVER}" = "${VULNERABLE_VERSION}" ]; then
        echo "[!] VULNERABLE: official 24.22.0 build confirmed exploitable by Imperva PoC"
    else
        echo "[i] Not 24.22.0 — treat as potentially affected until Node.js advisory scopes all release lines"
    fi
else
    echo "[-] No system-wide node binary found"
fi

# 2. Find node binaries outside PATH (containers, bundled runtimes, sidecars)
echo "[+] Scanning for additional node binaries..."
find / -xdev -type f -name node -executable 2>/dev/null | while read -r bin; do
    ver=$("$bin" --version 2>/dev/null || echo "unknown")
    echo "    ${bin} -> ${ver}"
done

# 3. Inventory running Node.js processes and their versions
echo "[+] Running node processes:"
for pid in $(pgrep -x node 2>/dev/null || true); do
    exe=$(readlink -f /proc/"$pid"/exe 2>/dev/null || echo "unknown")
    cmd=$(tr '\0' ' ' < /proc/"$pid"/cmdline 2>/dev/null || echo "unknown")
    echo "    PID ${pid}: ${exe} :: ${cmd}"
done

# 4. Audit container images for the vulnerable tag
echo "[+] Checking local container images for node:24.22.0 ..."
if command -v docker >/dev/null 2>&1; then
    docker images --format '{{.Repository}}:{{.Tag}}' | grep -i node || echo "    none found"
elif command -v crictl >/dev/null 2>&1; then
    crictl images | grep -i node || echo "    none found"
else
    echo "    no container runtime CLI available"
fi

# 5. Flag code paths that decompress Brotli from untrusted input
echo "[+] Scanning for Brotli decompression call sites in application source..."
for dir in /srv /opt /home /var/www; do
    [ -d "$dir" ] && grep -rIl --include='*.js' --include='*.ts' --include='*.mjs' \
        -e 'brotliDecompress' -e 'createBrotliDecompress' -e "Content-Encoding.*br" \
        "$dir" 2>/dev/null || true
done

echo ""
echo "=== ACTION REQUIRED ==="
echo "1. Upgrade Node.js to the patched release per the Node.js security advisory."
echo "2. Until patched, do NOT decompress untrusted Brotli data (disable 'br' content-encoding"
echo "   acceptance at your reverse proxy / load balancer as a temporary control)."
echo "3. Review the flagged source paths above for attacker-reachable decompression paths."

Remediation

  1. Patch immediately. Upgrade to the fixed Node.js release published in the official Node.js security advisory (monitor the Node.js blog and Imperva's disclosure for the exact patched version across 24.x, 22.x LTS, and 20.x LTS lines). Rebuild and redeploy all container images — do not rely on in-place package updates for long-running services.
  2. Temporary mitigation — strip Brotli at the edge. Until patches roll out, configure your reverse proxy / load balancer / WAF (NGINX, Envoy, HAProxy, Cloudflare) to remove br from Accept-Encoding and reject inbound request bodies with Content-Encoding: br. This severs the most common network-reachable delivery path without touching application code.
  3. Audit decompression call sites. Inventory every use of brotliDecompress*, createBrotliDecompress*, and transparent Brotli handling in HTTP clients. Any of these fed by request bodies, uploads, queue messages, or third-party API responses is an exposure.
  4. Contain blast radius. Run Node.js workloads as non-root with read-only root filesystems, seccomp/AppArmor profiles restricting execve of shells, and egress filtering. The exploit executes inside the node process — constrained process privileges directly degrade payload utility.
  5. Hunt retroactively. Pull the last 30+ days of telemetry through the KQL query and Sigma logic above. With a public PoC in circulation, assume probing began at disclosure.
  6. Track CISA KEV. Monitor the CISA KEV catalog — a KEV listing would impose remediation deadlines for federal agencies and should accelerate your own patch SLA.

Related Resources

Security Arsenal Penetration Testing Services AlertMonitor Platform Book a SOC Assessment vulnerability-management Intel Hub

Is your security operations ready?

Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.