CVE-2026-111497: Flaw in Brotli decoder affects Node.js, Bun, Python, .NET, and Envoy—what you need to update now
A flaw in Google's Brotli decoder (versions 1.0.3 through 1.2.0) allows an out-of-bounds write, potentially leading to code execution, using crafted data (CVE-2026-111497, CVSS 9.2). Any software that decompresses Brotli data from untrusted sources is affected: Node.js, Bun, Python with Brotli/brotlicffi, .NET, Envoy, and curl. Updates are available.
Google’s Brotli decoder contains a flaw in versions 1.0.3 through 1.2.0 that allows crafted Brotli data to overwrite memory outside a buffer. The vulnerability is identified as CVE-2026-111497 and has a CVSS 4.0 score of 9.2; publicly, it is known as Node2Shell and Broccoli2Shell. Possible consequences include a crash, reading process memory, or code execution. Imperva demonstrated code execution on an unmodified Node.js 24.22.0. Proof-of-concept code is partly public, but attacks in the wild are not known so far. Node.js released the fixes on October 21, 2026; the other ecosystems followed by October 26.
After the disclosure, I checked my own systems: this website’s build runner was still running Node.js 22.23.1, even though 22.23.4 had been available for days. The reason is described in the GitHub Actions section below; it affects every self-hosted runner with actions/setup-node.
Help with inventory and updates
If you need help finding affected components in applications, container images, or CI pipelines, please use the contact form on adeptio.ch. I can also get back to you at short notice.
Cause
The flaw is in the DecodeBlockTypeAndLength() function. It processes block switches in the compressed data stream, meaning the points where the decoder switches to a different Huffman code. In vulnerable versions, the function returns only a Boolean value; BROTLI_FALSE means both “malformed data stream” and “more input required.” A crafted data stream declares a single block type and exhausts its length, forcing a switch that cannot succeed. The decoder treats this as missing input, appends additional bytes to an internal 8-byte buffer, and thus writes beyond its end.
The upstream fix (commit 0ed4268 in the google/brotli repository) introduces a separate BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH error code and aborts decoding. OpenAI Codex Security reported the flaw as early as February 2026. The fix was added to the source code at that time, but was not classified as a security fix and did not appear in any release. It was only shipped with Brotli 1.2.1 and the Node.js releases of October 21, 2026.
When a system is vulnerable
Compressing with Brotli is harmless; only those who decompress Brotli data from an untrusted source are vulnerable. There are two paths:
- Client: The application fetches a URL and decodes a response with
Content-Encoding: br. The built-infetch()in Node.js and Bun does this automatically and cannot be disabled. This affects crawlers, webhook receivers with callbacks, link previews, monitoring scripts, and any automation that loads content from third-party servers. An attacker only needs control over one of the fetched servers. - Server: A framework or middleware decompresses request bodies with
Content-Encoding: br. Imperva identifiesbody-parser2.0.0 through 2.3.0 and Express 5.0.0 through 5.3.0 with configuredjson()orraw()parsers for Node.js. A bare Node.jshttpserver does not itself decode incoming bodies.
Apache mod_brotli and the widely used Brotli modules for nginx only compress and are therefore not affected. Envoy and Istio are vulnerable only when the Brotli decompressor filter is configured; Istio does not enable it by default.
Affected components and fixed versions
| Component | Patched versions | Note |
|---|---|---|
| libbrotli (Google Brotli) | 1.2.1, 1.1.1, 1.0.10 | versions 1.0.3 through 1.2.0 are affected |
| Node.js | 26.12.1, 24.22.1, 22.23.4 | Release of October 21, 2026; includes additional fixes (DNS, TLS name verification) |
| Bun | 1.4.4 | rebuild executables created with bun build --compile |
Python Brotli | 1.2.1 | automatically used by urllib3, requests, and aiohttp when installed |
Python brotlicffi | 1.2.1.0 | likewise; also available as the httpx[brotli] extra |
| .NET | 8.0.33, 9.0.22, 10.0.14, 11 RC3 | Out-of-band update of October 25, 2026; .NET Framework is not affected, .NET 7 has no fix |
| Envoy | 1.40.0, 1.39.3, 1.38.6, 1.37.8 | only with the Brotli decompressor filter |
| Istio | 1.31.2, 1.30.6, 1.29.9 | only with a Brotli decompressor in an EnvoyFilter |
| Java brotli4j | 1.24.0 | JNI wrapper bundles its own Brotli copy |
| curl/libcurl | Built against Brotli 1.2.1 | only with --compressed or CURLOPT_ACCEPT_ENCODING |
Other bindings for PHP, Ruby, and Go (cgo) depend on the system-wide or bundled libbrotli. Among Linux distributions, Debian 12 and 13, Alpine, and Amazon Linux 2023 had patched packages as of October 26; Fedora and Red Hat were partially patched, while the fix was still pending for Ubuntu and SUSE.
Finding affected versions
For Node.js, Python, and the system library, three queries are sufficient. On Windows, node -v produces the same result as on Linux.
node -v
pip show Brotli brotlicffi
pipdeptree -r -p Brotli
On Debian/Ubuntu and Alpine, the package manager shows the version of the system library:
dpkg -l 'libbrotli*'
apk info -v brotli-libs
Container images must be checked separately: an updated host is of no use if the image contains an old Node.js version or a bundled libbrotli. After the update, images must be rebuilt and running workloads restarted; for Bun and brotli4j, this also applies to applications that statically link Brotli.
Self-hosted GitHub runners: setup-node takes the version from the cache
actions/setup-node with node-version: 22 does not check by default whether a newer version in the 22 series exists. If the runner’s tool cache already contains a matching version, it is used. On GitHub-hosted runners, the image is rolled out regularly; a self-hosted runner, on the other hand, retains its cache until someone clears it. The log then says, for example, Found in cache @ .../_tool/node/22.23.1/x64.
A further line in every setup-node step provides a remedy:
- uses: actions/setup-node@v4
with:
node-version: 22
check-latest: true
Alternatively, the minimum version can be pinned (node-version: 22.23.4); it must then be updated with every security release. This is especially relevant for pipelines that retrieve content from third-party servers, such as scanners, link checkers, or feeds: fetch() runs there against servers you do not control, and the runner generally has access to deployment secrets.
If an immediate update is not possible
The mitigations target decoding:
- Incoming: Reject requests with
Content-Encodingcontainingbrat the reverse proxy or in middleware. The comparison must be case-insensitive and also cover lists such asgzip, br. - Outgoing: Remove
brfromAccept-Encodingand discard responses withContent-Encoding: brbefore decoding. Removing it fromAccept-Encodingalone is not sufficient because a crafted server can send the encoding anyway. This is not possible with the built-infetch()in Node.js and Bun; only updating helps there. - curl: Omit
--compressed; in libcurl, leaveCURLOPT_ACCEPT_ENCODINGset toNULL. - Python: Uninstall
Brotliandbrotlicffi, and remove extras such ashttpx[brotli]from dependencies. urllib3, requests, and aiohttp then fall back to gzip and deflate. - Envoy/Istio: Remove the Brotli decompressor from the configuration or EnvoyFilters and check the running configuration.
Cloudflare Workers and browsers
Anyone running applications as a Cloudflare Worker does not run their own Node.js process; the workerd runtime is operated and updated by Cloudflare. Cloudflare had not issued a statement on CVE-2026-111497 as of October 26, and customers cannot change the runtime themselves. However, the tools around the Worker remain affected: build scripts, wrangler and local development environments run on Node.js and should use a patched version. Browsers use their own Brotli implementations; vendor and security researcher reports do not identify them as affected.
Timeline
| Date | Event |
|---|---|
| February 2026 | OpenAI Codex Security reports the flaw; the fix lands in Brotli source code without a release |
| 10/21/2026 | Node.js releases 26.12.1, 24.22.1, and 22.23.4 |
| 10/22/2026 | Brotli 1.2.1 and brotlicffi 1.2.1.0 on PyPI; Imperva analysis with code execution |
| 10/23/2026 | Fixes for libbrotli, Bun, Envoy, and Istio |
| 10/24/2026 | brotli4j 1.24.0, packages for Amazon Linux 2023 |
| 10/25/2026 | Out-of-band updates for .NET |
| 10/26/2026 | Debian and Alpine patched, Fedora and Red Hat partially patched |
Comments
Comments are loaded from GitHub / Giscus.