If your app runs on Node.js, check the version today. A bug called Node2Shell (CVE-2026-111497) lets an attacker send a malformed Brotli-compressed stream that crashes the process, leaks memory, or in some setups runs code on your server. No login needed.
On October 27, CISA added it to the Known Exploited Vulnerabilities catalog, listed as "Google Brotli Unchecked Return Value Vulnerability," with a federal remediation deadline of November 10. That listing means CISA has evidence of real-world exploitation. A week earlier, nobody had reported any.
What the bug is
Node.js ships its own copy of Google's Brotli decompression library inside the runtime binary. According to Akamai's write-up, a structurally invalid block-type switch in a Brotli stream was treated as "need more input" instead of an error, so the decoder kept appending data to an eight-byte internal buffer and wrote past the end of it. That's the out-of-bounds write.
Google, as the CVE numbering authority, scored it 9.2 on CVSS 4.0. The bug has been in Brotli since version 1.0.3, released in March 2018, per ELLIO. Node.js fixed it in its October 21 security release.
Because the bug lives in the runtime, updating an npm package won't fix it. HeroDevs points out that the npm package called "brotli" is unrelated. You need a new Node binary.
How attacker data gets in
You don't have to call a Brotli function yourself to be exposed. The sources agree on three paths:
- Express 5 request bodies. body-parser 2.x decompresses bodies sent with
Content-Encoding: brby default, because itsinflateoption defaults to true. Any client on the internet can send one. - Built-in
fetch()responses.fetch()decompresses Brotli responses automatically. If your app fetches URLs you don't control (webhooks, link previews, "import from URL"), a malicious server can reach you through its response. - Direct zlib calls. Anything that passes untrusted input to
zlib.brotliDecompress()orzlib.createBrotliDecompress().
A bare node:http server doesn't decode incoming Brotli bodies on its own, so the framework and the outbound calls are what matter.
How real is the exploit?
Real enough. A public proof of concept showed up on October 22. It only got code execution against a deliberately weakened build, but Imperva's red team then reported code execution on the official Node.js 24.22.0 Linux arm64 image, through both fetch() and Express 5. Not on every attempt.
ELLIO went further. In its own tests on x86-64, it got a shell against the stock node:24.22.0-slim image, against Express 5.3.0 with express.json(), and against Koa 3. Most of its 400 Express attempts crashed the worker instead of returning a shell, which is still a denial of service. In an update dated October 26, ELLIO said its sensors had recorded attacker traffic carrying exploit code aimed at Node.js 24.22.0. That attacker's chain scored zero hits in 50 attempts when ELLIO replayed it, so this is early, clumsy exploitation. It won't stay clumsy.
The scale is big. Wiz says 91% of the cloud environments it sees have vulnerable resources, and Akamai's telemetry puts affected Node.js versions on 61% of networks. And the same bug hits other software that bundles Brotli, including Bun before 1.4.4, Envoy, Istio, and Python's Brotli packages.
Are you exposed?
Fixed versions are 22.23.4, 24.22.1 and 26.12.1. Anything older on those lines is vulnerable. Node 25, 23, 20 and earlier are end of life and won't get a fix. Node 20 went EOL on April 30, 2026, and Akamai notes the Node advisory lists no workaround.
Check what actually runs in production, not what's on your laptop:
- Containers. Run
docker run --rm <image> node --versionagainst the image you deploy. A Dockerfile pinned tonode:24.22.0ornode:22.23.3-alpinestays vulnerable until you change the tag and rebuild, as Aikido points out. A floating tag likenode:22-alpineonly helps if you've rebuilt since October 21. - Serverless. A Lambda function on the
nodejs20.xruntime is running Node 20, which is end of life and won't be fixed. Move it to a supported runtime. - VMs and CI runners.
node --versionon each one. Distro packages may link the system Brotli library, so check your distro's advisory too. - Express 5.
npm ls express body-parser. If you see Express 5 or body-parser 2.x, that service takes compressed bodies from anyone. - Outbound fetches. Make a list of every place the app fetches a URL a user or a third party can influence. Those services go to the top of the patch list.
What to do this week
- Upgrade within your line. 22.23.4, 24.22.1 or 26.12.1. It's a patch-level bump with no API changes, per HeroDevs.
- Rebuild and restart everything. Every image, every function, every compiled binary that embeds the runtime. A patched base image does nothing for a container that's still running the old one.
- Get off Node 20. There's no upstream fix coming. If you can't move this week, put it on the calendar for next week and use the stopgaps below in the meantime.
- Block Brotli request bodies until you've patched. Reject
Content-Encoding: brat your proxy or load balancer, or set body-parser'sinflateoption tofalse. This does nothing forfetch()responses, so it's a stopgap, not a fix. - Watch for crashes. A Node worker that keeps segfaulting after restart is worth a look. ELLIO also suggests limiting who can read core dumps, since a crash can write secrets to disk.
November 10 is a deadline for federal agencies, not for you. But it's a useful one to borrow. As we wrote about a few weeks ago, the gap between disclosure and exploitation is now measured in days. This one took less than a week to show up in the wild.
Where a pen test fits
Patching is on you. Nobody outside your team can bump a Dockerfile tag or redeploy a Lambda. What a pen test can do is show you what your stack tells the world: framework fingerprints, headers like X-Powered-By: Express, version strings, and the forgotten staging box still running last year's image. Those are the things attackers scan for first.
The free scan is a quick look at what's visible on your domain. A $495 pen test goes further, with a human reviewing every finding, and it'll flag outdated runtimes and frameworks where they can be seen from outside.