Home / Blog / Broccoli2Shell: Brotli decoder RCE in Node.js, Python and…
Tech News

Broccoli2Shell: Brotli decoder RCE in Node.js, Python and more

Google patched a critical buffer overflow in the Brotli C decoder that impacts Node.js under 24.22.1 and Python packages running Brotli below version 1.2.1.

By Dillip Chowdary β€’ Oct 25, 2026 β€’ Source: broccoli2shell.com

Broccoli2Shell: Brotli decoder RCE in Node.js, Python and more

Google issued security patches for its reference Brotli compression library to fix a remote code execution vulnerability named Broccoli2Shell. The flaw exists in the upstream C decoder across versions 1.0.3 through 1.2.0, allowing memory corruption when decompressing malformed payloads. According to broccoli2shell.com's report, the vulnerability lets attackers overflow internal buffers during decompression routines executed automatically by networking stacks and application runtimes. Because downstream ecosystems bundle or link this reference C decoder, the vulnerability affects Node.js, Python packages, and data tools handling untrusted data.

This technical analysis covers the Broccoli2Shell vulnerability, examining the unchecked return value in the C decoder, memory corruption mechanics, exposed runtime layers, and available software patches. It is written for backend engineers, security teams, DevOps operators, and platform architects responsible for securing APIs, web crawlers, data pipelines, and container environments. Understanding this attack surface is vital because standard dependency scanners initially failed to identify vulnerable packages, leaving automated pipelines and services exposed to silent exploitation until manually audited, reconfigured, or upgraded.

What broke in Broccoli2Shell

The flaw exists directly within Google's reference C decoder for Brotli, located inside the DecodeBlockTypeAndLength function in c/dec/decode.c. In releases spanning Brotli 1.0.3 through 1.2.0, this function returned a plain boolean that prevented callers from distinguishing a malformed stream from one merely needing more input. On the fast path, the decoder ignored the return value entirely. Formally tracked as CWE-252 for unchecked return value and CWE-787 for out-of-bounds write, this logic failure creates severe memory corruption risks across systems processing untrusted compressed streams.

When an invalid stream requests an impossible block switch, the decoder assumes it needs more input and keeps appending attacker bytes into an eight-byte internal buffer, writing past the buffer boundary. This overwrite corrupts neighboring decoder state, transforming a malformed stream into a memory leak or arbitrary code execution. Upstream maintainers resolved the issue in google/brotli commit 0ed4268, accompanied by commits 50a9b70, b418fa8, and da98063. The patch enforces a hard format error, BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH with value minus seventeen, halting execution before memory corruption occurs.

Who is exposed by Broccoli2Shell

Broccoli2Shell: Brotli decoder RCE in Node.js, Python and more
Illustration Β· Pexels

Any application decompressing Brotli data controlled by an external party faces exposure because HTTP clients decompress responses automatically. In Node.js, the built-in fetch function automatically decodes responses presenting Content-Encoding br headers. Incoming request bodies handled by Express versions 5.0.0 through 5.3.0 or body-parser versions 2.0.0 through 2.3.0 inflate Brotli payloads through raw and json parsers. While Express and body-parser do not contain the bug themselves, they route untrusted bytes directly into the vulnerable decoder. Direct calls to zlib.brotliDecompress across webhooks, link previews, and crawlers trigger identical vulnerability.

The Python environment is broadly affected whenever the PyPI packages Brotli or brotlicffi are installed. When present, urllib3 and requests advertise Accept-Encoding br and automatically decompress Brotli server responses without explicit imports. The aiohttp client activates Brotli decompression when the package is installed, httpx uses it via the httpx[brotli] extra, and web crawlers like Scrapy frequently bundle it. Native bindings across Java JNI, PHP extensions, Ruby gems, and Go cgo wrappers are similarly exposed if they compile C versions between 1.0.3 and 1.2.0, as are system libraries named libbrotlidec.

Advertisement

Tech Pulse Daily

Get tomorrow's pulse first

Join engineers who read Tech Pulse before stand-up. Free, weekday mornings.

What to do now about Broccoli2Shell

Remediation requires updating core runtimes and C dependencies rather than web frameworks. For Node.js, administrators must upgrade to versions 22.23.4, 24.22.1, or 26.12.1 using version managers or updated container images, as Node.js bundles its own internal Brotli decoder. In Python environments, developers must upgrade packages by running pip install upgrading Brotli to at least 1.2.1 and brotlicffi to 1.2.1.0 or higher. Lockfiles across poetry, uv, and pipfile must be regenerated, container images rebuilt, and running services restarted to prevent automated build systems from reinstalling vulnerable cached dependencies.

If immediate upgrades are impossible, teams can mitigate Python exposure by uninstalling Brotli and brotlicffi, causing requests, urllib3, and aiohttp to safely negotiate gzip or deflate encoding instead. Engineers must audit system environments using package managers like dpkg, rpm, or apk, and verify active processes by searching for brotlidec in proc maps. Node.js versions can be checked by evaluating process.versions.brotli directly. Upgrades should be prioritized on edge services that fetch external URLs, ingest webhooks, or accept incoming requests carrying Content-Encoding br payloads.

How the Broccoli2Shell issue works

Brotli divides streaming data into discrete blocks, with the decoder switching between block types as it reads the payload. The exploit occurs when an attacker crafts a stream containing an invalid block switch instruction. Because DecodeBlockTypeAndLength returned an ambiguous boolean, the decoder failed to recognize the sequence as invalid syntax. Treating the condition as an indication that more input data was required, the decoding loop kept accepting attacker input bytes into an eight-byte internal buffer, writing past the allocated boundary.

The resulting buffer overflow corrupts nearby internal decoder memory, enabling attackers to leak memory contents or achieve arbitrary remote code execution. Decoders written in memory-safe languages avoid this execution pathway entirely. Re-implementations in Java, JavaScript, and C#, used by projects like pdf.js, iText, and HtmlUnit, cannot reach the vulnerability. The Go port andybalholm/brotli contained the identical parsing logic flaw, but it merely crashed rather than corrupting memory, and received a fix on October 23. Similarly, Rust's brotli-decompressor safely traps the condition and returns an error.

What is still unknown about Broccoli2Shell

Significant uncertainty remains regarding the full scope of unpatched software shipping private vendored copies of the C decoder. Automated code searches on GitHub regularly skip submodules, large repositories, and private builds, obscuring the true extent of exposure. Unpatched projects decoding untrusted input include the .NET runtime across HttpClient and ASP.NET Core decompression tracked in issue 136422, DuckDB Parquet decompression in pull request 27791, Apache Arrow bundled build 1.0.9 in issue 55166, v8-jsi 1.2.0, 7-Zip-zstd 1.2.0, p7zip 1.0.9, EDK II firmware, and woff2 Makefile builds.

Vulnerability scanner coverage also created gaps in early detection. At initial disclosure, pip-audit, Dependabot, and Safety did not reliably flag affected PyPI packages because the original CVE named the upstream Google repository rather than Python packages. Although GitHub advisories PYSEC-2026-4322 and PYSEC-2026-4323 were subsequently issued, manual audits remain necessary. Additionally, while projects like ClickHouse, NanaZip, GraalJS, YDB, and libjxl merged the upstream fix into master branches, several had not published formal stable releases, leaving production systems exposed until new versions are tagged and deployed.

Developer Action Items

  • ☐ Inventory whether Google / Python / Node.js runs in prod, CI, staging, or on laptops before you debate severity.
  • ☐ Confirm the vendor's fixed build for Google / Python / Node.js from Hacker News Best, then schedule the patch window.
  • ☐ If you cannot patch today, isolate the service, rotate tokens that sat on the affected surface, and raise the logging floor.
  • ☐ Record the decision and residual risk so the next on-call does not re-litigate whether you are exposed.

Broccoli2Shell FAQ

What is the root cause of the Broccoli2Shell vulnerability?

The vulnerability is caused by an unchecked return value in DecodeBlockTypeAndLength inside Google's reference Brotli C decoder. When handling an invalid block switch, the decoder treats the failure as a request for more input and overflows an internal eight-byte buffer.

Which versions of Node.js and Python are vulnerable to Broccoli2Shell?

Node.js versions below 22.23.4, 24.22.1, and 26.12.1 are affected because Node bundles its own vulnerable Brotli library. In Python, installations containing PyPI packages Brotli below 1.2.1 or brotlicffi below 1.2.1.0 expose clients like requests, urllib3, and aiohttp.

Can upgrading Express or body-parser resolve Broccoli2Shell?

No, Express 5.0.0 through 5.3.0 and body-parser 2.0.0 through 2.3.0 do not contain the bug itself, but merely route request bodies into the underlying decoder. Resolving the flaw requires updating the Node.js runtime binary directly.

Are Brotli decoders implemented in Go, Rust, Java, or C# vulnerable to remote code execution?

No, ports written in memory-safe languages cannot reach remote code execution. Decoders in Java, JavaScript, and C# are unaffected, Rust's brotli-decompressor returns a clean error, and the Go port only triggered a process crash before being patched on October 23.

Sources

Dillip Chowdary

Author

Dillip Chowdary

Writes Tech Bytes coverage of AI, engineering, and the tools that actually ship. Editor of Tech Pulse Daily.

Related on Tech Bytes

Advertisement

5-min tech signal

Weekday briefing for engineers who skip the noise.

No spam Β· Unsubscribe anytime

Advertisement

✈️ CareerPilot

Your AI job-search copilot

Match your resume against live Ashby, Greenhouse & Lever openings β€” fit scores, job-specific resume optimization and email alerts.

Find matching jobs β†’

Free Tools

Browse all tools β†’