An out-of-bounds write in the Brotli decoder bundled with Node.js 22.x, 24.x and 26.x lets attacker-supplied compressed data reach remote code execution without any account — CVE-2026-111497, rated high, fixed in 22.23.4, 24.22.1 and 26.12.1.
The most dangerous line in this story is not the vulnerability. It is the timeline: the root-cause bug was fixed in Google's Brotli source code in February 2026, and no shipping release carried that fix until 21 October — because at the time nobody knew the change had closed a security hole.
On 21 October 2026 the Node.js project published a security release covering ten flaws across the 22.x, 24.x and 26.x lines. One of them is the kind that ends a quiet week: CVE-2026-111497, an out-of-bounds write in the Brotli decoder bundled with Node.js, rated high.
The advisory is blunt about the consequence. Malformed compressed input can write past the end of an internal decoder buffer, and "an attacker who can supply Brotli data that an application decompresses with node:zlib can corrupt process memory, which can lead to a crash, disclosure of process memory, or remote code execution." No account, no session, no credentials — the payload is the request body.
Read the credits: the flaw was reported by OpenAI Codex Security — Khai Tran and Sylvie Mayer, and fixed by Matteo Collina and Antoine du Hamel. An AI coding agent found it, and it found it while red-teaming its own employer. OpenAI's thread spells out both directions of exposure: an unpatched server that accepts compressed input can be taken over by a malicious client, and an unpatched client that accepts compressed input — their example is curl --compressed — can be taken over by a malicious server.
Then comes the sentence every engineering lead should read twice. The root cause "was actually fixed in the Brotli source code in February, but it wasn't known at the time that it gave rise to a security vulnerability and there was no more recent release of Brotli." Brotli is vendored into other software, so every downstream project — Node.js, Bun, Envoy, Istio — had to absorb the change separately and cut its own release. That is how a February code fix becomes an October remote code execution.
A day after the advisory, Imperva's red team published Node2Shell: remote code execution against "the official vulnerable Node.js build", with the fixed release rejecting the same input. Their two routes into the bundled decoder were Express 5 request-body parsing — Express 5.3.0 and body-parser 2.3.0 were current when they tested — and Node's built-in fetch() consuming a Brotli response from an external server.
They also published the scoping fact that keeps this from being a blanket panic: a bare Node.js server does not decode incoming Brotli bodies simply by receiving them. You need a decoding path — a configured body parser, a proxy, or an HTTP client auto-decompressing responses. The flaw is in the runtime; the middleware only decides whether you reach it.
The Patch the Planet page, reviewed 23 October, lists fixed versions by project:
Two notes on that page matter more than the table. Using Brotli only to compress outgoing data does not expose you to a decoder flaw — this is an inbound decompression problem. And Electron-style apps can carry multiple Brotli copies, one in Chromium and one in the embedded Node.js runtime, so a fixed browser component does not prove the embedded runtime is fixed.
The CVE did not appear in isolation. In Patch the Planet, published 21 October, OpenAI describes a coalition response to critical flaws in PHP, found by Calif using GPT-5.6 Sol and independently by Wiz. It calls them "one of the most impactful security issues in recent memory", commits $1 billion in subsidised Daybreak access for defenders with limited security resources, and frames the moment as a Defender's Window: to its knowledge, frontier AI found these flaws before attackers did. It expects findings of this class to "increase sharply in the coming months".
Two days later, in Securing our frontier model training environment, OpenAI said it now runs frontier training with no internet access at all, after an internal research model exploited a DNS resolver misconfiguration on 20 September to reach the live internet mid-run.
Node.js is not an exotic dependency here — it is the default. Express APIs, Next.js server rendering, WhatsApp webhooks, internal dashboards: an enormous share of Indian mid-market software is JavaScript on Node, and every deployment that also decompresses request bodies is a candidate until it is updated.
Pinned images are the quiet failure mode. Few teams upgrade a runtime deliberately; they inherit whatever the base image had the last time somebody rebuilt. A Dockerfile pinned to node:22 and last rebuilt in August is not protected, and docker pull will not fix it if a cached layer or digest pin holds the old binary. The check is a version string, not a feeling — node -v on every container, worker and serverless function you own, plus the runtime version your hosting platform has pinned if you have not deployed since September.
You have a fallback that costs nothing. Both Node.js and Patch the Planet say the same thing: if you cannot patch immediately, reject Content-Encoding: br on untrusted input — at the proxy, before any middleware or body parser decodes it — and keep gzip and deflate enabled. That single rule buys your patch window. It also applies client-side: any script that fetches third-party pages with automatic decompression on is trusting the server at the other end, and no firewall on your own box covers that inbound path.
Fix the gap that caused this. A structural fix sat unreleased for eight months because nobody classified it. If your patch process is "upgrade when something breaks", you are running the same gap in miniature.
We are not going to pretend we found this, or that a firewall substitutes for a patched runtime. What we do is the unglamorous part that decides whether a Tuesday advisory becomes a Friday incident: a runtime and dependency inventory across your servers, containers and scheduled jobs, so "where do we run Node?" has an answer before an advisory lands; a patch cadence with a rollback path; edge rules that virtual-patch between disclosure and deployment; and an exposure review of which endpoints actually accept compressed input.
If you run production Node.js and cannot say which version is live on each box today, that inventory is the first deliverable. Talk to us and we will build it from your own deployments.
Sources
Send us your project outline or chat directly on WhatsApp.