‹ FeedCybersecurity
Cybersecurity

HTTP2Shell Beyond Node.js: Python, .NET and Bun

The Brotli decoder flaw is not only a Node.js problem. Here is where else the vulnerable copy ships, which versions fix it, and how to find every copy you run.

8 min read

Brotli is a way of making data smaller before it travels over the internet, and a large share of web traffic uses it. The code that unpacks Brotli data had a mistake that let specially crafted data write into memory it should not touch. Node.js was the first place anyone reported it, which is why it was first called Node2Shell. Then people checked other software that carries the same unpacking code, and found it in many places. This page lists those places and what to update. The complete PHP2Shell and Node2Shell guide covers the wider picture.

What is the vulnerability, exactly?

It is CVE-2026-111497, also called Node2Shell, HTTP2Shell and Broccoli2Shell. The flaw sits in Google's Brotli C decoder. Vendors name three possible results: a crash, a memory leak and, in some cases, remote code execution. The CVE record, assigned by Google, scores it 9.2 on CVSS 4.0.⁠1

The version numbers need careful reading, because the affected span and the fixed releases overlap numerically. The advisory says Brotli 1.0.3 through 1.2.0 is affected and that users should move to 1.0.10, 1.1.1 or 1.2.1.⁠13 Each fix belongs to its own release branch. Read it by branch:

Release branchAffectedFixed in
1.0.x1.0.3 through 1.0.91.0.10
1.1.x1.1.01.1.1
1.2.x1.2.01.2.1

So 1.1.1 is a fixed release, not an affected one, even though it sits numerically inside "1.0.3 through 1.2.0". Debian's tracker records the introducing change as version 1.0.3 and a separate fixing commit for each of the three branches.⁠8 The advisory states one range and three fixed releases. The branch-by-branch listing above is my reading of that text, and it matches the per-branch lists in Tanium's and Wiz's write-ups.⁠1⁠7 Upstream released the fixed versions on 21 October 2026. Tanium says the upstream fix was committed on 27 February with no advisory.⁠1

Reported CISA added it to the Known Exploited Vulnerabilities catalog on 27 October and gave no attack detail.⁠2 Reports put the federal deadline at 10 November.⁠3⁠4 Status as of 4 November 2026.

Despite the "HTTP2Shell" name, this has nothing to do with the HTTP/2 protocol.⁠1 The name changed because the bug lives in the library, not in one runtime.

Where else is it, and what do I update to?

Each copy of the decoder is fixed by whoever ships it. Read the "Note" column, because several rows depend on how the product is configured or built.

EcosystemWhat carries the copyFixed versionNote
Google BrotliThe upstream C library1.0.10 (1.0.x branch), 1.1.1 (1.1.x), 1.2.1 (1.2.x)Affected: 1.0.3 to 1.0.9, 1.1.0 and 1.2.0.⁠13⁠8
Node.jsThe runtime's bundled decoder22.23.4, 24.22.1, 26.12.1Node's advisory names node:zlib as the route.⁠5 See [[patch-node2shell-nodejs-22-24-26
PythonPyPI packages Brotli and brotlicffiBrotli 1.2.1; brotlicffi 1.2.1.0Affected from 1.0.3 up to those versions. Each virtualenv, CI runner and container has its own copy.⁠13⁠1
.NETBrotli support in System.IO.Compression8.0.33, 9.0.22, 10.0.14, 11 RC3From Microsoft's advisory. .NET Framework is not affected.⁠6
BunThe runtime's bundled decoder1.4.41.0.21 through 1.4.3 are affected. Executables built with Bun's compile option keep the old decoder until rebuilt.⁠7⁠1
EnvoyIts Brotli decompressor1.40.0, 1.39.3, 1.38.6, 1.37.8 (also 1.36.12 on the unsupported 1.36 branch)Affects deployments with the decompressor configured.⁠1⁠14
IstioEnvoy data plane1.31.2, 1.30.6, 1.29.91.29 reached end of life on 15 October.⁠7⁠14
Goandybalholm/brotliv1.2.7A separate implementation. Tanium says the likely effect is a crash.⁠1⁠7
DebianThe brotli source package12 (bookworm): 1.0.9-2+deb12u1. 13 (trixie): 1.1.0-2+deb13u1. Unstable (sid): 1.2.0-4.1Testing (forky) 1.2.0-4 was still listed vulnerable on 4 November. Debian's nodejs and python-brotlicffi use the system library.⁠8
UbuntuThe brotli, libbrotli1 and python3-brotli packages22.04: 1.0.9-2ubuntu0.1. 24.04: 1.1.0-2ubuntu0.1. 26.04: 1.2.0-3ubuntu0.1. 26.10: 1.2.0-4ubuntu0.1From USN-8956-1. 16.04 to 20.04 get fixes through Ubuntu Pro (USN-8956-2).⁠9⁠10
PHP for WindowsBundled Brotli in the Windows buildsRebuilt packages 8.5.12-1, 8.4.27-1, 8.3.36-1 and 8.2.35-1Reported by iTnews and The Hacker News.⁠15⁠11

How I checked these numbers: I read Microsoft's .NET post, Debian's tracker and a complete copy of Ubuntu's USN-8956-1 directly. Python's ranges come from the Brotli advisory record. The Bun, Envoy, Istio and Go figures come from those projects' advisories (Bun GHSA-663w-cv8g-jj2p, Envoy GHSA-3wvj-j6qm-62mr, Istio ISTIO-SECURITY-2026-007) as relayed by Tanium, Wiz and Field Effect, which agree with each other. I could not open the advisories themselves. Confirm those four rows against the projects' pages before you act on them.

Tanium reported on 24 October that Red Hat, SUSE, Amazon Linux 2023 and Fedora had no fix yet.⁠1 I did not recheck those, so read your vendor's tracker before assuming anything. Distribution fixes move quickly.

Common misreading: "I updated my system's Brotli package, so I'm fine." Only for software that uses the system library. Node.js bundles its own decoder, so a system update does not touch it.⁠5 Debian's tracker says its own nodejs package uses the system library, which is why the answer depends on how each program is built.⁠8 Microsoft says the same about self-contained .NET apps: a newer runtime on the host does not update the one bundled in the app.⁠6

Common misreading: "I'll update the brotli npm package." The Node.js flaw lives in the runtime binary, not in an npm package. Node's advisory places it in the decoder bundled with Node.js, so the fix is a Node.js release.⁠5

Common misreading: "The version string says 1.1.0, so I'm unpatched." Per Tanium, a fixed Node.js can still report an old Brotli version, so check the Node.js version itself.⁠1 Distributions also backport fixes without changing the headline number. Ubuntu's 24.04 fix is still 1.1.0, as package release 1.1.0-2ubuntu0.1.⁠9 Compare the full package release against the vendor advisory.

What does finding your copy look like?

Take a Python service that calls a partner API with requests. The response comes back Brotli-compressed, and the library unpacks it with its own Brotli copy. Per Tanium, urllib3, requests, httpx and aiohttp decode Brotli automatically whenever Brotli or brotlicffi is installed, and your code never has to import either.⁠1

So the first question is which copy your service has. In the environment that runs the service, ask pip:

python -m pip show Brotli brotlicffi

For a container, run the same command against the live container with docker exec <container> python -m pip show Brotli brotlicffi. The output gives each installed package's Version and Location. If the version is below 1.2.1 for Brotli, or below 1.2.1.0 for brotlicffi, that copy is yours to fix: upgrade it, regenerate your lockfile, rebuild the image and restart the service. If the package came from your Linux distribution (python3-brotli), the fix arrives through your distribution's update instead.

The same output has a Required-by line, but treat it carefully. It can be empty, and it does not reliably show why a package was installed. To find which dependency pulled Brotli in, use a dependency-tree tool such as pipdeptree in reverse mode for that package, or read your lockfile.

Nothing in this example touches the bug itself. The point is only that someone has to find the copy and own the fix.

How do I find every copy?

Brotli rarely shows up as an application, because it is compiled into other things. Tanium's list of where copies hide is a good checklist:⁠1

  • Node.js runtimes installed outside package managers, such as nvm, fnm, Volta and Homebrew.
  • Applications that ship their own Node.js, including desktop apps and developer tools.
  • Python environments, which often get Brotli as a transitive dependency of an HTTP client.
  • Bun binaries, including standalone executables.
  • System libbrotli packages.
  • Container images, which keep the runtime from the day they were built.
  • Go and Java libraries, proxies such as Envoy and Istio, and Electron apps.

For software that vendors Brotli's source, one clue is the new error name BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH, which the upstream fix adds.⁠12⁠13 Finding it in a copy suggests the fix is present. Not finding it is only a lead that the copy may be unfixed. Vendors can backport a fix under different code, modify the implementation or use another code path, so the name is not a vulnerability test. The vendor advisory, the patch diff or a verified fixed build is what settles it.

A software bill of materials (SBOM) helps here, and Tanium says scanners were slow to map this CVE to the Python packages.⁠1 So don't read a quiet scanner as proof that you have no copies.

Who is exposed in practice?

Exposure needs two things: a vulnerable decoder, and a path for attacker-controlled Brotli data to reach it. Both directions count. A server can decompress a request body, and a client or service can decompress a response from a server it fetches. Tanium names URL previews, webhook targets and crawlers as examples of the second direction.⁠1

Some products only reach the decoder when a feature is turned on. In .NET, ASP.NET Core request decompression and automatic HttpClient response decompression are not on by default.⁠6 Envoy and Istio are exposed only when a Brotli decompressor is configured.⁠1 For Node.js, Node's advisory names data an application decompresses with node:zlib.⁠5 Whether your web server is affected has its own page: whether your web server is affected.

Exposure through a feature being off is not the same as no copy. Patch the copies anyway. Features get turned on later.

What do I do?

  1. Inventory every copy, using the list above.
  2. Patch each ecosystem on its own schedule, using the table.
  3. Rebuild and redeploy container images, and rebuild self-contained apps and Bun executables.
  4. Restart every process, because a running process keeps the decoder it loaded.

If you can't update right away, Tanium lists interim steps: reject requests with Content-Encoding: br at your WAF or proxy, remove the Brotli decompressor filter in Envoy or Istio, and uninstall Brotli and brotlicffi in Python, which makes HTTP clients fall back to gzip.⁠1 These are bridges, not equivalents of patching. A WAF covers inbound requests only, not Brotli responses your own code fetches. For Express, see how an Express app decodes Brotli.

FAQ

No. The flaw is in Google's Brotli decoder, and Node.js, Python's Brotli and brotlicffi packages, .NET, Bun, Envoy, Istio and other software have shipped fixes for their own copies.

Only for software that uses the system library. Programs that bundle their own decoder, such as Node.js, Bun and self-contained .NET apps, need their own update.

Brotli from 1.0.3 up to but not including 1.2.1, and brotlicffi from 1.0.3 up to but not including 1.2.1.0. Check each virtualenv, CI runner and container, because each has its own copy.

Read it by release branch. On the 1.0.x branch, 1.0.3 through 1.0.9 are affected and 1.0.10 is fixed. On the 1.1.x branch, 1.1.0 is affected and 1.1.1 is fixed. On the 1.2.x branch, 1.2.0 is affected and 1.2.1 is fixed.

You've reached the end

HTTP2Shell Beyond Node.js: Python, .NET and Bun

The full article has comments, related reading and sharing.