HTTP2Shell Brotli Vulnerability Explained: How One Decoder Flaw Spread From Node.js to Python, Bun and Envoy (World Tech)

http2shell brotli vulnerability explained — server racks in a data center (illustrative)
Image: Wikimedia Commons / Marián Hubinský (freely licensed) — server racks at CERN (illustrative; the flaw lives in the shared Brotli decoder inside servers and runtimes everywhere, not in any one machine).

TL;DR — http2shell brotli vulnerability explained: CVE-2026-111497, an out-of-bounds write in Google's Brotli decoder, started as a Node.js flaw on 21 October 2026 and within days was found in Python packages, Bun, Envoy and Istio — because they all bundle the same C decoder. No attacks in the wild are confirmed yet, but the fixes are out, and your scanners may not flag the Python ones, so check by hand.

📌 KEY HIGHLIGHTS

  • The flaw: CVE-2026-111497 — an out-of-bounds write in Google's Brotli decoder, versions 1.0.3 to 1.2.0. Google rates it 9.2 critical (CVSS 4.0); Node.js rates it High.
  • Why it spread: Brotli is a shared C library. Every program that bundles it — Node.js, Bun, Python packages, Envoy, curl — needed its own fix, on its own schedule.
  • Code execution shown: Imperva's researchers ran attacker code on an unmodified Node.js 24.22.0 build in a lab. The exploit was not released, and no real-world attacks are confirmed.
  • The Python trap: if the Brotli or brotlicffi package is installed, Python HTTP clients decode Brotli responses automatically — even if your code never imports Brotli.
  • The scanner gap: as of 23 October, pip-audit, Dependabot and Safety did not reliably flag the Python packages. Check installed versions manually.

What happened?

On 21 October 2026, Node.js shipped security releases 22.23.4, 24.22.1 and 26.12.1, fixing ten vulnerabilities. The headline flaw was in the Brotli decoder Node.js bundles: malformed compressed input could write past the end of an internal decoder buffer, corrupting process memory and potentially allowing remote code execution. Our Node.js October security release guide covered that release the same day.

Then the story grew — fast. On 22 October, Imperva's Red Team, which coined the name Node2Shell, demonstrated code execution on an official Node.js 24.22.0 build for Linux on ARM64, delivered both as a fetched response and as an Express request body. The same day, researchers showed the PyPI packages Brotli and brotlicffi carry the same flaw, and the name began to change: Python2Shell, then, from late 23 October, HTTP2Shell — because the bug reaches any stack that decodes Brotli over HTTP. By 24 October, fixed releases had landed for Bun, Envoy, Istio and the operating-system packages, and the full blast radius was clear. This post covers that widening — the part the Node.js release alone does not tell you.

HTTP2Shell brotli vulnerability explained: how one decoder breaks everything

Brotli is Google's compression format for shrinking web traffic, and its decoder is written in C and reused everywhere. The bug sits in a function called DecodeBlockTypeAndLength, which handles the points where a Brotli stream switches between Huffman trees. In vulnerable versions, that function returns a plain true/false value, and "false" can mean two different things: "this stream is malformed" or "I need more input". On the decoder's fast path, the return value was discarded entirely. A crafted stream could therefore declare a block type, exhaust that block's length, and force a switch the stream's own structure ruled out — and the decoder, instead of stopping with a format error, kept going in a corrupted state and wrote past a small internal buffer.

That is why the flaw works in both directions, as OpenAI's Codex Security team — Khai Tran and Sylvie Mayer, who reported it — describes it: an unpatched server that accepts compressed input can be taken over by a malicious client, and an unpatched client that accepts compressed input (such as curl with compression enabled) can be taken over by a malicious server. OpenAI found the flaw in February 2026, and the change that fixes it was committed to Brotli's source code on 27 February — but nobody recognised it as a security issue at the time, and no Brotli release carried it until 21 October. Every project that bundles Brotli therefore spent eight months exposed without knowing it.

http2shell brotli vulnerability explained — rear of a server rack with cables and LEDs (illustrative)
Image: Wikimedia Commons, CC0 — the rear of a server rack, cables and status LEDs (illustrative of the server infrastructure running the affected runtimes).

Who is affected: the fix table

A program is exposed only if it decodes Brotli data that someone else controls. For Node.js and Bun, that happens when built-in fetch() reads a response sent with Content-Encoding: br, or when request-body code such as Express 5 and body-parser 2 unpacks a Brotli upload. A plain Node.js HTTP server does not decode request bodies on its own. Envoy and Istio are affected only when Brotli decompression is configured. In Python, the risk is sneakier: once the Brotli or brotlicffi package is installed, HTTP clients such as requests, urllib3, httpx and aiohttp decode Brotli responses on their own.

ProductAffected versionsFixed inExposed when
Google Brotli (C library)1.0.3 to 1.2.01.0.10, 1.1.1, 1.2.1Code decodes untrusted Brotli
Node.js22.x, 24.x, 26.x before the fix; 20.x and older (end of life)22.23.4, 24.22.1, 26.12.1fetch() of a br response, or Express/body-parser br bodies
Bun1.4.3 and earlier1.4.4fetch() of a br response, or node:zlib
Python Brotli1.2.0 and earlier1.2.1Installed, and an HTTP client decodes br
Python brotlicffi1.2.0.x and earlier1.2.1.0Installed, and an HTTP client decodes br
Envoy1.39.2, 1.38.5, 1.37.7, 1.36.111.40.0, 1.39.3, 1.38.6, 1.37.8Only if the Brotli decompressor is configured
Istio1.31.0–1.31.1, 1.30.0–1.30.5, 1.29.0–1.29.81.31.2, 1.30.6, 1.29.9Only if Brotli decompression is enabled
curl / libcurlBuilds linked against affected BrotliUpdate the Brotli dependency to 1.2.1 or a vendor-fixed packageCompressed responses decoded by curl

Two honest limits. First, code execution has been demonstrated only on the one Node.js build Imperva tested — it took several tries, was not tested on every architecture, and the exploit was not released. Research on the Python packages did not try to reach code execution at all. Second, fixes are still rolling out vendor by vendor: Debian fixed its brotli package for Debian 13 on 23 October, while Amazon Linux 2023 still listed its brotli and Node.js 24 packages as pending a fix as of 22 October. Check your own vendor; a missing vendor fix is not proof you are safe.

Why it matters for India readers

India runs a huge share of the world's Node.js and Python workloads — product startups, IT services firms, and data teams whose scrapers, webhook handlers, URL-preview services and AI agents fetch untrusted URLs all day. That outbound-fetch path is exactly the blind spot here: a web application firewall can block crafted Brotli request bodies coming in, but it cannot see responses your own code fetches from other servers. Vercel, which added firewall rules on the day of disclosure, says so itself — those rules do not cover "responses your functions fetch from other servers". For that path, only updating the runtime or library closes the hole.

The scanner gap makes it worse for Indian teams that rely on automated dependency checks. The CVE record names Google's Brotli repository, not the PyPI packages, and GitHub's advisory initially listed no affected package — which is what Dependabot reads. The PyPI advisories PYSEC-2026-4322 and PYSEC-2026-4323 were only added on 23 October. If your pipeline said "all clear" before that, it was reading an incomplete map. The fix is unglamorous but effective: check installed versions by hand, starting with the services that call outside servers or accept compressed request bodies.

Should you care?

✅ Yes — if you run Node.js, Python services, Bun, Envoy or Istio: update to a fixed version now, then restart the service and rebuild container images, because a running process keeps the old decoder until it restarts. ⏳ Check by hand even if scanners are green: the Python packages were invisible to pip-audit, Dependabot and Safety until 23 October. 🔍 Honest caveat: no attacks in the wild are confirmed and code execution was shown on one lab build only — but the flaw is public, the fix is a version bump, and there is no reason to stay on a vulnerable decoder.

What to do now: checks and workarounds

Check Node.js and Bun: run node --version (affected if below 22.23.4, 24.22.1 or 26.12.1, or on an end-of-life line) and node -p "process.versions.brotli" to see the Brotli version bundled into your exact Node binary. For Bun, bun --version is affected at 1.4.3 or earlier. Inside a container image, run the same checks in the image — a package inventory can miss a bundled runtime. Check Python: run pip show Brotli brotlicffi in every environment and every container image, find what pulls the packages in with pipdeptree -r -p Brotli, and search lockfiles with grep -i brotli poetry.lock uv.lock requirements*.txt. Check system libraries: dpkg -l | grep -i brotli on Debian/Ubuntu, rpm -qa | grep -i brotli on RHEL/Fedora.

If you cannot update yet: reject incoming requests with Content-Encoding: br before any proxy or parser decodes the body; turn off automatic Brotli decoding in HTTP clients and reject Brotli responses before they are decoded; in Python, uninstall the Brotli and brotlicffi packages where Brotli support is optional so clients fall back to gzip and deflate. Note that dropping br from the Accept-Encoding header alone does not help, because a server can send Brotli whatever the client asks for. For Node.js, no workaround has been published — updating the runtime is the only fix. And remember the lesson of the LiteLLM supply-chain attack: the transitive dependency you never chose is the one your tooling sees last — which is also why the Bun 1.4.4 release mattered beyond its features.

FAQs

Is HTTP2Shell being exploited in the wild?
No attacks in the wild had been confirmed as of 24 October 2026, and the flaw is not in CISA's Known Exploited Vulnerabilities catalog — CISA's 23 October assessment recorded exploitation as "none". Imperva's exploit was demonstrated in a lab and has not been released, but the flaw itself is public, so patching now is the safe move.

Is my Python app affected if I never import Brotli?
Possibly, yes. If the Brotli or brotlicffi package is installed at all, HTTP clients such as requests, urllib3, httpx and aiohttp decode Brotli responses automatically. Upgrade Brotli to 1.2.1 and brotlicffi to 1.2.1.0, or uninstall them where Brotli support is optional.

Will pip-audit or Dependabot flag the Python packages?
Not reliably yet. As of 23 October, the CVE record, OSV and the GitHub Advisory Database did not map the CVE to either PyPI package, so scanners missed them. The PyPI advisories PYSEC-2026-4322 and PYSEC-2026-4323 were added on 23 October, but check installed versions manually anyway.

Is HTTP2Shell a different flaw from Node2Shell?
No. Node2Shell, Python2Shell, HTTP2Shell and Broccoli2Shell are all names for the same vulnerability, CVE-2026-111497, in Google's Brotli decoder. The names track how widely the flaw's reach was understood: first Node.js, then Python, then every HTTP stack that decodes Brotli.

Which versions fix CVE-2026-111497?
Node.js 22.23.4, 24.22.1 or 26.12.1; Bun 1.4.4; Python Brotli 1.2.1 and brotlicffi 1.2.1.0; native Brotli 1.0.10, 1.1.1 or 1.2.1; Envoy 1.40.0, 1.39.3, 1.38.6 or 1.37.8; Istio 1.31.2, 1.30.6 or 1.29.9. Node.js 20 and older are end of life and receive no fix — move to a supported line.

Takeaway: HTTP2Shell is a reminder that the most dangerous bugs hide in shared plumbing, not in your own code. One C decoder, eight months unnoticed, and a version bump in a dozen ecosystems is the price of finding it. Update, restart, rebuild — and check the Python packages by hand.

Follow World Tech on TechByCountry for tomorrow's 6 PM update.

📸 Get tech in the last 24 hours on Instagram — follow @_techinlast24hrs for daily posts (9 AM–9 PM) and reels at 12:30 PM & 8:30 PM.

Sources

Comments