# Node2Shell (CVE-2026-111497): the Brotli Flaw in Node, Python, and Everything That Bundles It

> Amen Security Team · 2026-10-24T15:20:36.337Z · security

The week of October 21, 2026 gave the internet two headline vulnerabilities, but most of the attention went to only one of them. While everyone watched PHP, a single flaw in a compression library quietly put Node.js apps, Python environments, proxies, and service meshes on the same patch list. Its name is Node2Shell. Its CVE is CVE-2026-111497. And the uncomfortable part is not the flaw itself — it is how many places the same flawed code is hiding.
In 30 seconds
- CVE-2026-111497 is an out-of-bounds write in the Brotli decoder, a C library bundled into Node.js, Python packages, Bun, curl, Envoy, Istio, and more. Node.js rates it High and says it permits remote code execution.
- "HTTP2Shell" is the same CVE under a second nickname, not a second flaw.
- Fixed versions exist for every major home of the flaw — but the Python fixes shipped quietly, with no vulnerability mention in the release notes, so scanners may miss them. Finding every copy you bundle is the real job.

Contents: One decoder, half the internet's plumbing · The week it unfolded · Where the flaw actually lives · The Python fix nobody announced · Who should worry first · Find every Brotli you bundle · Four checks you can run today · Your week, in order · Five questions, answered straight · Related reading · Start with the copy you'd forget
One decoder, half the internet's plumbing
Brotli is a compression format. When a server sends you a web page, or your app fetches data from another service, the data is often squeezed with Brotli first and un-squeezed on arrival. The un-squeezing is done by a small, fast C library that a remarkable number of projects simply bundle inside themselves rather than writing their own.
CVE-2026-111497 is an out-of-bounds write in that decoder: specially crafted compressed data can make the decoder write past the memory it was given. Node.js rates the flaw High and says it permits remote code execution. Because decompression usually happens before any application login check — the server has to un-squeeze the request before it can read it — a crafted payload can reach native code early, in a place where a JavaScript error would never save you.
That is why the name matters less than the library. Call it Node2Shell, call it HTTP2Shell — both nicknames point at the same CVE, the same decoder, the same fix. If you chase the two names as two problems, you will patch one list and miss the other. There is only one list, and it is longer than the Node.js release notes suggest.
The sibling story from the same week is worth reading next to this one: [PHP2Shell: the October 2026 PHP flaws, and the 15-minute check for your website](https://amensecurity.ca/en/blog/php2shell-critical-php-vulnerability-canada-2026). Same week, different runtime, same lesson — the layer underneath your code needs its own patch.
The week it unfolded
Date (2026)
What happened

October 21
Node.js ships security releases 22.23.4, 24.22.1, and 26.12.1, fixing 10 CVEs — four rated High, three Medium, three Low in secondary coverage of the release. The headline fix is CVE-2026-111497.

October 21
Brotli ships fixed releases 1.2.1, 1.1.1, and 1.0.10; the same fix lands in Bun 1.4.4 and in the official Node.js Docker images.

October 22
A public proof of concept appears, and researchers report code execution on an unmodified Node.js 24.22.0 build in lab conditions.

October 23
OpenAI says it found the flaw during a red-teaming exercise, and notes it works in both directions: a malicious client against a server, and a malicious server against a client such as curl --compressed. The "HTTP2Shell" nickname starts circulating for the same CVE.

October 23, 22:00 UTC
The CVE is not in CISA's exploited-vulnerabilities file, and no in-the-wild exploitation has been reported. That is the honest status — it is not the same as safe.

Where the flaw actually lives
This is the table to check your stack against. A "fixed version" here means the release carrying the corrected decoder — anything older on the same line is still carrying the flaw.
Home of the flaw
Fixed version
Notes

Node.js 22.x
22.23.4
Also fixes TLS hostname-check bypasses (CVE-2026-105483, CVE-2026-106069) and a DNS truncation flaw (CVE-2026-105482).

Node.js 24.x
24.22.1
Same companion fixes as 22.x, plus bundled dependency updates.

Node.js 26.x
26.12.1
Same companion fixes as 22.x, plus bundled dependency updates.

Node.js 20.x and older
No fix
Node 20 reached end of life on April 30, 2026. The only move is up to 22, 24, or 26.

libbrotli (the C library itself)
1.2.1
Also patched as 1.0.10 and 1.1.1 for older lines.

Python package Brotli
1.2.1
Advisory PYSEC-2026-4322; GitHub advisory GHSA-9v8h-qqgm-4m35.

Python package brotlicffi
1.2.1.0
Advisory PYSEC-2026-4323.

Bun
1.4.4
Versions before 1.4.4 are affected.

curl / libcurl
Update the Brotli dependency to 1.2.1, or take a vendor fixed package
curl itself bundles nothing to patch in place — its Brotli comes from the dependency.

Envoy
1.40.0 / 1.39.3 / 1.38.6 / 1.37.8
Pick the fixed patch for the line you run.

Istio
1.29.9 / 1.30.6 / 1.31.2
Pick the fixed patch for the line you run.

The release also refreshes bundled dependencies (c-ares, OpenSSL, SQLite, Undici) and removes trust in the compromised eMudhra intermediate certificate — worth having, but none of it substitutes for the decoder fix.
The Python fix nobody announced
Here is the detail that makes this story different from a routine patch Tuesday. The Python fixes — Brotli 1.2.1 and brotlicffi 1.2.1.0 — were published quietly, with no vulnerability mention in their release notes. The advisories (PYSEC-2026-4322, PYSEC-2026-4323) exist, but a team that reads release notes, or leans on a scanner whose database has not caught up, can walk straight past them believing Python is unaffected.
That is a plausible way to end up patched in Node and still exposed in Python: the same decoder, in a second language, on the same server, with no announcement to trip your process. If your patch workflow starts from vendor announcements, add this one manually — check the installed versions directly (see the four checks below) instead of waiting for a feed to tell you.
Who should worry first
Not every Node server is remotely exploitable, and saying otherwise would be dishonest. Exploitation needs an application that processes attacker-controlled Brotli data through the vulnerable decoder. That puts these at the front of the queue:
- Servers that decompress request bodies. Express 5 and body-parser 2.x decompress Brotli request bodies, so a client can send a crafted Content-Encoding: br request straight at them.
- Apps that fetch from URLs others control. If your code calls fetch() on a user-supplied address, a malicious server can hand back crafted compressed data.
- Proxies, gateways, and ingestion services. Anything that squeezes or un-squeezes other people's traffic at volume.
- Compressed uploads and responses. Any path where compressed data arrives from outside your trust boundary.

Lower down the list, but not off it: internal services that only talk to each other. Several of the companion fixes protect the calls your code makes to other services, not just the requests it receives, and the eMudhra certificate removal touches every outbound HTTPS call. Patch those too — just patch the internet-facing ones first.
One more honesty note: updating the system Brotli library on a server does not patch a copy bundled inside a runtime or a package. Each bundled copy needs its own update, which is exactly why the inventory below matters more than any single upgrade command.
Find every Brotli you bundle
Patching one Node runtime is a version bump. Finding every copy of Brotli in your stack is the actual job — and it is the part most teams underestimate, because the copies do not live in one place. Work through these four hiding spots in order:
- Node runtimes — every one of them, not just the default. Changing the nvm default moves none of the others: pm2 entries (live and saved), the pm2 daemon itself, systemd units with a hard-coded PATH to an old install, and cron jobs pointing at an old binary by absolute path all keep running the old runtime until you move each one. Check the real binary of every running process, not the process name.
- Python environments. Every virtual environment, every deployment image, every data pipeline box: check the installed Brotli and brotlicffi versions directly. Remember the quiet release notes — do not trust a green scanner dashboard here until you have seen the version numbers.
- Containers. Rebuild images with --pull so they pick up the fixed base. The official node:22, node:24, and node:26 tags carry the fix; node:20, node:25, and node:18 will not get one. A redeploy of an old image is a redeploy of the flaw.
- Vendored copies. Libraries, SDKs, and appliances that bundle their own Brotli — Envoy and Istio sidecars, curl builds, anything with a third_party/brotli directory — each need their own fixed release, listed in the table above. If you cannot find a vendored copy's version, treat it as unpatched until proven otherwise.

Find every Brotli you bundle: runtimes → Python environments → containers → vendored copies.Upgrading one Node is a one-line change. Finding every copy of Brotli in your stack is the actual job — and the copies you forget are the ones that stay exposed.

Four checks you can run today
No new tooling needed. Run these on each server that runs your apps, not just your laptop:
- Check 1 — Node, everywhere it runs: node -v on the box, then the version behind each pm2 entry, each systemd unit, and each cron job. Anything below 22.23.4 / 24.22.1 / 26.12.1 on its line, or on Node 20 and older, goes on the patch list.
- Check 2 — Python, by version number: pip show Brotli brotlicffi in every environment. Below 1.2.1 / 1.2.1.0 means unpatched — regardless of what any advisory feed says.
- Check 3 — Containers, by base image: list your images' base tags and rebuild dates. Anything built on a pre-fix node tag, or on an image that has not been rebuilt with --pull since October 21, gets rebuilt.
- Check 4 — Vendored copies, by admission: search your dependency tree and appliances for bundled Brotli (Envoy, Istio, curl builds). Any copy whose version you cannot confirm is counted as unpatched until confirmed.

If all four checks come back clean, you are done — and you now have a list you can re-run next time a bundled library makes the news. If any check turns up a copy you did not expect, that is the whole point of the exercise.
If you want a second pair of eyes on the inventory — especially the Python environments and vendored copies, which are the ones teams most often miss — [a free assessment will map it with you, and you keep the list either way](https://amensecurity.ca/en/contact).
Your week, in order
- Today: patch every internet-facing Node, proxy, and gateway to a fixed version, and check the Python versions by hand.
- This week: work the four hiding spots above until the inventory is complete; rebuild containers with --pull and redeploy.
- Before you call it done: re-run the four checks and confirm the running processes — not just the installed packages — are on fixed builds. A package upgrade that leaves an old process running has changed nothing.
- After that: note the lesson for the next bundled-library flaw, because there will be one: the inventory you build this week is reusable, and the next flaw will not wait for your scanner to catch up.

Five questions, answered straight
Is Node2Shell only a Node.js problem?
No. Node.js is where it got its name, but the flaw is in the Brotli C decoder that Node bundles — and Python packages, Bun, curl, Envoy, and Istio bundle the same decoder. Patching Node alone leaves the other copies in place.
Is HTTP2Shell a second vulnerability?
No. HTTP2Shell is a nickname that started circulating in late October for the same CVE-2026-111497, not a second flaw with its own fix. One CVE, one decoder, one patch list.
Are we safe because nobody has exploited it in the wild yet?
No. As of October 23, 2026, no in-the-wild exploitation had been reported and the CVE was not in CISA's exploited-vulnerabilities file — but a public proof of concept exists and researchers have already demonstrated code execution in lab conditions. Absence of exploitation reports is a status update, not a safety guarantee.
Does a clean npm audit mean we are fine?
No. npm audit checks your packages, not the Node.js runtime itself and not a bundled C decoder. A perfectly clean audit says nothing about which runtime your processes are actually running.
We updated Node — are we done?
Only if the four checks above come back clean. Python environments, containers built on old base images, and vendored copies in proxies and meshes are all separate copies of the same flaw, and each needs its own fix.
Related reading
- [Your Microsoft 365 backup can be attacked too](https://amensecurity.ca/en/blog/microsoft-365-backup-security-checklist) — the October 2026 lesson in backup access: a connected app's stolen credential opened tenants, no password needed.
- [PHP2Shell: the October 2026 PHP flaws, and the 15-minute check for your website](https://amensecurity.ca/en/blog/php2shell-critical-php-vulnerability-canada-2026) — the sibling story from the same week, and the check that pairs with this one.
- [Clean up your Microsoft 365 licences and security settings](https://amensecurity.ca/en/blog/microsoft-365-cleanup-licences-security-settings) — the tenant hygiene that makes every other fix cheaper.

Start with the copy you'd forget
If you take one thing from this week, make it this: the copy of Brotli you forget is the one that stays exposed, and the copy most teams forget is not the Node runtime — it is the Python package with the quiet release notes, or the decoder vendored inside a proxy nobody has inventoried. Check those first, tonight, before the week moves on.
And if the inventory turns up more copies than you expected, our free assessment will map them with you — you keep the list either way, whether or not we ever work together again.
Trust box — sources & review
- Node.js October 2026 security releases (October 21, 2026): fixed versions 22.23.4, 24.22.1, 26.12.1; CVE-2026-111497 rated High, permits remote code execution; companion flaws CVE-2026-105482, CVE-2026-105483, CVE-2026-106069; Node 20 end of life April 30, 2026.
- Brotli fixed releases 1.2.1, 1.1.1, 1.0.10 (October 21, 2026); Bun 1.4.4; Envoy fixed 1.40.0 / 1.39.3 / 1.38.6 / 1.37.8; Istio fixed 1.29.9 / 1.30.6 / 1.31.2; curl/libcurl dependency update to 1.2.1 or vendor fixed package.
- Python advisories PYSEC-2026-4322 (Brotli 1.2.1) and PYSEC-2026-4323 (brotlicffi 1.2.1.0), GitHub advisory GHSA-9v8h-qqgm-4m35; fixes published with no vulnerability mention in release notes.
- Public proof of concept and lab code execution on Node 24.22.0 (October 22, 2026); OpenAI red-team finding, both-directions exploitation (October 23, 2026); CISA exploited-vulnerabilities status as of October 23, 2026, 22:00 UTC (not listed); no in-the-wild exploitation reported as of October 23, 2026.
- Reviewed: October 24, 2026. From Amen Security, a Winnipeg-based managed IT and web & app development team serving Canadian and US small and mid-sized businesses. No services, prices, partnerships, or certifications are claimed in this post beyond what the live site proves.

## Topic: Cybersecurity & compliance
- [Main guide](https://amensecurity.ca/en/services/cybersecurity.md)
- [Managed IT vs Break-Fix: Side-by-Side Comparison](https://amensecurity.ca/en/guides/msp-vs-break-fix.md)

---
Source page: https://amensecurity.ca/en/blog/node2shell-nodejs-brotli-rce-october-2026
Markdown version for AI agents · Amen Security
Email: info@amensecurity.ca
Phone: +1 (204) 514-3536
