Broccoli2Shell: Brotli decoder out-of-bounds write (CVE-2026-111497)
Pangram verdict · v3.3
We believe that this text is a mix of AI and human-written content.
AI likelihood · overall
AIArticle text · 1,084 words · 22 segments analyzed
Who's exposed You're at risk if your code, or any library it uses, decompresses Brotli data that someone else controls. That happens in more places than you'd think, because HTTP clients decompress Brotli responses on their own. Your app fetches a URLNode's built-in fetch() decodes Content-Encoding: br responses automatically. So do Python's requests/urllib3 and aiohttp whenever a Brotli package is installed. Any server you talk to can send the payload, whether through webhooks, link previews, crawlers or "import from URL" features. Your app accepts uploads or request bodiesExpress 5.0.0–5.3.0 and body-parser 2.0.0–2.3.0 inflate Brotli request bodies in parsers such as raw() and json(). Python frameworks and middleware that decode br bodies are exposed in the same way. A bare node:http server doesn't decode bodies by itself. Your app calls the decoder directlyThis means zlib.brotliDecompress*(), createBrotliDecompress(), brotli.decompress(), and any library that uses them on archives, caches or queue messages. Express and body-parser don't contain the bug. They're just paths to it, so upgrading them won't help. Node.js bundles its own copy of Brotli, which means the system libbrotli doesn't matter there. Only the Node.js version does. The bug A Brotli stream is split into blocks, and the decoder switches between block types as it reads them. Before the fix, DecodeBlockTypeAndLength() in c/dec/decode.c returned a plain boolean, so callers couldn't tell a malformed stream from one that just needed more input. On the fast path, the decoder ignored the return value altogether. A crafted stream can request a block switch that can't happen. The decoder took that to mean "need more input" and kept adding attacker bytes to an eight-byte internal buffer, writing past its end. The overwrite corrupts nearby decoder state. That's how a malformed stream can turn into a memory leak or code execution. The upstream fix is google/brotli commit 0ed4268, along with 50a9b70, b418fa8 and da98063. It returns a hard format error, BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH (−17), to the caller. The bug is tracked as CWE-252 (unchecked return value) and CWE-787 (out-of-bounds write). Python The PyPI packages Brotli and brotlicffi compile the same C decoder. Your code doesn't need to import them to be exposed. If either one is installed, these clients use it on their own: urllib3, and therefore requests, advertises Accept-Encoding: br and decodes Brotli responses. aiohttp uses Brotli when it's installed. httpx uses it through the httpx[brotli] extra. Scrapy and other crawlers. Some versions install Brotli as a dependency. Don't wait for your scanner. When this was disclosed, pip-audit, Dependabot and Safety didn't reliably flag the affected PyPI versions. The CVE record named the upstream Google repository, not the PyPI packages. GitHub's advisory now lists both packages (PYSEC-2026-4322 and PYSEC-2026-4323), but check by hand anyway. If your bindings come from your Linux distribution (for example python3-brotli) and not from PyPI, the fix arrives through your distribution's security updates. Other software The bug is in Google's reference C decoder, not in Node.js or Python. Anything that ships or links Brotli 1.0.3 through 1.2.0 may be affected, even before an advisory names it. The system library. It's called libbrotlidec, packaged as libbrotli1, brotli and similar. Programs that link it dynamically are fixed once your distribution ships a patched package and you restart them. Statically linked or vendored copies need their own rebuild. Bindings that wrap the C code. This covers Java JNI wrappers, PHP and Ruby extensions, and Go cgo bindings. Look for a release that bundles 1.0.10, 1.1.1 or 1.2.1. Proxies, CDNs, HTTP clients and archive tools that decode br content with the C library. Decoders rewritten in other languages aren't a concern. The Java, JavaScript and C# ports, which pdf.js, iText and HtmlUnit use, can't reach the bug. The Go port (andybalholm/brotli) had the same logic error, but it would only have crashed, and it was fixed on 23 October. Rust's brotli-decompressor catches the condition and returns an error. Code execution is only possible in the C decoder. Projects that bundle their own copy Many projects ship a private copy of the C decoder instead of using your system's library. A distribution update doesn't fix those: each project has to update its copy. We searched GitHub for vendored copies and read their headers, and last rechecked them on 25 October 2026. A copy is patched if it includes the new BLOCK_SWITCH error code. Not fixed yet, as of 26 October ProjectBundled copyUntrusted input it decodes .NET runtime1.1.0BrotliDecoder, BrotliStream, HttpClient automatic decompression, and request bodies in ASP.NET Core apps that use the request decompression middleware. Microsoft confirmed it is working on a response in issue #136422. DuckDBunpatchedBrotli-compressed Parquet files. A fix is in progress in PR #27791. Apache Arrow (bundled build)1.0.9Brotli-compressed Parquet files.
Tracked in issue #55166.
PR #55167, which moves to Brotli 1.0.10, has been approved but not merged. v8-jsi1.2.0The same paths as Node.js, because it bundles Node.js 7-Zip-zstd1.2.0Archives and .br files a user opens.
Tracked in issue #579.
p7zip1.0.9Archives and .br files a user opens EDK II1.2.0Compressed firmware sections.
Tracked in issue #13378.
woff2 (Makefile build)1.0.3WOFF2 fonts passed to woff2_decompress. The CMake build links the system library instead.
Tracked in issue #207. A fix has been proposed in PR #208.
Fixed since disclosure ProjectFixed inDetails Ruby brotli gem0.9.1Bundles Brotli 1.2.1 and refuses to build against an unpatched system libbrotli.
Released on 24 October (issue #64).
PHP brotli extension0.21.1Bundles Brotli 1.2.1.
Released on 24 October (PR #105). UEFIToolA76Bundles Brotli 1.2.1.
Released on 24 October (issue #492).
MuPDF1.28.0Its Brotli fork picked up the upstream fix in April 2026, before disclosure, so every 1.28.x release is patched. The 1.27.x releases still bundle the affected decoder.
ClickHousemaster branchUpdated to Brotli 1.2.1 in PR #127419 on 25 October and backported to 26.10. Backports to 26.9, 26.8 and 26.3 LTS are open.
Not in a release yet: the latest, 26.10.2.103, came out before the fix.
NanaZipmain branchUpdated to Brotli 1.2.1 in 3da1c6a on 24 October. Not in a release yet: the latest, 7.0.1873.0, came out before the fix.
GraalJS (graal-nodejs)master branchThe fix was merged on 22 October. Not in a release yet: GraalVM ships security updates quarterly, and the latest release, 25.4.4.1.1, came out before the fix.
YDBmain branchPatched with the upstream fix in 343f6be on 23 October. Not in a release yet.
libjxlmain branchUpdated to Brotli 1.2.1 in PR #5062 on 24 October.
Not in a release yet: the latest, v0.12.0, came out before the fix. Fixed before this list was made: Node.js, Bun, Chromium, Firefox, brotlicffi, ngx_brotli, Brotli4j, SumatraPDF, Ghostscript, CatBoost and YTsaurus, as well as Gentoo, Solus and VMware Photon packages.
This list isn't complete.