Brotli Decoder Vulnerability Poses Remote Code Execution Risk

A vulnerability in Brotli’s C decoder could lead to remote code execution. Developers should check their Node.js versions, Python libraries, and embedded copies of the decoder.

· 4 min read · 5 comments

A vulnerability has been found in Brotli’s reference C decoder: specially crafted compressed data could lead to remote code execution. According to Broccoli2Shell, patched Brotli versions 1.0.10, 1.1.1, and 1.2.1 were released on October 21, 2026. Direct use of the decoder is not the only thing to check: Node.js, Python libraries, and other software may decompress Brotli data without an explicit call in the application code.

How the Bug Works and Where the Risk Arises

The bug involves transitions between blocks in a Brotli stream. Previously, the decoder did not always distinguish a malformed stream from one that simply needed more input. On the fast path, the result of one check was ignored altogether. A crafted stream could cause the decoder to write past an internal eight-byte buffer and corrupt adjacent state. Possible consequences include memory disclosure or code execution.

Brotli’s C decoder is vulnerable in versions 1.0.3 through 1.2.0, including copies embedded in other projects. Decoders rewritten in other languages do not allow code execution through this bug. The fix stops processing a malformed stream with a format error.

One route to the vulnerability is through HTTP responses. Node.js’s built-in fetch() automatically decompresses responses with Content-Encoding: br. In Python, requests via urllib3, aiohttp, and httpx with Brotli support can do the same if the required package is installed. That creates a risk, for example, for an application that fetches data from an external URL. Another route is compressed request bodies: certain handlers in Express 5.0.0–5.3.0 and body-parser 2.0.0–2.3.0 decompress them. A server using node:http does not do this on its own.

Express and body-parser do not contain the bug: updating those packages alone will not fix it. Node.js ships its own copy of Brotli, so the Node.js version matters, not the version of the system library. Applications may also call the decoder directly—for example, when handling archives, caches, or queue messages.

Which Versions and Copies to Check

For Node.js, fixes are available in versions 22.23.4, 24.22.1, and 26.12.1; branches that are no longer supported are affected too. In Python, Brotli must be at least 1.2.1 and brotlicffi at least 1.2.1.0. Even if an application does not import these packages directly, they can enable Brotli support in an HTTP client. At the time of disclosure, pip-audit, Dependabot, and Safety did not always flag affected PyPI versions. Automated dependency checks alone are therefore not enough.

It is also important to establish where the program gets its C decoder. For a dynamically linked system library, install the fix through distribution updates and restart the process. Embedded and statically linked copies require an update to the project itself and a new build. Projects listed as having such copies include DuckDB, Apache Arrow, and p7zip. For some other projects, fixes have been merged into development branches but have not yet reached a release. Updating the system libbrotli will not protect embedded copies.

What This Means for Websites and Applications

Developers should start by checking services that fetch third-party URLs or accept request bodies with Content-Encoding: br. This applies beyond production servers: the report specifically mentions test environments, container images, CI, and serverless environments. After updating, rebuild images, restart processes, and update pinned dependency versions; otherwise, the next build could bring back a vulnerable package. The risk when fetching external URLs also involves automatic decompression in HTTP clients, not just the handling of incoming requests.

If an immediate update is not possible, the temporary option given for Python is to remove Brotli and brotlicffi along with any extras that would reinstall them. For incoming requests, bodies with Content-Encoding: br can be rejected at the proxy or WAF. But removing br from outgoing Accept-Encoding does not provide full protection: a server contacted by the application could still send a Brotli-compressed response. For Node.js, the way to fully resolve the issue is to update the runtime.

Imperva researchers achieved code execution on a standard Node.js 24.22.0 image for Linux arm64, passing data both through a fetched response and through an Express request body. According to the report, the exploit example published on October 22 achieves code execution only on a specially weakened build. As of October 22, there had been no reports of attacks against real-world systems.

My Take

I would start by checking the runtime and dependency versions in the image that is actually running, not just in the project files. Automatic response decompression is easy to miss: the code shows an ordinary request to a URL, while the path to the decoder comes from an installed package.

To me, this is also a reminder that updating a library on a machine and updating an application are different tasks. If the decoder is embedded in the build, the fix has to make it into that build.

Sources

Where the news comes from. The text is a retelling in the author’s own words; the facts come from the source, the opinion is the author’s.

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

About the author

Elise Evers

Junior frontend developer

I’m learning HTML, CSS, and JavaScript in evening classes. For practice, I recreate small pages and note where I get lost in the documentation.

All posts by the author

Leave a comment

Not published. We’ll send a link to confirm your comment.

No links or ads. Your first comment is published after review. By sending a comment you agree to the privacy notice.

  1. hmm, since Node.js and Python packages can bundle their own Brotli copies, is there a reliable way to verify the decoder version actually in use rather than just checking the system package? dependency advice that stops at “upgrade Brotli” tends to be charmingly incomplete

    1. Elise Evers Post author

      the system package check only covers dynamically linked copies. for node and python, inspect the runtime’s bundled dependency/version or the package lock and rebuild with a patched release; if the copy is embedded, the OS package manager won’t tell you much

    2. I ran into a similar “where is this actually coming from?” issue while learning to trace dependencies in a Node project: the package manager tree told me about the JS package, but not which native bits were bundled underneath. For this Brotli check, I’d start with the runtime’s reported Node version, then inspect the lockfile and the installed package’s metadata or build files for vendored/native copies; I wouldn’t assume the OS Brotli version tells the whole story. It’s a bit fiddly, but at least it makes the audit repeatable 🙂

      1. I like the repeatable-audit angle—especially checking the installed package’s build files, since a lockfile can hide what got bundled underneath. Have you found a quick way to confirm the actual Brotli decoder version at runtime, or is inspecting build metadata the best practical option?

        1. Elise Evers Post author

          i don’t know a reliable runtime query that exposes the exact bundled decoder version across node and python. checking the runtime version plus package build metadata is the practical route; if that’s ambiguous, rebuild against a patched release rather than treating the system brotli version as proof