Broccoli2Shell: The One Decoder to Rule Them All

CVE-2026-111497 lives in a Brotli decoder that’s been copied into runtimes, databases, and native packages far beyond Node.js. Here’s where it hides and what to do about it.

October 27th, 2026

One Brotli decoder bug. A lot of copies.

TL;DR - CVE-2026-111497 is an out-of-bounds write in the Brotli decompressor in google/brotli, fixed upstream in 1.2.1. It is not a separate Node, PHP, or npm bug. It is one C decoder that has been copied into runtimes, databases, document readers, image libraries, language bindings, and prebuilt native packages. And while originally reported as Node2Shell, this CVE impacts far more than just Node. In this post we go into detail on all the copies that you may have missed if you stopped reading after “Node.”

What is the bug?

CVE-2026-111497 is a Heap out-of-bounds write in Google's Brotli C decoder. Brotli is a compression algorithm that’s commonly used in HTTP applications and the vulnerable component is called when an attacker supplies a malformed Brotli stream. The decoder can treat an invalid block switch as incomplete input, continue with stale state, and write past the memory it owns.

That can mean a crash, memory disclosure, or memory corruption that may be useful for code execution, depending on the wrapper and the process around it. The bug is in the shared decoder, not in Node.js, Python, PHP, or npm itself. But how the decoder is handled and implemented changes how the vulnerability is actually patched and remediated.

The upstream 0ed4268a fix is in Brotli 1.2.1. The important change is that invalid block-switch state now returns a real decoder error instead of being treated as “need more input.” It’s a fairly simple fix, but prior to AI, it would need a skilled researcher familiar with C code and the Brotli compression decoder, which is probably why no one picked it up in Brotli 1.0.3 when it was introduced. 

Why this is bigger than Node

Node2Shell covered the Node.js attack paths. But Node is only one example. The underlying issue is the vulnerable decoder in Google’s C Brotli library.

That decoder has been copied into runtimes, browsers, databases, proxies, document tools, image libraries, and language bindings. It may be hidden inside a native library, wheel, DLL, addon, static binary, or transitive dependency. Updating one package does not update every copy in the application.

The patch is small. The difficult part is finding each bundled copy and confirming whether untrusted Brotli data can reach it.

Depending on the project, fixing it may mean:

  • Publishing new Python wheels or native packages

  • Releasing an updated runtime

  • Rebuilding Chromium, DuckDB, Envoy, .NET, or another larger artifact;

  • Updating the system libbrotli

  • Adapting the fix to a language-specific port

Sometimes it is a dependency update. Sometimes it requires a vendor release or a complete rebuild, so the just patch narrative can be complicated and not simple.

What to do

There will not be one neat package list for CVE-2026-111497. Broccoli2Shell is a useful resource, but each vendor will also identify packages that are not covered by the main public lists.  

Using Semgrep? A post on how it fits into your CVE-2026-111497 response is on the way.

The full scope will be difficult to track. Some projects are already patching silently, without publishing an advisory, and new affected packages will continue to appear across programming-language ecosystems and bundled native components.  

Below, we list packages we have confirmed so far, along with recommendations for cases where an immediate upgrade is not available.

Patch the package or runtime that contains Brotli

In this list we’ve compiled packages or runtimes that specifically ship Brotli inside of them. Patches are typically available for that component if you just update to the version listed below, and you can easily do these updates as you would any other patch.

Package

Vulnerable versions

Fixed in

Where Brotli lives

Google Brotli

1.0.3–1.2.0, excluding patched backports

1.2.1

upstream C decoder

libbrotli / distro brotli packages (source)

same upstream range unless backported

vendor-specific; upstream 1.2.1

system shared library or CLI

Python Brotli

1.0.3–1.2.0

1.2.1

CPython binding built from the C decoder

Python brotlicffi

1.0.3–1.2.0.x

1.2.1.0

native libbrotli build

Node.js

unpatched 22.x, 24.x, and 26.x releases

22.23.4, 24.22.1, 26.12.1

bundled deps/brotli

Bun

1.0.21–1.4.3

1.4.4

bundled Brotli copy

Go andybalholm/brotli

before v1.2.7

v1.2.7

Go decoder port

Java brotli4j

before 1.24.0

1.24.0

bundled native library

.NET System.IO.Compression.Brotli

8.0 before 8.0.33; 9.0 before 9.0.22; 10.0 before 10.0.14; .NET 11 before RC3

8.0.33, 9.0.22, 10.0.14, .NET 11 RC3

runtime bundle

Envoy Proxy

1.36.11, 1.37.7, 1.38.5, 1.39.2

1.36.12, 1.37.8, 1.38.6, 1.39.3, 1.40.0

bundled through Envoy

Istio

1.29.0–1.29.8, 1.30.0–1.30.5, 1.31.0–1.31.1

1.29.9, 1.30.6, 1.31.2

Envoy / bundled Brotli

Bundled Brotli

Some packages ship Brotli inside their own binary instead of using the system library. Many of these remain unfixed because either the package itself must be updated or rebuilt from source with the Brotli fixes included. Updating a top-level Brotli dependency will not patch those copies. 

Package

Vulnerable versions

Fixed in

Where Brotli lives

DuckDB

unpatched bundled copy

no fix yet

vendored Brotli; Parquet files

Apache Arrow

bundled Brotli 1.0.9

no fix yet

bundled Brotli; Parquet files

v8-jsi

bundled Brotli 1.2.0

no fix yet

bundled Node copy

7-Zip-zstd

bundled Brotli 1.2.0

no fix yet

bundled decoder; archives and .br files

p7zip

bundled Brotli 1.0.9

no fix yet

bundled decoder; archives and .br files

EDK II

bundled Brotli 1.2.0

no fix yet

bundled decoder; compressed firmware

woff2 Makefile build

bundled Brotli 1.0.3

no fix yet

bundled decoder; WOFF2 files

Ruby brotli gem

before 0.9.1

0.9.1

bundles Brotli 1.2.1

PHP brotli extension

before 0.21.1

0.21.1

bundles Brotli 1.2.1

UEFITool

before A76

A76

bundles Brotli 1.2.1

MuPDF

1.27.x

1.28.0

bundled Brotli fork

ClickHouse

latest release predates the fix

public branch fixed; release pending

bundled Brotli

NanaZip

latest release predates the fix

main fixed; release pending

bundled Brotli

GraalJS

latest release predates the fix

master fixed; release pending

bundled Node/Brotli copy

YDB

released versions not yet fixed

main fixed; release pending

bundled Brotli

libjxl

v0.12.0 and earlier

main fixed; release pending

bundled Brotli

Brotli4j

<= 1.23.0

1.24.0

Bundled native Brotli C decoder in the native-* Maven JARs, loaded through JNI.

Ruby brotli

< 0.9.1

0.9.1

Vendored Brotli source under vendor/brotli, with an optional system-library path.

Rust brotli-decompressor

< 6.2.0

6.2.0 (fix)

Rust implementation of the Brotli decompressor, with optional C-compatible FFI.

Go go-brrr

<= 1.3.0

1.3.1

Pure-Go Brotli encoder and decoder.

cycurl

<= 0.13.0

No fixed release (open issue #27)

Precompiled Python wheels bundle libcurl-impersonate with Brotli 1.1.0 statically linked. 

Pillow (PyPI)

>=9.3.0, <=13.0.0

No fix yet
"main fixed (PR https://github.com/python-pillow/Pillow/pull/10340) ; release pending

wheels ship libbrotlidec (FreeType WOFF2)

curl_cffi (PyPI)

< 0.17.0 

0.17.0

bundled brotli

pycurl (PyPI)

>= 7.45.3, <7.49.0 

7.49.0

wheels ship libbrotlidec 1.2.0

imagecodecs (PyPI)

2019.12.31 -2026.10.10(all releases)   

No fix yet

wheels ship libbrotlidec 1.2.0 (Brotli codec, JPEG XL)

pygame (PyPI)

2.0.3 – 2.6.1 (Linux / macOS wheels)   

No fix yet

wheels ship libbrotlidec 1.0.9 (FreeType WOFF2)

pygame-ce (PyPI)

<= 2.5.8 

No fix yet

wheels ship libbrotlidec 1.2.0 (FreeType WOFF2)

Magick.NET (NuGet, all Magick.NET-*  variants)

>=7.23.3, <=15.0.0

No fix yet

native ImageMagick build

IronCompress (NuGet)

>=1.2.5, <=1.7.0

No fix yet

native Brotli; used by Parquet.Net 4.x/5.x

Brotli.NET (NuGet)

>=2.0.0, <=2.1.1

no fix (open issue https://github.com/XieJJ99/brotli.net/issues/28)

prebuilt Brotli 1.0.9

methanol-brotli (Maven)

<= 1.9.0

no fix yet ( open issue #198)

JNI Brotli

mupdf-sys (Rust)

>=0.6.0, <=0.8.0

No fix yet

vendored MuPDF Brotli

woff (Rust)

>=0.2.2, <=0.6.3

No fix yet

vendored Brotli

es_compression (Dart)

<= 2.0.15

No fix yet

prebuilt Brotli 1.0.9

brotli (Elixir / Hex)

>=0.2.1, <0.3.4

0.3.4

vendored Brotli

multi_compress (Ruby)

<= 0.6.0

No fix yet

vendored Brotli

node-libcurl (npm)

>=2.0.0, <=5.1.2

No fix yet

prebuilt binaries statically link libcurl + Brotli

ladybug (PyPI)

>=0.15.3, <=0.22.0

no fix yet

vendored Brotli 1.1.0

real_ladybug (PyPI)

<= 0.15.3 (all releases)

no fix yet

vendored Brotli 1.1.0

@ladybugdb/core and its platform packages (npm)

<= 0.22.0 (all releases)

no fix yet

prebuilt native addon; vendored Brotli 1.1.0

lbug (npm)

<= 0.14.3 (all releases)

no fix yet

prebuilt native addon; vendored Brotli 1.1.0

lbug (crates.io)

<= 0.22.0 (all releases)

no fix yet

vendored Brotli 1.1.0 

LadybugDB.Native.* (NuGet: linux-x64, linux-arm64, osx-x64, osx-arm64, win-x64)

<= 0.19.1 (all releases)

no fix yet

vendored Brotli 1.1.0

We will continue to add to this list, and for packages which are directly included in your first party code, we will include the relevant Semgrep Supply Chain rules to help pinpoint locations you are using insecure versions of a library.

Semgrep Supply Chain findings for the Brotli unchecked return value advisory, showing four reachable findings in uv.lock files: two direct dependencies on brotli and brotlicffi, and two transitive ones through an httpx extra.

Semgrep Supply Chain showing four reachable findings for the Brotli advisory: two from direct dependencies and two from transitive ones.