
Advisory and analysis for CVE-2026-111497, a Brotli decoder out-of-bounds write reachable via Node.js HTTP decompression, with root cause, patch diff, detection rules, and mitigations.
Last verified: 2026-11-04 (KST). Each figure is listed only if confirmed from the sources in the References below; where values differ between sources, all are listed together.
c/dec/decode.c) ignores the error return value of an invalid block switch, continues decoding in a corrupted state, and performs an Out-of-Bounds Write beyond the buffer boundary.Brotli/brotlicffi, Bun, .NET, Envoy, Istio, etc. It is affected only if there is a path that decompresses attacker-controlled Content-Encoding: br data.| Item | Details |
|---|---|
| CVE ID | CVE-2026-111497 (GHSA-9v8h-qqgm-4m35) |
| Aliases | Node2Shell (named by Imperva), HTTP2Shell, Broccoli2Shell. Despite the names, this is not an HTTP/2 protocol flaw |
| Disclosure date | 2026-10-21 Node.js security release and Brotli patch release / 2026-10-22 CVE record published |
| Discoverers | OpenAI Codex Security (Khai Tran, Sylvie Mayer) |
| Affected products/versions | Google Brotli (libbrotlidec) 1.0.3 ~ 1.2.0 and products that bundle/link it (see table below) |
| Patched versions | Brotli 1.0.10 / 1.1.1 / 1.2.1, Node.js 22.23.4 / 24.22.1 / 26.12.1, Python Brotli 1.2.1, brotlicffi 1.2.1.0, Bun 1.4.4 |
| CVSS v4.0 (CNA: Google) | 9.2 Critical — CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N |
| CVSS v3.1 (NVD) | 9.8 Critical — CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| CVSS v3.1 (Red Hat / Amazon Linux) | 8.1 — CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H (reflecting attack requirement AT:P and platform hardening) |
| Vendor's own rating | Node.js: High / Red Hat: Important |
| CWE | CWE-787 Out-of-bounds Write (NVD, Red Hat, Canadian Cyber Centre) / CWE-252 Unchecked Return Value (CISA KEV description; some analyses also cite it as the root cause) |
| Actual exploitation | Exploitation confirmed. Added to CISA KEV on 2026-10-27, federal agency action deadline 2026-11-10. Honeypot operators (Previdian, ELLIO) observed exploitation attempts on 10-26~27 |
| Component | Affected versions | Fixed versions |
|---|---|---|
| Google Brotli (C, libbrotlidec) | 1.0.3 ~ 1.2.0 | 1.0.10, 1.1.1, 1.2.1 |
| Node.js 26.x (Current) | below 26.12.1 | 26.12.1 |
| Node.js 24.x (LTS) | below 24.22.1 | 24.22.1 |
| Node.js 22.x (LTS) | below 22.23.4 | 22.23.4 |
| Node.js 25.x / 23.x / 20.x and below | all versions (EOL) | No patch → migrate to 22/24/26 |
| Bun | 1.4.3 and below | 1.4.4 |
Python Brotli (PyPI) | 1.2.0 and below | 1.2.1 |
Python brotlicffi | below 1.2.1.0 | 1.2.1.0 |
| .NET / PowerShell | See vendor advisory | Microsoft emergency .NET update (dotnet/announcements#494) |
| Envoy / Istio | See vendor advisory | Fixed releases distributed in early October (without naming the flaw) |
| VMware SDDC Manager (VCF / vSphere Foundation) | See Broadcom advisory | See Broadcom advisory |
Indirect exposure paths: Python requests, urllib3, aiohttp[speedups], and httpx automatically decompress br responses if Brotli/brotlicffi is installed. curl is also affected when using the decompression option.
| Date | Event |
|---|---|
| 02-27 | Fix commit applied to the google/brotli repository (marked as a security issue; not released) |
| Early October | Envoy / Istio fixed releases distributed |
| 10-21 | Node.js security releases (22.23.4 / 24.22.1 / 26.12.1), Google Brotli 1.0.10 / 1.1.1 / 1.2.1 releases |
| 10-22 | CVE record published, Imperva demonstrates code execution on Node.js 24.22.0 (Linux arm64) |
| 10-23 | Patched PyPI packages distributed |
| 10-25 | Microsoft .NET advisory and updates |
| 10-26 | ELLIO reports exploitation traffic |
| 10-27 | Added to CISA KEV (remediation deadline 11-10) |
⚠️ Some analysis articles written between October 24 and 28 state that "no actual attacks have been confirmed and it is not listed in KEV," but this reflects the situation before KEV listing and differs from the present.
BROTLI_FALSE return valueBrotli 디코딩은 상태 기계(state machine)입니다. 스트림은 메타블록(metablock) 단위로 구성되며, 각 메타블록 안에서 리터럴(literal)·삽입-복사 명령(insert-and-copy command)·거리(distance)의 블록 타입을 전환(block switch) 하는 지시가 등장합니다.
DecodeBlockTypeAndLength() interprets block switches and returns a BROTLI_BOOL. The problem is that BROTLI_FALSE was used with two completely different meanings.
| Meaning | Nature | Correct handling |
|---|---|---|
| Needs more input | Recoverable | Wait for the next input and resume |
| Block switch itself is impossible because the metablock has only one block type | Fatal format error | Reject the stream |
The caller did not check this return value.
DecodeCommandBlockSwitch) is declared as static void and does not preserve the return value, and the non-safe branch of the BROTLI_SAFE macro merely calls the function and discards the result. (SonicWall analysis)DecodeLiteralBlockSwitch). Although different analyses point to different functions, according to the distribution patch description (TuxCare), all three block switch decoders—literal, command, and distance— were modified to return error codes, so all three paths can be considered involved.As a result, even when a format error occurs, the decoder continues as if the switch succeeded, the block length counter remains 0, and the position/distance state is carried over into a path that should have been rejected.
BrotliDecoderState).ProcessCommandsInternal() computes the destination as copy_dst = &s->ringbuffer[pos] and performs a 16-byte vector store with memmove16. Since pos is no longer constrained to the ring buffer range, a write occurs outside the allocated region.pos, this becomes a write-what-where primitive.The following is conceptual code reconstructing the gist of the changes based on descriptions in public analyses (SonicWall, Redfox, TuxCare patch description). It is not the original code from the actual commits, and details such as conditional expressions are inferred. For the exact diff, refer to the google/brotli v1.2.1 release and the Node.js
deps/brotlichanges. (The fix commit hash could not be confirmed from a primary source at the time this document was written.)
Before (vulnerable)
/* 형식 오류와 "입력 부족"이 같은 BROTLI_FALSE로 표현됨 */
static BROTLI_BOOL DecodeBlockTypeAndLength(int safe, BrotliDecoderState* s, int tree_type) {
...
if (/* 블록 타입이 1개뿐인 메타블록 */) {
return BROTLI_FALSE; /* 치명적 오류지만 복구 가능 신호와 구분 불가 */
}
...
return BROTLI_TRUE;
}