Skip to main content

The Identity at the Core

The Definitive Chronicle of Identity & Access Management

After PHP2Shell, Here Comes Its Cousin: Node2Shell

Meet Node2Shell (CVE-2026-111497): how a native Brotli memory flaw in Node.js turns untrusted compressed data into RCE, and why your workload IAM is the real prize.

By Paulo Barrilli
5 min read84 views0 comments

If you thought the security marketing department was taking the rest of Halloween week off after PHP2Shell, I have bad news. Within hours of the PHP advisories landing on October 21, a second vulnerability got christened on social media: "Node2Shell."

This time, the target is CVE-2026-111497 (), a high-to-critical vulnerability disclosed in the October 21, 2026 Node.js security release. Just like its cousin PHP2Shell, the branding is doing heavy lifting (Node.js itself never used the name "Node2Shell" in its advisory), and once again, the real story sits underneath the hype: a native C/C++ memory corruption flaw buried beneath a memory-safe scripting language, waiting to hand an attacker the keys to whatever service identity your runtime holds.

Let’s look at what the CVE record and the official advisories actually confirm, where the real exposure lies, and why this week is a masterclass in workload identity risk.

What the CVE Record Actually Says

Despite the matching "2Shell" costume, CVE-2026-111497 is not a JavaScript injection bug, nor is it exclusive to Node.js. It is an out-of-bounds write (CWE-787) in Google’s upstream Brotli compression library (versions 1.0.3 through 1.2.0), which Node.js bundles inside its runtime.

Here are the verified facts so far:

  • The Flaw: When the Brotli decoder processes a specially crafted, malformed compressed stream, it fails to halt on invalid input and writes past the end of its allocated memory buffer (fixed via upstream Brotli commit 0ed4268a).

  • The Score: Google’s CVE record assigns it a CVSS v4.0 score of 9.2 (Critical), while the Node.js security advisory rates it High and explicitly warns that the impact includes Remote Code Execution (RCE).

  • The Preconditions: Your application is exposed if it decompresses untrusted Brotli data. That happens directly if your code calls node:zlib Brotli decompression methods (zlib.brotliDecompress, createBrotliDecompress) on user-supplied payloads, or automatically when Node’s native fetch() (Undici) receives an HTTP response with Content-Encoding: br from an untrusted or attacker-controlled upstream server.

  • The Blast Radius Beyond Node: Because the bug lives in upstream Brotli, Bun (fixed in v1.4.4) and Python’s Brotli / brotlicffi packages (fixed in 1.2.1) also shipped emergency updates on October 22.

  • Affected and Patched Node Versions: Node.js patched the flaw on October 21 in v22.23.4, v24.22.1, and v26.12.1. Crucially, Node.js 20 and older have reached End of Life and will not receive upstream fixes. This creates a massive operational blind spot given how many production containers and serverless functions still pin Node 20.

  • Exploitation Status: While multiple Proof of Concept (PoC) repositories appeared on GitHub on October 22 and researchers have demonstrated intermittent code execution against unpatched Node 24 containers, CISA's Known Exploited Vulnerabilities (KEV) catalog () still lists active exploitation as "none."

The Sibling Rivalry: Why Node2Shell Is Even Sneakier for IAM

If PHP2Shell was a front door smash-and-grab against legacy and modern web servers, Node2Shell targets the connective tissue of modern cloud architectures: API gateways, SSRF filtering proxies, webhook processors, Backend for Frontend (BFF) tiers, and AI agent orchestrators that fetch() external URLs on behalf of users.

And what else shipped in that exact same October 21 Node.js security batch?

  • CVE-2026-105482: A DNS resolution truncation flaw (dns.resolve*) via embedded NUL bytes that lets an attacker pass an allowlist check for one domain while querying another.

  • CVE-2026-106069 and CVE-2026-105483: Two TLS hostname verification bypasses (tls.checkServerIdentity) involving noncanonical and Unicode full-width IP addresses.

  • CVE-2026-106073: A bypass in fs.realpathSync against Node’s built-in Permission Model.

Put those together, and you see the attacker’s dream chain: bypass a URL allowlist or TLS check to trick a Node.js service into fetching an attacker-controlled endpoint, return a malicious Content-Encoding: br payload, trigger the Brotli out-of-bounds write in native C code, and step right over JavaScript’s sandbox.

The Identity Prize Inside a Node.js Process

Once an exploit lands in a Node.js worker, the attacker does not need to drop a classic .php web shell on disk (MITRE ATT&CK T1505.003) when process.env is already sitting in memory. In modern microservice and serverless shops, a compromised Node runtime is an identity goldmine:

  • process.env Sprawl: Walk into almost any Node.js container and dump the environment variables. You will find AWS_SECRET_ACCESS_KEY, DATABASE_URL, STRIPE_SECRET_KEY, internal JWT signing keys, and third-party OAuth tokens sitting in plain text in memory.

  • Cloud Workload Identity and Metadata: If that Node service runs in Kubernetes or ECS without strict pod or task role scoping, or on EC2 with IMDSv1 enabled (), an attacker who hijacks the Node process immediately inherits the cloud IAM role attached to the compute node.

  • Outbound Trust by Default: Unlike traditional PHP workers that rarely need to call external URLs, Node services are built to talk to everything. A malicious payload executing inside the node binary blends right into normal outbound HTTPS traffic unless you enforce strict egress filtering and short-lived, audience-bound tokens.

What to Do Before Monday

First, patch the runtime, not just your package.json. Because Brotli is compiled into the Node.js binary itself, npm audit fix will not save you. You have to rebuild your base container images and upgrade runtimes to Node.js 22.23.4, 24.22.1, or 26.12.1 (and Bun 1.4.4 or Brotli 1.2.1 where applicable). If you are still on Node 20, this is your wake-up call that End of Life means unpatched RCE.

Second, if you cannot patch a service tonight and it fetches untrusted external URLs or accepts compressed uploads, strip br from outbound Accept-Encoding headers and block inbound Content-Encoding: br at your WAF or reverse proxy until the runtime is updated.

Finally, use PHP2Shell and Node2Shell as a two-for-one tabletop exercise for your identity team. Two completely different languages and two native C memory bugs were released on the exact same day, and both end with the exact same question: "When the runtime gets tricked into running a stranger's code, what permissions did we leave lying around for them to inherit?"

Shrink the IAM role, move long-lived secrets out of process.env, and audit your machine identities. Next week, there will be another "2Shell" bug, and it will not care what language you wrote your app in.

#node2shell#cve2026111497#php2shell#nodejs#brotli#workloadidentity#iam#secretsmanagement
Share:XLinkedInFacebook

Be the first to comment

Members only: sign up if you have something worth saying.

Want to weigh in? Sign in or create a free account.

No comments yet.