Supplying the Ministry of Defence? Which DCC level your contracts need, and what to do next.

Read it

Zarco / Blog / Advisory

HTTP2Shell (CVE-2026-111497): how to find, patch and contain it

A technical guide for developers and IT teams: the fixed versions for Node.js, Bun, .NET, Python, Envoy, Istio and Brotli itself, how to find every copy in your stack, how to stop decoding untrusted Brotli while you patch, and how to prove the fix is live.

Our HTTP2Shell advisory explains what the Brotli flaw means for a business. This guide is for the people doing the work. It covers the fixed versions, how to find every copy of the vulnerable decoder in your stack, how to stop untrusted Brotli being decoded while you patch, and how to confirm the fix is live.

It reflects public information on 26 October 2026.

At a glance

  • The flaw: an out-of-bounds write in Google’s Brotli decoder (c/dec/decode.c), versions 1.0.3 to 1.2.0. When a crafted stream makes an invalid block switch, the decoder gets back an ambiguous result that its fast path ignores. It carries on with corrupted state and writes past its buffer (CWE-252, leading to CWE-787).
  • How it is reached: only by decoding Brotli data someone else controls. That means a request body sent with Content-Encoding: br, a response from a server you don’t control, or a Brotli-compressed file.
  • Impact: a crash, leaked memory or, at worst, code execution. Imperva has run its own code on an unmodified Node.js 24.22.0 build for Linux on Arm after several attempts. Nobody has shown the same on other software.
  • Severity: 9.2 on CVSS 4.0 from Google, which assigned the CVE. Red Hat and Microsoft (for .NET) rate it 8.1, and Node.js rates it high.
  • Exploitation: none reported as of 26 October. It is not in CISA’s catalogue of known exploited vulnerabilities (version 2026.10.23), and CISA’s own assessment on 23 October recorded exploitation as “none”.

Sources: PYSEC-2026-4322 at OSV, GitHub advisory GHSA-9v8h-qqgm-4m35, Microsoft’s .NET advisory, Red Hat: CVE-2026-111497, The Hacker News, 26 October 2026 and the CISA Known Exploited Vulnerabilities catalogue.

Fixed versions

Update to a fixed release, or to a later one in a supported line.

Software Fixed in Exposed when
Google Brotli (C library) 1.0.10, 1.1.1, 1.2.1 Anything built on it decodes untrusted Brotli
Node.js 22.23.4, 24.22.1, 26.12.1 fetch() reads a Brotli response, Express 5 or body-parser 2 decodes a Brotli request body, or code passes untrusted data to the zlib Brotli functions. Node.js 20 and older are end of life and get no fix
Bun 1.4.4 fetch() reads a Brotli response, or code uses node:zlib on untrusted data
.NET 8.0.33, 9.0.22, 10.0.14 (11.0 RC3) Only where Brotli decompression is switched on in ASP.NET Core or HttpClient, or BrotliStream or BrotliDecoder decode untrusted data
Python Brotli (PyPI) 1.2.1 The package is installed: requests (through urllib3), httpx with the brotli extra and aiohttp then decode Brotli automatically
Python brotlicffi (PyPI) 1.2.1.0 As for Brotli
Envoy 1.40.0, 1.39.3, 1.38.6, 1.37.8 Only if a Brotli decompressor filter is configured. 1.36.12 has the fix, but 1.36 is unsupported
Istio 1.29.9, 1.30.6, 1.31.2 Only if an EnvoyFilter adds Brotli decompression. 1.29 is end of life
cdxgen 13.5.0, 12.8.9 Standalone binaries and images scan untrusted input
curl and libcurl Your vendor’s build with a fixed Brotli You use --compressed, or libcurl has response decoding switched on

Operating-system packages move at their own pace. Debian has fixed its brotli package for Debian 13 and 12 (DSA-6582-1 and DLA-4855-1), and Amazon Linux 2023 shipped fixed brotli and Node.js 24 packages on 24 October. Ubuntu still listed its packages as needing evaluation, and Red Hat’s bulletin RHSB-2026-015 tracks its fixes. Vendors often backport a fix without changing the upstream version number, so go by the vendor’s advisory rather than the version string.

Some common setups are not affected. Apache’s mod_brotli only compresses responses, and Nginx doesn’t decode Brotli by default. A plain Node.js HTTP server doesn’t decode request bodies on its own. Serving Brotli-compressed pages uses the encoder, not the vulnerable decoder.

Sources: Patch the Planet: Brotli guidance, Node.js security releases, 21 October 2026, Microsoft’s .NET advisory, PYSEC-2026-4322 and PYSEC-2026-4323, the Debian security tracker, Ubuntu: CVE-2026-111497, Red Hat RHSB-2026-015, The Hacker News and Aikido.

Find every copy

Check what is running, not what your lockfile says. These commands report the versions to compare with the table above.

# Runtimes, on each host and inside each image
node --version
bun --version
dotnet --list-runtimes
docker run --rm --entrypoint node <image> --version

# Python, in every environment, virtualenv and image
python -m pip show Brotli brotlicffi
pipdeptree -r -p Brotli          # what pulls it in
grep -i brotli poetry.lock uv.lock requirements*.txt

# The system library, and the Brotli that curl links against
dpkg -l | grep -i brotli         # Debian and Ubuntu
rpm -qa | grep -i brotli         # RHEL, Fedora and Amazon Linux
curl -V                          # brotli appears in the version and Features lines

# Envoy and Istio: is a Brotli decompressor configured?
kubectl get envoyfilters -A -o yaml | grep -n "brotli.decompressor"
istioctl proxy-config listeners <pod> -n <namespace> -o json | grep -n "brotli.decompressor"

Then look where copies hide:

  • Container images, including their base images and images built months ago that are still running.
  • Self-contained and NativeAOT .NET apps, and executables compiled with Bun. Each carries its own runtime, so a server-wide update doesn’t reach them.
  • Serverless functions and managed platforms. The provider chooses the runtime build, so confirm which one your functions run and redeploy if needed. Vercel, for example, added firewall rules on the day of disclosure but says they don’t cover responses your functions fetch from other servers.
  • CI runners, build agents and developer laptops, where Python environments accumulate.
  • Desktop software. Electron apps can bundle more than one copy of Brotli, in Chromium and in Node.js. Red Hat also lists Firefox and Thunderbird, which embed their own decoder. Mozilla had not published a fix for this CVE by 26 October, so keep browsers on automatic updates and watch for one.
  • File handling. Anything that opens Brotli files or WOFF2 fonts from outside your organisation is in scope too.

Advisory databases now cover the Python packages, through PYSEC-2026-4322, PYSEC-2026-4323 and the GitHub advisory that Dependabot reads, so pip-audit, OSV-Scanner and Dependabot should flag them. A scanner only sees what it scans, though. It won’t see a runtime baked into an image or a decoder bundled inside a product.

Sources: Patch the Planet: Brotli guidance, Microsoft’s .NET advisory, Red Hat RHSB-2026-015, Mozilla security advisories, GitHub advisory GHSA-9v8h-qqgm-4m35 and The Hacker News.

Stop decoding untrusted Brotli while you patch

If you can’t patch everything today, cut off the route to the decoder. Three rules apply whatever your stack:

  1. Block every decoding path, not just one. Blocking Brotli at the edge does nothing for responses your servers fetch, and a disabled proxy filter passes the encoded bytes on to the next decoder.
  2. Don’t rely on Accept-Encoding. Removing br from what a client asks for doesn’t stop a malicious server sending it.
  3. Reject before decoding. Checking Content-Encoding after a client has read and decoded the body is too late.

Then, by stack:

  • Incoming requests, on any stack: at the proxy, load balancer or first middleware, reject any request whose Content-Encoding includes br with HTTP 415, before a body parser runs. Match case-insensitively, including in lists such as gzip, br, and cover routes that reach the origin directly.

  • Node.js and Bun: the built-in fetch() decodes Brotli responses automatically and has no standard switch to stop it, so updating the runtime is the only fix for responses your code fetches. Until then, pause features that fetch from servers you don’t control, such as webhooks, link previews, crawlers and “import from URL”. In Express, put the encoding check before every body parser. Setting inflate: false on body-parser is a blunt fallback that rejects all compressed bodies.

  • Next.js: the built-in image optimiser fetches remote images, so set images.unoptimized: true until Node.js is patched. It doesn’t protect other server-side fetches.

  • Python: where Brotli support is optional, uninstall Brotli and brotlicffi and remove extras such as httpx[brotli] that would reinstall them. Then regenerate your lockfiles and rebuild. Clients fall back to gzip and deflate, but a server that sends Brotli anyway may then cause an error. Where you need finer control, read responses without automatic decoding and check Content-Encoding first.

  • .NET: nothing is exposed by default. If you have switched Brotli on, take it out:

    • drop "br" from the providers in AddRequestDecompression in ASP.NET Core;
    • set AutomaticDecompression to GZip | Deflate on your HttpClient handler;
    • stop passing untrusted data to BrotliStream or BrotliDecoder.

    Microsoft warns against adding decompression settings if you weren’t already using them.

  • curl: don’t use --compressed against servers you don’t control until your curl links a fixed Brotli. In libcurl, response decoding stays off unless CURLOPT_ACCEPT_ENCODING is set.

  • Envoy and Istio: remove the Brotli decompressor filter, or disable it in both the request and response directions, and keep your gzip and zstd filters. Remove any runtime key that could switch it back on, and check the effective configuration on every gateway and sidecar.

Keep these controls in place until every component is patched and verified.

Sources: Patch the Planet: Brotli guidance, Microsoft’s .NET advisory, Aikido and The Hacker News.

Prove the fix is live

  1. Check the running process. Run the version commands inside the running container or pod, for example kubectl exec <pod> -- node --version, not just in your build.
  2. Rebuild and restart everything that embeds a copy. That means images, self-contained and NativeAOT .NET apps, Bun executables and Python wheels, then a restart of every service, worker, scheduled job and replica. A process that started before the update keeps the old decoder until it restarts.
  3. Test your temporary blocks. Send a harmless request with Content-Encoding: br to each protected endpoint and confirm it is rejected before anything decodes it. Then confirm that gzip still works.
curl -i -X POST -H "Content-Encoding: br" --data-binary "test" https://your-service.example/endpoint
# Expect HTTP 415 (or your proxy's rejection), not a 2xx response or a parser error
  1. Check again as vendors catch up. Ubuntu’s packages, Red Hat’s errata and any browser fixes were still in progress on 26 October, and more bundled copies may surface.

Why one fix took eight months

The root cause was fixed in Brotli’s source code on 27 February, in commit 0ed4268. Nobody recognised it as a security fix at the time, and no Brotli release carried it until 21 October. Every project that bundles its own copy of the decoder has to ship its own update, which is why fixes are still arriving product by product. OpenAI’s Codex Security team, Khai Tran and Sylvie Mayer, reported the flaw.

Sources: The Hacker News, Node.js security releases and Brotli 1.2.1 release notes.

FAQ

Is a website that serves Brotli-compressed pages affected?

Not through that alone. Compressing responses uses the Brotli encoder. The same server is exposed only if it also decodes Brotli request bodies or fetches content from servers it doesn’t control.

Does a web application firewall protect us?

Partly. A rule that rejects Brotli-encoded requests covers inbound traffic, but not the responses your applications fetch from other servers. Vercel, which added firewall rules on the day of disclosure, makes the same point.

Do we need to import Brotli to be affected in Python?

No. If Brotli or brotlicffi is installed, urllib3 (and so requests), httpx with the brotli extra and aiohttp use it automatically.

We use .NET. Are we exposed?

Only if your code switches on Brotli decompression in ASP.NET Core or HttpClient, or decodes untrusted data with the Brotli APIs. Update the runtime anyway, and rebuild self-contained and NativeAOT apps.

Is it being exploited?

No attacks in the wild had been reported by 26 October. Public proof-of-concept code crashes vulnerable decoders, and Imperva has shown code execution on one Node.js build. Treat it as urgent wherever untrusted Brotli can reach a decoder.

How we can help

  • Find where untrusted Brotli reaches you. A Security Posture Assessment maps what you expose to the internet, including services that accept compressed request bodies, and confirms what is really reachable.
  • Check your product. An Application & API Penetration Test covers the routes where your application accepts or fetches data from outside and, with read-only source access, the dependencies behind them.
  • Prove the fix. Every engagement includes a retest, so “patched” means confirmed on the running system, not assumed.
  • Catch the next one. With Continuous Agentic Red Teaming, critical disclosures are checked against your scope as they are published.

This guide reflects public information on 26 October 2026. We will update it as vendors ship more fixes.

→Contact

Tell us what you need.

A tender deadline, an insurer's questionnaire, a system you want tested, or a job you'd like AI to take off your team's hands. We reply within one working day, UK hours.

  • A 30-minute first call, with no obligation
  • A fixed quote before any work starts
  • A UK-based team you can talk to directly