Another day, another vulnerability.
This one is CVE-2026-111497, an out-of-bounds write in Google's Brotli decoder. It has picked up a few names (Brotli2Shell, Node2Shell, Broccoli2Shell), and it's worse than it looks, because Node.js, .NET, Bun and many other projects bundle their own copy of the decoder, and each copy needs its own fix.
Early Light now detects it, and Sensei fixes it. This post is the first in a series. Each time a new vulnerability drops, Early Light gets a detector, Sensei gets the fix, and we write it up here.
Brotli releases 1.0.3 through 1.2.0 discard an error in the decoder's block-switch logic, so a crafted compressed stream corrupts the decoder's memory. That can crash the process, leak its memory or run code. Anything that decompresses Brotli data from a source it doesn't trust is exposed, including HTTP clients and servers that accept Content-Encoding: br. Brotli 1.0.10, 1.1.1 and 1.2.1 fix it (GHSA-9v8h-qqgm-4m35).
The system libbrotlidec is only the start. Node.js, .NET, Bun, Envoy and Istio, Electron, and Python packages such as Pillow, pyarrow and pycurl each carry their own copy of the decoder. Updating the operating system package fixes the system library and anything that links to it. A Node.js installed from your distribution's packages uses the system library instead, so the OS update covers it. The bundled copies each need their own fixed release:
| Runtime | Fixed releases | No fixed release |
|---|---|---|
| Node.js | 22.23.4, 24.22.1, 26.12.1 | 20, 21, 23, 25 and older |
| .NET runtime and ASP.NET Core | 8.0.33, 9.0.22, 10.0.14 | 7 and older |
| Bun | 1.4.4 | minors before 1.4 |
A version string is weak evidence. Distributions backport fixes without changing the version, and many builds strip the version out entirely. So Early Light reads the decoder itself. The fix added a new error code to the decoder's error table, which means a decoder that carries it is fixed, whatever version it claims. Where a build strips that table, Early Light uses the release's own version stamp or the decoder's machine code, which only handles that error once fixed. When it can't settle a case, such as a decoder compiled to WebAssembly, it reports unknown instead of calling you safe.
We checked it against 38 container images and 73 release binaries and packages with known fix status, across Linux, Windows and macOS. It got all 111 right.
brew install defectdojo/tap/earlylight
earlylight scan image --detector brotli your-registry/your-app:latest
earlylight scan repo --detector brotli . # Node.js, .NET and Bun pins and bundling packages
earlylight fix --detector brotli --dry-run . # the one-line moves to fixed releases
sudo earlylight scan fs / # this machine
As of DefectDojo Pro 3.4.303, Sensei has two new checks for CVE-2026-111497. The first reads the pins that choose a Node.js, .NET or Bun release (Dockerfiles, CI workflows, version files, package.json, global.json, serverless configs) and the dependencies that bundle the decoder. The second pulls the images your repository builds on and deploys, and judges each decoder inside them with Early Light's detector.
These fixes are deterministic. Sensei moves a pin to the fixed release on its line once the registry shows that release is published. It re-pins an image, bumps its tag or adds an OS package refresh only after it has pulled the result and scanned it clean. Where a safe change isn't possible, it gives you the exact manual steps.
New vulnerabilities aren't slowing down. Our goal is the fastest detection and fix in security, every time one drops. Early Light is free and open source under the BSD 3-Clause license.
Fight AI with AI before new vulns drop tomorrow.