Status: Patched
Severity: Critical, CVSS v4.0 9.2 (Google, the CVE’s assigner) · Node.js rates it High
Overview
Node2Shell is CVE-2026-111497, an out-of-bounds write in Google’s Brotli decoder. Crafted Brotli-compressed data can crash a process, disclose process memory or, in some setups, run code. It affects Node.js, Python’s Brotli packages, Bun, Envoy, .NET and other software that bundles the decoder. Fixes shipped from 21 October 2026. Update, rebuild and restart.
Why So Many Names?
- Node2Shell: Imperva’s name for the Node.js exposure, where the bug first drew broad attention.
- HTTP2Shell: a later name for the wider impact. Despite the name, this is not an HTTP/2 bug, or necessarily an HTTP bug. Any attacker-controlled Brotli stream that reaches an affected decoder can trigger it.
- Broccoli2Shell: the name used by an independent tracking site that lists affected software.
All three are CVE-2026-111497. Patching for one patches for all of them.
Am I Affected?
- Google Brotli: 1.0.x from 1.0.3 before 1.0.10, plus 1.1.0 and 1.2.0, on all platforms.
- Node.js: 22.x, 24.x and 26.x before the fixed releases. Node.js says end-of-life versions are always affected when a security release ships; that includes 20.x, 23.x and 25.x.
- Python: the Brotli package from 1.0.3 up to 1.2.1, and brotlicffi from 1.0.3 up to 1.2.1.0. Clients such as urllib3, Requests, HTTPX and aiohttp decode Brotli responses automatically when one of these packages is installed, even if your code never imports it.
- Bun: 1.0.21 up to 1.4.4.
- Envoy: deployments with the Brotli decompressor configured.
- .NET: .NET 8, 9 and 10 runtimes before the fixed releases, and .NET 11 previews. It is only reachable through ASP.NET Core request decompression with the
brprovider,HttpClientautomatic Brotli decompression, or direct use ofBrotliStreamorBrotliDecoder, none of which is on by default. .NET Framework is not affected. - Other software: anything that bundles or links an affected Brotli, such as curl builds that decode Brotli responses (
--compressed) using an affected libbrotli. Check each vendor’s advisory and your OS packages.
When Is It Reachable?
An attacker must get a crafted Brotli stream decoded by a vulnerable copy. Common routes:
- Compressed request bodies: services that decompress incoming bodies sent with
Content-Encoding: br. Imperva confirmed this path through Express 5.0.0–5.3.0 and body-parser 2.0.0–2.3.0 with theraw()andjson()parsers. Running Express alone does not mean you are exposed, and a bare Node.js HTTP server does not decode incoming Brotli bodies. - Compressed responses: clients that decode Brotli responses from servers they don’t control, for example webhooks or URL previews. Imperva confirmed this path through Node.js’s built-in
fetch(). - Direct decoding: code that passes untrusted data, including uploaded or imported files, to
node:zlib’s Brotli functions or equivalent APIs in other languages.
What to Do
- Find every copy of Brotli: Node.js runtimes (including inside container images), Python environments, .NET apps, and other runtimes, proxies and tools that bundle it.
- Update Node.js to 22.23.4, 24.22.1 or 26.12.1, or later. Move off end-of-life Node.js lines.
- Update Python’s Brotli to 1.2.1 and brotlicffi to 1.2.1.0, then regenerate lockfiles.
- Update the system Brotli library to 1.2.1, or to 1.1.1 or 1.0.10 on those branches. Distribution packages may backport the fix without changing the version number, so follow your distribution’s advisory.
- Update everything else that bundles Brotli, including Bun, Envoy and .NET.
- Rebuild, redeploy and restart. Running processes keep the old decoder until they restart. Rebuild Bun
bun build --compileexecutables, republish .NET NativeAOT apps, and rebuild container images. - If you can’t update straight away: Node.js says there is no workaround. As a stopgap, some researchers suggest rejecting requests with
Content-Encoding: brat your proxy or middleware. This does not protect responses your services fetch, so prioritise updating services that call untrusted servers. For .NET, Microsoft suggests removing thebrprovider from request decompression and Brotli fromHttpClientautomatic decompression.
Fixed Versions
| Component | Fixed in |
|---|---|
| Google Brotli | 1.2.1, 1.1.1, 1.0.10 |
| Node.js | 26.12.1, 24.22.1, 22.23.4 |
| Python Brotli | 1.2.1 |
| brotlicffi | 1.2.1.0 |
| Bun | 1.4.4 |
| Envoy | 1.40.0, 1.39.3, 1.38.6 |
| Envoy (older) | 1.37.8, 1.36.12 |
| .NET | 10.0.14, 9.0.22, 8.0.33 |
| .NET 11 | 11.0.0-rc.3 |
Timeline
| Date | Event |
|---|---|
| 2026-02-27 | Fix lands in Brotli’s source, not marked as a security fix |
| 2026-10-21 | Brotli 1.0.10, 1.1.1 and 1.2.1 released |
| 2026-10-21 | Node.js 22.23.4, 24.22.1 and 26.12.1 released |
| 2026-10-22 | Imperva reports code execution on Node.js 24.22.0 |
| 2026-10-22 | GitHub advisory for Python Brotli and brotlicffi; fixes on PyPI |
| 2026-10-23 | Bun and Envoy publish advisories |
| 2026-10-25 | Microsoft publishes the .NET advisory |
The fix (commit 0ed4268, “Detect and report invalid stream earlier”) was public in Brotli’s source from 27 February, but nothing marked it as a security fix and no release shipped it until October. Software built from release tarballs or older vendored copies stayed affected until then.
Technical Summary
- The bug: a Brotli stream can tell the decoder to switch between block types. A crafted stream asks for a switch after declaring only one block type. In the vulnerable code,
DecodeBlockTypeAndLength()returned the same result for this format error as for “not enough input yet”, so the streaming decoder waited for more data (CWE-252, unchecked return value). - The corruption: as more input arrived, the decoder kept appending it to an eight-byte internal buffer and wrote past its end into neighbouring decoder state (CWE-787, out-of-bounds write).
- The impact: depending on what is overwritten, a crash, disclosure of process memory, or code execution in the process. Imperva reached code execution on the official Node.js 24.22.0 Linux arm64 image, which took multiple attempts. Imperva has not released an exploit, and public crash demonstrations are not the same as a reliable RCE exploit.
- The fix: the decoder now returns a specific error,
BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH, for an impossible block switch and stops instead of buffering. Patched Node.js rejects Imperva’s inputs and keeps running. - Severity: CVSS v4.0 9.2 (
AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N). “Attack requirements: present” reflects that the target must decode Brotli from an attacker-influenced source. Microsoft scores the .NET exposure CVSS v3.1 8.1.
Update Log
- 26 October 2026: Initial publication. Status: patched.
References
- CVE-2026-111497 record
- Node.js: October 2026 security releases
- Google Brotli 1.2.1 release and fix commit 0ed4268
- GitHub advisory GHSA-9v8h-qqgm-4m35 (Python Brotli, brotlicffi)
- Bun advisory GHSA-663w-cv8g-jj2p
- Envoy advisory GHSA-3wvj-j6qm-62mr
- Microsoft .NET advisory
- Imperva: Node2Shell, from Brotli data to remote code execution
- Aikido: Python packages affected by Node2Shell (Python clients, curl, proxy stopgap)
- Broccoli2Shell (independent list of affected software)
- Credits, from the Node.js advisory: reported by Khai Tran and Sylvie Mayer of OpenAI Codex Security; fixed by mcollina and aduh95.