Creuto is now an OpenAI Select Partner Read More
node2shell is a real out-of-bounds write in the Brotli decoder Node.js bundles. There is no workaround, and your outbound fetch() calls count too.

The fix for node2shell landed in Google's Brotli source in February 2026, roughly eight months before Node.js shipped it to users. CVE-2026-111497 is an out-of-bounds write in the Brotli decoder Node.js bundles, rated High, and it is fixed in 22.23.4, 24.22.1 and 26.12.1. If your code decompresses Brotli data an attacker controls — in a request body or in a response you fetch — you are in scope, and there is no upstream workaround to apply instead.
That last clause is the part worth planning around. This is not a patch you can defer behind a mitigation while you schedule a window.
Node.js published its security releases on 21 October 2026, covering the 26.x, 24.x and 22.x lines and fixing ten CVEs in total. The one that got a nickname is CVE-2026-111497, titled in the advisory as "Node.js Brotli decoder out-of-bounds write permits remote code execution", affecting all three supported lines.
Now read what the advisory does not contain. There is no CVSS score for any of the ten CVEs, only the labels High, Medium and Low. There are no affected version ranges — just which release lines are involved. And there is no workaround or mitigation text for any of them, including this one. Each CVE section names the reporter and the fixer and stops.
So the advisory tells you the highest severity in the release is High, and leaves you to work out whether that applies to you. For a team running a mixed fleet of services on three Node lines, that is the whole triage problem and none of the answer. We have hit this with clients before: the version table is the easy part, and the reachability question is the work.
The advisory is clear on one thing, and it matters: "End-of-Life versions are always affected when a security release occurs." Node.js 20.x and earlier get nothing here.
A proof of concept appeared on 22 October, and the coverage of it diverges in a way worth being precise about, because it changes how urgently you treat this.
The Hacker News reported that the PoC reached code execution only on a deliberately weakened test build, and that on a standard build its author saw a crash and a limited memory read.
Aikido's write-up agrees about the weakened build, then adds something the first account leaves out: the same day, separate researchers reported code execution against "the official, unmodified Node.js 24.22.0 image on Linux arm64", with an exploit that "did not work on every attempt", and 24.22.1 rejects the same input.
These are not strictly contradictory — they can be two different researchers with two different results — but neither account confirms the other, and nobody has published a reliable exploit against a stock build. Aikido does not name the researchers or link the report, so treat the unmodified-build claim as credible and unverified rather than settled. As of 22 October, no exploitation in the wild had been reported.
The honest reading: a memory-corruption bug in a decoder, with one lab report of inconsistent code execution on a stock build, is a patch-now bug and not a drop-everything bug. Two of those three facts are usually missing from the summaries.
This is the question the advisory skips, and Aikido answers it precisely enough to audit against. Vercel puts the rule in one sentence in its customer bulletin: you are exposed when your code, or a library it uses, "decompresses Brotli data an attacker controls, whether in a request body or in a response it fetches".
| Path | Decodes attacker-controlled Brotli? | What to grep for |
|---|---|---|
| Express 5, body-parser 2.x | Yes — decompresses bodies sent with Content-Encoding: br | Any public POST or PUT route |
Built-in fetch() | Yes — decompresses Brotli responses automatically | Outbound calls to third parties |
node:zlib directly | Yes, on any untrusted input | brotliDecompress, createBrotliDecompress |
Bare node:http server | No — does not decode incoming Brotli bodies on its own | — |
The outbound row is the one teams miss. An API client that calls a partner service is exposed through the response it receives, which means a compromised or hostile upstream reaches your process without ever sending you a request. If you build API integrations against third-party services you do not control, that path is in scope.
Two further cases. Distro-packaged Node may link the system Brotli library rather than the bundled copy, in which case the fix arrives through your distribution's package — the fixed Brotli library versions are 1.2.1, 1.1.1 and 1.0.10. And Bun carried the same flaw until 1.4.4.
With no upstream workaround, the available stopgap is to drop requests carrying Content-Encoding: br at your reverse proxy, load balancer or middleware. Aikido recommends exactly that and says it used the rule on internal services it could not upgrade immediately. Vercel added firewall rules on 21 October that apply to every project automatically.
Both are explicit about the boundary, and it is the same boundary. Vercel's rules "do not cover responses your functions fetch from other servers". Aikido's version: "Neither stopgap covers Brotli responses that your application fetches from other servers. Only a runtime upgrade removes the flaw." Vercel also flags that self-hosted Next.js needs the runtime upgrade because "Next.js does not block Brotli responses in image optimization".
So the proxy rule closes the inbound half and buys you a scheduling window. It is worth doing on anything you cannot patch today. It is not a substitute, and a change log that records it as remediation is wrong.
Upgrade to 22.23.4, 24.22.1 or 26.12.1 — and note that this release also fixed three High-severity TLS and DNS hostname-verification bugs that have attracted almost no attention next to the Brotli one.
Then work the reachability list rather than the version list: public routes behind Express or body-parser, every outbound fetch() to a party you do not control, and direct node:zlib calls on untrusted input. Anything still on Node 20.x or earlier needs a line migration, not a patch. The triage shape is the same one that applied to Next.js 16.4.1's two critical RCEs: the version check takes an hour and the reachability audit takes the rest of the week.
The eight-month gap between the upstream Brotli commit and this release is the durable lesson. A vulnerability in a bundled dependency is fixed when your runtime ships it, not when the dependency fixes it — which is the same shape as php2shell landing on PHP estates the same week, and the reason a software bill of materials that stops at your direct dependencies will keep missing this class of bug. If you are deciding where to spend the next quarter's hardening budget, that inventory is worth more than another scanner.
node2shell is the nickname for CVE-2026-111497, an out-of-bounds write in the Brotli decoder that Node.js bundles. Specially crafted Brotli data can make the decoder write past its buffer, with impact ranging from a crash to code execution in the Node.js process. It is rated High severity.
The 26.x, 24.x and 22.x release lines are all affected, and the fixes are in 26.12.1, 24.22.1 and 22.23.4. The Node.js advisory does not publish exact affected version ranges, only the lines. Node.js 20.x and earlier are end of life and will not receive the fix.
No. The Node.js advisory publishes no workaround for CVE-2026-111497. Dropping requests with a Content-Encoding of br at a reverse proxy or load balancer reduces inbound exposure, but it does not cover Brotli responses your application fetches from other servers. Only a runtime upgrade removes the flaw.
No exploitation in the wild had been reported as of 22 October 2026. A proof of concept published that day reached code execution against a deliberately weakened build, and separate researchers reported inconsistent code execution against an unmodified Node.js 24.22.0 build on Linux arm64.
Check three paths. Express 5 and body-parser 2.x decompress request bodies sent with Content-Encoding: br. The built-in fetch() decompresses Brotli responses automatically, so outbound calls count. Finally, search your code for brotliDecompress and createBrotliDecompress from node:zlib.
Ready to take the first step towards unlocking opportunities, realizing goals, and embracing innovation? We're here and eager to connect.