Brotli flaw CVE-2026-111497 (Node2Shell) hits Python and other HTTP software

Brotli flaw CVE-2026-111497 (Node2Shell) hits Python and other HTTP software

Security firm Aikido has published a running explainer on CVE-2026-111497, an out-of-bounds write in the Google Brotli decoder. Brotli is a lossless compression format developed by Google and widely used for HTTP compression of HTML, CSS and JavaScript. The flaw affects Brotli versions 1.0.3 through 1.2.0 on all platforms and carries a CVSS v4.0 score of 9.2 (Critical).

According to the post, Node.js disclosed the bug in the middle of the week of October 21 and dubbed it "node2shell": a Node.js process that decompresses attacker-controlled Brotli data can be made to leak memory or run arbitrary code. Apps were exposed if they or a library decompress bad Brotli data, for example through the built-in fetch() or body-parser. Python followed with a security update for the same flaw. On Friday, October 23, it became known that the CVE also reaches other major languages and HTTP service applications, where patches were not yet fully available. The patching section of the post calls the wider problem HTTP2Shell.

A remote, unauthenticated attacker can send a crafted Brotli stream to corrupt memory, leak sensitive data, crash the process, or potentially execute arbitrary code. The decoder keeps accepting bytes when it should reject the data, and those bytes can overflow a small working buffer. In a later update, Aikido says OpenAI reported it discovered the vulnerability in February and described it as unauthenticated remote code execution that works in both directions: a malicious client can take over an unpatched server, and a malicious server can take over an unpatched client that accepts compressed responses.

The root cause was fixed in the Brotli source code in February, but nobody recognised it as a security issue then, and no release shipped with the fix until now. So every project that bundles Brotli has to ship its own update.

Technical detail: the flaw is in DecodeBlockTypeAndLength(), which handles block switches, the points where a stream changes which Huffman tree it uses. In vulnerable versions it returns a plain boolean, and BROTLI_FALSE can mean either "malformed stream" or "I need more input". Callers cannot tell them apart, and on the fast path the decoder discards the return value entirely. A crafted stream can declare a single block type and then exhaust that block's length, forcing a switch that cannot succeed. The decoder then either asks for more input on a complete stream, or keeps decoding with its old block state, which leads to the out-of-bounds write. The upstream fix, google/brotli commit 0ed4268, makes the function return an error code and adds a new error, BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH (-17), so decoding stops on a format error on both paths. OSM diffed the Brotli 1.2.0 and 1.2.1 source distributions and found 1.2.1 differs only in the version bump and the decoder changes from that commit.

Python is hit through two PyPI packages, Brotli and brotlicffi, which compile the same decoder Node.js bundles. Brotli has 82.8 million downloads per month. You are affected if any environment has Brotli 1.2.0 or earlier, or brotlicffi 1.2.0.x. HTTP clients such as requests (via urllib3), httpx with the brotli extra, aiohttp and Scrapy advertise Accept-Encoding: br and decode Brotli automatically, so an app can be exposed without importing Brotli in its own code. Attacker data arrives either in a Brotli response from a server the app calls (webhooks, URL previews, crawlers, "fetch this URL" features) or in a request body sent with Content-Encoding: br. The release notes for the fixed Python versions do not mention the CVE, and as of October 23 advisory databases do not map it to either PyPI package, so pip-audit, Dependabot and Safety will not flag vulnerable versions yet.

Fixed versions listed by Aikido: Node.js 22.23.4, 24.22.1 or 26.12.1 (or a newer supported release in the same line); native Brotli / libbrotli 1.2.1 or later, or 1.0.10 and 1.1.1 for older lines; Python Brotli 1.2.1 and brotlicffi 1.2.1.0; Bun 1.4.4 or later; Envoy 1.40.0, 1.39.3, 1.38.6 or 1.37.8 (1.36.12 also has the fix but that branch is unsupported); Istio 1.29.9, 1.30.6 and 1.31.2. For curl/libcurl, update the Brotli dependency; for operating-system packages, install the vendor's update, since vendors may backport the fix without changing the upstream version number. An update at 4:12PM PT said patches are available for libbrotli, Python, C++, Node.js, bun and Envoy, with more coming, and that Apache and Nginx do not decode Brotli by default.

Where an upgrade is not yet possible, Aikido recommends disabling Brotli decoding until patches arrive. Workarounds include uninstalling Brotli and brotlicffi in Python environments where Brotli is optional, rejecting inbound requests whose Content-Encoding includes br at the proxy, load balancer or middleware, and, for outbound requests, removing br from Accept-Encoding while also disabling Brotli response decoding or rejecting such responses before decoding starts.

Key facts

  • CVE-2026-111497 is an out-of-bounds write in the Google Brotli decoder, versions 1.0.3 through 1.2.0 on all platforms, with a CVSS v4.0 score of 9.2 (Critical).
  • First disclosed by Node.js as "node2shell", it also affects the Python Brotli and brotlicffi packages (Brotli has 82.8 million downloads per month) and other HTTP software that decodes Brotli.
  • OpenAI says it discovered the flaw in February; the root cause was fixed upstream then but not recognised as a security issue, and no release carried the fix until now.
  • Patched versions include Brotli 1.2.1, brotlicffi 1.2.1.0, Node.js 22.23.4, 24.22.1 and 26.12.1, Bun 1.4.4 and several Envoy and Istio releases.
  • Where no patch exists, Aikido recommends disabling Brotli decoding; Apache and Nginx do not decode Brotli by default.

Why it matters

Brotli is a standard way to compress web content, and the same decoder code is bundled into many runtimes and libraries. A crafted stream from an unauthenticated remote party can corrupt memory, leak data, crash the process or potentially lead to code execution, and the attack works both ways: against servers that accept compressed request bodies and against clients that accept compressed responses. Because the upstream fix shipped in no release until now, each project that bundles Brotli must publish its own update, which is why the problem is spreading from Node.js to Python and other HTTP software.

Who it affects

Anyone running Node.js, Python or other software that decodes Brotli with a version in the affected range. In Python, that means any environment with Brotli 1.2.0 or earlier or brotlicffi 1.2.0.x, including through requests, urllib3, httpx with the brotli extra, aiohttp or Scrapy, even if the code never imports Brotli. Aikido also lists curl/libcurl, Bun, Envoy, Istio, operating-system packages, and other HTTP servers, reverse proxies, API gateways and clients as needing updates. Apps that fetch URLs from untrusted servers (webhooks, URL previews, crawlers) or accept Brotli-encoded request bodies are the most exposed paths.

How to use it

Check whether you decode Brotli anywhere, including as a transitive dependency, and upgrade: Node.js to 22.23.4, 24.22.1 or 26.12.1; Python Brotli to 1.2.1 or later and brotlicffi to 1.2.1.0 or later (for example pip install -U "Brotli>=1.2.1"); Bun to 1.4.4 or later; Envoy to 1.40.0, 1.39.3, 1.38.6 or 1.37.8; Istio to 1.29.9, 1.30.6 or 1.31.2. Update lockfiles, rebuild container images and wheels that bundle the packages, check every environment including laptops and CI runners, redeploy and verify the running workloads. If you cannot upgrade, disable Brotli decoding, uninstall Brotli and brotlicffi where Brotli is optional, or reject br in Content-Encoding before any decoder touches the body. Removing br from Accept-Encoding alone is not enough, because a malicious server can send Brotli regardless.

How solid is it

The vulnerability details come from a vendor blog post by Aikido, which also sells a product that flags vulnerable versions, and the post is updated as events unfold. It cites a CVE, a CVSS score, an upstream commit (0ed4268), a Python advisory on GitHub and OpenAI's own account of finding the bug. The post is not fully consistent: it gives the Node.js disclosure date as October 21 in one place and October 22 in another. The OpenAI details are relayed by Aikido; the advisory contents are not reproduced in the post.

Risks and caveats

Patches are incomplete: the post says more are coming, and gives no patch versions for Apache, Nginx or other affected products. Scanners lag, since as of October 23 pip-audit, Dependabot and Safety will not flag the vulnerable PyPI versions. Bundled or statically linked copies need an updated application build, and managed services need confirmation from the provider. Uninstalling the Python packages can break responses from servers that send Brotli anyway, and automatic fallback to gzip or deflate is not guaranteed; it also does not remove Brotli decoders bundled into other runtimes or products. Code execution is described as a potential outcome, and the visible text gives no evidence of exploitation in the wild.

“Check if you are decoding Brotli as a dependency within your libraries.”

— Aikido