26 October 2026 7 min read

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-in fetch() 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 identifies body-parser 2.0.0 through 2.3.0 and Express 5.0.0 through 5.3.0 with configured json() or raw() parsers for Node.js. A bare Node.js http server 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

ComponentPatched versionsNote
libbrotli (Google Brotli)1.2.1, 1.1.1, 1.0.10versions 1.0.3 through 1.2.0 are affected
Node.js26.12.1, 24.22.1, 22.23.4Release of October 21, 2026; includes additional fixes (DNS, TLS name verification)
Bun1.4.4rebuild executables created with bun build --compile
Python Brotli1.2.1automatically used by urllib3, requests, and aiohttp when installed
Python brotlicffi1.2.1.0likewise; also available as the httpx[brotli] extra
.NET8.0.33, 9.0.22, 10.0.14, 11 RC3Out-of-band update of October 25, 2026; .NET Framework is not affected, .NET 7 has no fix
Envoy1.40.0, 1.39.3, 1.38.6, 1.37.8only with the Brotli decompressor filter
Istio1.31.2, 1.30.6, 1.29.9only with a Brotli decompressor in an EnvoyFilter
Java brotli4j1.24.0JNI wrapper bundles its own Brotli copy
curl/libcurlBuilt against Brotli 1.2.1only 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
Options explained
OptionEffect
node -voutputs the version of the active Node.js installation
pip show Brotli brotlicffishows the version and dependents of the two Python packages, if installed
pipdeptreelists the dependency tree of installed Python packages (must be installed separately)
-rreverses the tree: shows which packages include the named package
-p Brotlilimits output to the Brotli package

On Debian/Ubuntu and Alpine, the package manager shows the version of the system library:

dpkg -l 'libbrotli*'
apk info -v brotli-libs
Options explained
OptionEffect
dpkg -l 'libbrotli*'lists all installed packages whose name begins with libbrotli, including their version
apk info -v brotli-libsdisplays the Alpine package brotli-libs with its version number

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
Options explained
OptionEffect
node-version: 22selects the latest available version in the 22.x line
check-latest: truequeries the Node.js version directory on every run and downloads a newer version instead of using the version in the tool cache

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-Encoding containing br at the reverse proxy or in middleware. The comparison must be case-insensitive and also cover lists such as gzip, br.
  • Outgoing: Remove br from Accept-Encoding and discard responses with Content-Encoding: br before decoding. Removing it from Accept-Encoding alone is not sufficient because a crafted server can send the encoding anyway. This is not possible with the built-in fetch() in Node.js and Bun; only updating helps there.
  • curl: Omit --compressed; in libcurl, leave CURLOPT_ACCEPT_ENCODING set to NULL.
  • Python: Uninstall Brotli and brotlicffi, and remove extras such as httpx[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

DateEvent
February 2026OpenAI Codex Security reports the flaw; the fix lands in Brotli source code without a release
10/21/2026Node.js releases 26.12.1, 24.22.1, and 22.23.4
10/22/2026Brotli 1.2.1 and brotlicffi 1.2.1.0 on PyPI; Imperva analysis with code execution
10/23/2026Fixes for libbrotli, Bun, Envoy, and Istio
10/24/2026brotli4j 1.24.0, packages for Amazon Linux 2023
10/25/2026Out-of-band updates for .NET
10/26/2026Debian and Alpine patched, Fedora and Red Hat partially patched

Sources

  1. Node.js: October 2026 Security Releases

    official advisory with the cause, affected lines and fixed versions, as well as nine additional CVEs in the same release.

    https://nodejs.org/en/blog/vulnerability/october-2026-security-releases
  2. NVD: CVE-2026-111497

    CVE entry with a CVSS 4.0 score of 9.2.

    https://nvd.nist.gov/vuln/detail/cve-2026-111497
  3. Imperva: Node2Shell, from Brotli data to remote code execution

    technical analysis demonstrating code execution, the client and server paths in Node.js, and affected versions of Express and body-parser.

    https://www.imperva.com/blog/node2shell-from-brotli-data-to-remote-code-execution/
  4. Aikido: Python packages vulnerable to Node2Shell

    cause in DecodeBlockTypeAndLength(), fixed versions across all ecosystems, timeline, and mitigations; continuously updated.

    https://www.aikido.dev/blog/python-packages-vulnerable-node2shell-brotli-cve-2026-111497
  5. Microsoft .NET Blog: .NET October 2026 out-of-band security updates
  6. Broccoli2Shell

    information page on the vulnerability under its second name.

    https://broccoli2shell.com/
  7. heise online: Brotli decoder flaw not only in Node.js, but also in Bun, Python, and more
  8. actions/setup-node: check-latest

    documentation for the option that checks the tool cache against the version directory on every run.

    https://github.com/actions/setup-node#check-latest-version

Comments

Comments are loaded from GitHub / Giscus.