Brotli CVE-2026-111497 (Node2Shell / HTTP2Shell): Affected Versions, Fixed Releases, and Workarounds
What happened with CVE-2026-111497
CVE-2026-111497 is a critical out-of-bounds write in Google's Brotli decoder, present in Brotli versions 1.0.3 through 1.2.0 on all platforms. Node.js disclosed it as "Node2Shell" on the week of October 21, 2026, and the name expanded to "HTTP2Shell" as security researchers confirmed the same decoder bug affects Python packages, native libbrotli, curl, Bun, Envoy, Istio, Git for Windows, and a long tail of applications that bundle a Brotli decoder. The fix ships in Brotli 1.2.1 (plus backports 1.0.10 and 1.1.1), and any library or application that statically links or bundles a vulnerable Brotli decoder needs its own release.
Aikido published the aggregated advisory on October 23, 2026, noting that patches were still landing across the ecosystem and that vendors were announcing affected components in sequence.
The technical root cause: an ambiguous boolean in DecodeBlockTypeAndLength()
The flaw sits in DecodeBlockTypeAndLength(), the Brotli decoder function that handles block switches, which are the points where a Brotli stream changes which Huffman tree it uses. In vulnerable versions the function returns a plain boolean, so BROTLI_FALSE can mean either "this stream is malformed" or "I need more input." Callers cannot distinguish the two cases, and on the fast decode path the decoder discards the return value entirely.
A crafted stream can declare a single block type and then exhaust that block's length, forcing a block switch that cannot succeed. The decoder then either reports that it needs more input for a stream that is actually complete, or keeps decoding with the block state it already had. That second path produces the out-of-bounds write.
The upstream fix, google/brotli commit 0ed4268, makes the function return an error code and introduces a new error value, BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH (-17). Decoding now stops on a format error on both the safe and fast paths. Differential analysis of the Brotli 1.2.0 and 1.2.1 source distributions found that 1.2.1 differs only in the version bump and the decoder changes from that commit.
The CVE record pairs CWE-252 (unchecked return value) with CWE-787 (out-of-bounds write) and assigns a CVSS v4.0 score of 9.2 (Critical).
Attack impact: memory leak, crash, or remote code execution in both directions
CVE-2026-111497 lets a remote, unauthenticated attacker send a crafted Brotli-compressed stream that corrupts memory, leaks sensitive data, crashes the process, or potentially achieves arbitrary code execution. The flaw was reported as unauthenticated remote code execution that works in both directions, meaning a malicious client can take over an unpatched server and a malicious server can take over an unpatched client that accepts compressed responses.
Two data paths expose the decoder:
- Outbound requests. An application fetches a Brotli-encoded response from a server an attacker controls, for example through a webhook delivery, URL preview, crawler, or "fetch this URL" feature.
- Inbound requests. A framework or middleware decodes a request body sent with
Content-Encoding: br, which is the Python equivalent of the Express 5 case in Node.js.
The Hacker News reported no exploitation in the wild as of October 22, 2026.
Fixed versions for CVE-2026-111497
Every project that bundles Brotli has to ship its own update, because the root cause was fixed upstream in source but no upstream release shipped the fix until now. Fixed releases reviewed on October 23, 2026:
| Project | Patch status | Fixed versions | Notes |
|---|---|---|---|
| Node.js | Patch available | 22.23.4, 24.22.1, 26.12.1 | Use a supported release line |
| Bun | Patch available | 1.4.4 | Includes Brotli 1.2.1 |
| Envoy | Patch available | 1.40.0, 1.39.3, 1.38.6, 1.37.8 | 1.36.12 also includes the fix, but 1.36 is unsupported |
| Istio | Patch available | 1.29.9, 1.30.6, 1.31.2 | 1.29 is end of life; move to a supported line |
| Google Brotli (upstream) | Patch available | 1.0.10, 1.1.1, 1.2.1 | Choose the fixed release for the matching library branch |
| Python: Brotli (PyPI) | Patch available | 1.2.1 | Release notes do not mention the CVE |
| Python: brotlicffi (PyPI) | Patch available | 1.2.1.0 | Release notes do not mention the CVE |
Additional guidance from the advisory:
- curl / libcurl: update the Brotli dependency to 1.2.1, a patched older release, or the vendor's security-fixed package. Bundled or statically linked copies require an updated application build.
- Operating-system packages: install the vendor's security update. Vendors may backport the fix without changing the upstream version number.
- Other HTTP servers, reverse proxies, API gateways, and HTTP clients: update the affected runtime or the Brotli library they use. Where Brotli is bundled into a product, install the product vendor's release that explicitly addresses this CVE. For managed services, confirm remediation with the provider.
After upgrading, update dependency locks, rebuild affected applications and container images, redeploy, and restart services, then verify that running workloads use the patched components.
Why one Brotli bug affects so many languages and products
Python, Node.js, C++, libbrotli, Envoy, and Bun are all affected because they compile or bundle the same C Brotli decoder. There is only one implementation of the decoding logic, so a single memory-safety defect propagates into every runtime that embeds it.
Two PyPI packages, Brotli and brotlicffi, compile the same vulnerable decoder that Node.js bundles, and Brotli has 82.8 million downloads per month. HTTP clients such as urllib3 (and therefore requests), httpx with the brotli extra, and aiohttp load either package automatically when it is present, and decode Brotli responses without the application importing Brotli directly. Scrapy and other packages install Brotli as a dependency. As a result, a Python application can be exposed without containing a single Brotli import in its own source code.
Some components are not vulnerable to the decoding path. Apache's standard mod_brotli does not decode Brotli, and Apache and Nginx do not decode Brotli by default.
Advisory database gaps: pip-audit, Dependabot, and Safety do not flag it yet
As of October 23, 2026, advisory databases did not map CVE-2026-111497 to either the Brotli or brotlicffi PyPI package. The CVE record, OSV, and the GitHub Advisory Database did not list the two packages, which means pip-audit, Dependabot, and Safety will not flag vulnerable versions. A GitHub advisory was posted at GHSA-9v8h-qqgm-4m35, and the reporter was submitting PYSEC entries plus a PyPI package mapping for the GitHub advisory so that tooling picks it up. Until that mapping lands, exposure checks have to be manual.
How to check whether your application is exposed
An installed copy of a vulnerable Brotli decoder is enough to be exposed, even if no application code calls it. Practical checks:
- Check installed versions with
pip show Brotli brotlicffiin each environment, and withdocker run --rm <image> pip show Brotli brotlicffifor each container image. - Find what pulls the packages in. Run
pipdeptree -r -p Brotlito see which dependencies require it, and search lockfiles withgrep -i brotli poetry.lock uv.lock requirements*.txt. - List outbound HTTP calls that go to servers you do not control, plus any endpoints that decode
Content-Encoding: brrequest bodies. - Upgrade the services that match step 3 first, then the rest.
For reproduction work: brotli.decompress() raises a generic brotli.error: decoder failed for any error, so the specific error code is not visible from Python. A Decompressor() fed the crafted stream incrementally will never finish on 1.2.0. Testing Brotli 1.2.0 and 1.2.1 built with AddressSanitizer showed that 1.2.0 consumed all of a roughly 23 MB crafted stream while repeatedly reporting that it needed more input, whether the stream arrived in one piece or in chunks as small as one byte; version 1.2.1 rejected the stream each time with error -17.
Workarounds if you cannot upgrade immediately
These mitigations reduce exposure while patches are prepared:
- Python applications: where Brotli support is optional, uninstall both Brotli and brotlicffi from affected environments. Remove dependency extras such as
httpx[brotli]and any other requirements that would reinstall them, then regenerate dependency locks and rebuild or restart workloads. httpx, requests, and urllib3 retain gzip and deflate support without the optional packages, but a server that sends Brotli anyway may produce an unreadable response or an application error, and automatic fallback is not guaranteed. - Incoming HTTP requests: reject requests whose
Content-Encodingincludesbrat the reverse proxy, load balancer, or application middleware, before any vulnerable decoder processes the body. Matchbrcase-insensitively, including when it appears inside a list of encodings. - Outbound HTTP requests: remove
brfromAccept-Encoding, and also disable Brotli response decoding or reject responses whoseContent-Encodingincludesbrbefore decoding begins. The check has to happen before automatic body processing; checking after the client has downloaded and decoded the response is too late.
Changing Accept-Encoding alone is insufficient, because a malicious server can send a Brotli response regardless of what the client advertises, and urllib3 selects its decoder from the response's Content-Encoding header. Uninstalling the Python packages also does not remove separate Brotli decoders bundled into other runtimes, libraries, or products.
The disclosure timeline and the OpenAI February discovery
Aikido's TL;DR states that Node.js disclosed CVE-2026-111497 on Wednesday, October 21, 2026, while the later timeline section of the same advisory describes the Node.js disclosure as Wednesday, October 22, 2026; the source lists both dates. Python published a security update patching the same flaw the following day. On Friday, October 23, it became known that the CVE affects other major languages and service applications using HTTP, where patches were not yet fully available.
OpenAI stated that it discovered the vulnerability in February. The root cause was fixed in the Brotli source code at that time, but it was not recognized as a security issue and no release shipped with the fix until October 2026. OpenAI reported it as unauthenticated remote code execution working in both directions, and published advisories referenced at patchtheplanet.org/brotli.
Hacker News commenters pushed back on the attribution. One commenter argued the February change came from Google rather than OpenAI:
Article claims OpenAI found this in February, but I don't think that's correct. I think Google made a change to the Brotli source code in February that fixes the issue, but hadn't realized it was a security issue and therefore hadn't cut a release.
Another commenter highlighted the gap between reporting severity and shipping a release:
reported it as unauthenticated remote code execution that works in both directions ... but it wasn't recognized as a security issue at the time and no release shipped with the fix until now. I'm always getting my dangerous RCE bugs mixed up with my harmless RCE bugs. I'm curious how this was reported and fixed back in Feb but nobody recognized the importance. A case of AI automation and nobody at the wheel?
Community reaction: naming, complexity, and the C language debate
The most consistent complaint in the Hacker News discussion was the name. "Node2Shell" no longer described the scope once Python and other ecosystems were confirmed affected, and "HTTP2Shell" was widely rejected as too broad and too vague:
Well, whoever picked the name HTTP2Shell certainly didn't use any intelligence, artificial or genuine. It's so meaningless, broad and undescriptive of the actual issue. No it probably doesn't affect an HTTP server with nothing else behind it, so why is HTTP being blasted?
Alternative names proposed in the thread included Brotli2Shell and Broccoli2Shell. One commenter made the case that HTTP is only incidental to the bug:
Much prefer the Broccoli2Shell name & site (for the same vuln). For starters, I'm pretty sure you can hit this without HTTP if you do any manual Brotli decoding, HTTP just happens to be the most common case that comes up.
Several commenters questioned how widely Brotli-compressed request bodies are actually decoded in default configurations, arguing the advisory blurred the difference between normal response decompression and the more obscure inbound path:
To me, the surprising part is how many of these implement brotli compression of request (not just response) bodies, given how obscure a feature that is. In any case all this sensationalism is starting to get annoying. Patch your stuff and move on.
A complexity argument also surfaced, framed as the cost of replacing gzip/deflate:
An example of the cost of added complexity I suppose. Brotli is much more complicated than the gzip/deflate it replaces. ... and of course we still have to expose gzip to attack as well. Every time you add something you lose something...
One thread revolved around whether this is an argument against C:
Honestly it's time to get rid of C as a language used where security is a factor. Enough already. Why the hell is a lib like brotli that processes public general internet traffic, and maintained by google, not in rust?
A reviewer of the upstream patch found it rushed:
I even read the patch for the C code (patch which, btw, seems a bit hacky to me with isSafe? methods added and whatnots ... this patch really looks like "lipstick on a buffer overflowing C pig" to me). ... What's the link between Python / Node / C++ / libbrotli / Envoy / Bun: are those some all using the same C brotli encoder/decoder?
The answer to that commenter's question is yes: they all embed or link the same Brotli C decoder, which is why upstream Brotli 1.2.1 alone does not secure a system that bundles its own copy.
Operationally affected software reported by commenters
Commenters catalogued real-world exposure beyond the advisory's table:
- Git for Windows is vulnerable even in its latest release (2.56.0.windows.3); the fix is merged in the repository but only available in a snapshot build, with a follow-up release expected on Monday (2.56.0.windows.4). Pulling repositories over HTTPS from untrusted servers is the relevant risk.
- Codex (the GUI) ships its own Git and its own Node, which commenters described as potentially higher risk; the suggested mitigation is updating Codex and clearing its cache at
~/.cache/codex-runtimes. - Wireshark and ImHex remain vulnerable even on their latest repository commits.
- Microsoft 365 Copilot still shipped its own unpatched
brotlidec.dlldated October 7, with no fix available and no confirmed path to reach the vulnerable decoder. - Ubuntu still had the
libbrotli1patch under review as a medium-severity item, which was holding up updates to libcurl and therefore Git and other dependent packages. - A file search on a single Windows development box found the Brotli library linked into Git, Sublime Text, Visual Studio, CUDA, .NET, Inkscape, and Azure Tools.
One operations-side commenter checked their fleet and found no exposure at all, illustrating the transitive-dependency lottery:
I had to check all of our Python deployments and installation BOMs and was quite relieved - turns out that none actually installed brotli libraries. HTTP libraries like httpx, requests and frameworks consider them optional and autodetect their presence.
An unanswered architecture question raised in the thread was whether an application is safe when a load balancer terminates TLS and handles decompression:
Let's say I have a node.js app behind an Amazon elastic load balancer which terminates TLS. My understanding is that in nearly all configurations, my app would be unaffected because the ELB would handle decompression. Is that generally correct?
No definitive answer is recorded in the discussion, so the practical rule remains: audit every component in the decode path rather than assuming an edge proxy removes the risk.
The patch-velocity problem
The discussion also captured a broader tension in dependency management. Package ecosystems spent 2025 advising engineers to apply cooldowns to newly published releases to avoid supply-chain attacks, and critical vulnerabilities now force those cooldowns aside:
A few month ago, everyone was advising to use cool-downs in your package upgrades. Now we're constantly overriding those because security incidents will be exploited immediately. Guess that's just how it's gonna be from now on.
Some engineers responded by automating remediation, with one commenter describing pointing Claude Code at each new advisory as it appears. Others framed the practical posture bluntly: patch, rebuild, redeploy, and move on. The one point the thread did not dispute is that Brotli decoders are now part of the untrusted-input attack surface of nearly every HTTP client and server, and that every project bundling Brotli has to ship its own update for CVE-2026-111497.
Sources
Related
- Dispatch
- Project
- Project
- Dispatch
- Dispatch