Broccoli2Shell: One Vulnerability, Three Names

Category: Security · Vulnerability Management · Supply Chain
Level: Foundational

CVE-2026-111497 is an out-of-bounds write in Google's Brotli decoder, scored 9.2 on CVSS v4.0, and it's already shown up in security coverage under three different nicknames: Broccoli2Shell, Node2Shell, and HTTP2Shell. No vendor settled on the same name, and that says more about the bug than it first looks like: Brotli isn't a library one product uses, it's a compression library sitting inside almost anything that speaks HTTP. The "HTTP2Shell" name isn't even accurate — the bug has nothing specific to do with HTTP/2, it just reflects the most common way the payload gets delivered.

The flaw affects libbrotli 1.0.3 through 1.0.9, 1.1.0, and 1.2.0. Google and the Node.js project shipped fixes on October 21, covering the 22.x, 24.x, and 26.x release lines. Microsoft followed four days later with an out-of-band patch: .NET 8.0.33, 9.0.22, 10.0.14, and the Release Candidate 3 of .NET 11. The Python brotli and brotlicffi packages also have patched releases out.

Why This Isn't Your Code's Fault

Like PHP2Shell, this isn't a bug born from a bad decision in your application. It lives in the decompression decoder itself — the part of the code that runs when your server (or your runtime) receives a Brotli-compressed response and has to decompress it before anything else happens. Having Node.js installed doesn't make you vulnerable on its own: the requirement is that the application decompresses Brotli data coming from someone you don't control — exactly what happens constantly in HTTP requests carrying Content-Encoding: br.

What Actually Breaks

The Brotli decoder reads the compressed stream in blocks, switching state as it goes. A malformed stream can force an invalid block switch that the decoder doesn't reject — it treats it as a legitimate request for more input. Depending on how the application reacts to that inconsistent state, the result ranges from a process crash to memory disclosure, up to remote code execution.

Imperva's Red Team is credited with the discovery, coining the name "Node2Shell" in a technical report published October 22, demonstrating real code execution against the official Node.js 24.22.0 image on Linux ARM64 — Imperva itself noted the run took several attempts, this isn't a trivial, first-try exploit. A public proof of concept that circulated the same day only achieved code execution against a deliberately weakened test build; against a standard build, the result was a crash and limited memory reads, not direct RCE. It's the same pattern as PHP2Shell: the first wave of PoC always looks worse (or better, from an attacker's perspective) than it actually is, until someone tests it against a real target.

One Library, Dozens of Patches

What this incident exposes well is the transitive dependency chain nobody audits. Brotli isn't something most teams consciously choose — it ships embedded in the runtime (Node.js), in the framework (.NET), in the language bindings (Python), silently, as part of native support for Content-Encoding: br. Fixing this bug wasn't one patch, it was several patches, published on different days, by different vendors, each chasing the same root cause coming from a project most of their own developers have never heard of.

There's an extra catch worth calling out for anyone doing vulnerability management: patching the operating system's Brotli library does not fix applications that bundle their own static copy of the library. If your inventory only tracks top-level packages in package.json or the OS package manager, this is exactly the kind of exposure that slips through — the vulnerable dependency isn't on your list of direct dependencies, it's two or three layers down, and it may be duplicated: a system copy already patched, and a vendored copy inside a binary nobody thought to rescan.

What's Known About Exploitation

The exploitation timeline followed the usual script for any high-CVSS, relatively easy-to-reproduce CVE. On October 23, researchers still said there was no confirmed exploitation in production. That changed on October 27: CISA added CVE-2026-111497 to its Known Exploited Vulnerabilities (KEV) catalog, with a remediation deadline of November 10 for US federal agencies — without detailing the observed attacks. The same day, honeypot firm Previdian logged an exploitation attempt from a US-based IP, but its own analysis found the exploit used was broken; as Previdian itself notes, a honeypot catching an attempt doesn't mean it would have worked against a real target.

In short: public PoC since October 22, KEV listing on the 27th, recorded attempt volume still low and mostly unsuccessful — but the usual pattern repeats anyway. The moment a high-CVSS CVE exists, automated scanning is usually already running before press coverage settles, and waiting for confirmation of "serious" exploitation before patching is always the wrong bet.

Mitigating Without Patching

For anyone who can't update right away, the edge mitigation here is more direct than PHP2Shell's: block requests carrying Content-Encoding: br at the reverse proxy or firewall, or disable Brotli support in the runtime until the patch is applied. That works because, unlike session.upload_progress, this attack vector rides on a standard, visible HTTP header — easier to filter at the edge than a feature buried in the application engine.

Compression Is Invisible Infrastructure

Nobody chooses Brotli. It ships enabled by default, does its job without drawing attention, and because of that it never enters the conversation about "which third-party libraries do we audit." It's the same pattern as session.upload_progress in PHP2Shell: the most dangerous component isn't the one you chose to use, it's the one that was already switched on before you decided anything — except this time, spread across three different language ecosystems at once.


Related: BleepingComputer — CISA warns of hackers now exploiting critical Node2Shell flaw · SecurityWeek — CISA Warns of Node2Shell Exploitation as Honeypots Log Attack Attempts · Sysdig — Detecting the Node.js Brotli RCE