TECHNOLOGY
Brotli decoder flaw behind Node2Shell reaches Python and other HTTP software, with patches rolling out
CVE-2026-111497, a critical bug in Google's Brotli decoder first disclosed as Node2Shell, also affects Python packages and other HTTP tools. Patches exist for several projects, but advisory scanners may not flag the problem yet.
Image: IntraGoals Media
A serious bug in Google's Brotli decoder, first disclosed as "Node2Shell", affects far more than Node.js. CVE-2026-111497 also hits Python packages and other software that handles HTTP traffic. Some patches are out, and others are still on the way.
Brotli is a lossless compression format developed by Google. It makes data smaller for storage or sending over the internet, and software unpacks it to get the original back. It is widely used in HTTP compression for web content like HTML, CSS and JavaScript.
CVE-2026-111497 is an out-of-bounds write in the Brotli decoder, in versions 1.0.3 through 1.2.0 on all platforms. An out-of-bounds write means a program writes data outside the memory it was meant to use. A remote attacker with no login can send a crafted Brotli stream to corrupt memory, leak sensitive data, crash the process, or potentially run their own code. The flaw has a CVSS v4.0 score of 9.2, which is rated Critical. Node.js is affected through its bundled Brotli library.
Here is how the bug works. The decoder keeps accepting more bytes when it should reject the data. Those bytes can overflow a small working buffer and damage the program's memory, and an attacker can use that damage to control what runs.
The timeline, as the report gives it: Node.js disclosed the flaw on Wednesday. Python disclosed that its packages were vulnerable the next day. By Friday, October 23, it was clear other languages and HTTP-based applications were affected too, and patches were not yet fully available. The draft gives slightly different dates for the Node.js disclosure (October 21 in one place, October 22 in another), so that date should be confirmed.
OpenAI says it found the vulnerability in February and reported it as unauthenticated remote code execution that works in both directions. A malicious client could take over an unpatched server, and a malicious server could take over an unpatched client that accepts compressed responses. The root cause was fixed in the Brotli source code that month. But nobody recognized it as a security issue, and no release shipped with the fix until now. So every project that bundles Brotli has to ship its own update.
In Python, two PyPI packages, Brotli and brotlicffi, compile the same vulnerable decoder that Node.js bundles. You are affected if any environment has Brotli 1.2.0 or earlier, or brotlicffi 1.2.0.x. HTTP clients such as requests, httpx and aiohttp load these packages automatically when they are present. Scrapy installs Brotli as a dependency. So an app can be exposed without ever importing Brotli in its own code. The report says Brotli gets 82.8 million downloads a month.
Attacker data can reach the decoder in two ways. One is an outbound request, where your app fetches a Brotli response from a server the attacker controls, for example through a webhook, URL preview or crawler. The other is an inbound request, where a framework or middleware decodes a request body sent with Content-Encoding: br.
The fix for Python is to upgrade to Brotli 1.2.1 or brotlicffi 1.2.1.0, then rebuild any container images or wheels that bundle them. An image built on a vulnerable version stays vulnerable until it is rebuilt. Release notes for both fixed versions don't mention the CVE. As of October 23, advisory databases don't map it to either PyPI package, so pip-audit, Dependabot and Safety won't flag vulnerable versions yet. A manual check is needed for now.
Other projects have patches too. Node.js users should move to 22.23.4, 24.22.1 or 26.12.1, or a newer release in their line. Native libbrotli should go to 1.2.1 or later, or the patched 1.0.10 or 1.1.1 for older lines. Bun's fix is in 1.4.4. Envoy has fixes in 1.40.0, 1.39.3, 1.38.6 and 1.37.8, and Istio in 1.29.9, 1.30.6 and 1.31.2. The Envoy 1.36 and Istio 1.29 branches are unsupported or end of life, so users there should move to a supported line. For curl and operating-system packages, install the vendor's security update, since vendors may backport the fix without changing the upstream version number. Apache and Nginx do not decode Brotli by default, and Apache's standard mod_brotli does not decode it.
If you can't upgrade yet, there are workarounds. In Python, where Brotli is optional, you can uninstall both Brotli and brotlicffi. HTTPX, Requests and urllib3 keep gzip and deflate support. But a server that sends Brotli anyway may produce an unreadable response or an error. This also won't remove separate Brotli decoders bundled into other runtimes or products.
For incoming requests, reject any whose Content-Encoding includes br at the reverse proxy, load balancer or middleware, before a decoder touches the body. For outgoing requests, remove br from Accept-Encoding, and also block Brotli responses before decoding starts. Changing Accept-Encoding alone is not enough, because a malicious server can send Brotli whatever the client asks for.
On exploitation, the report says researchers at Imperva and others exploited the same decoder code against an unmodified Node.js 24.22.0 build. The Hacker News reported no exploitation in the wild for Node.js as of October 22. A separate analysis by OSM built Brotli 1.2.0 and 1.2.1 with AddressSanitizer, a memory-error checker, and ran a crafted stream of roughly 23 MB through both. Version 1.2.0 consumed the whole stream and kept asking for more input. Version 1.2.1 rejected it with error -17 every time. OSM did not test memory corruption or code execution in the Python extension.
The technical cause sits in a function called DecodeBlockTypeAndLength(), which handles points where a Brotli stream switches Huffman trees. In vulnerable versions it returns a plain true/false value, and false can mean either "this stream is malformed" or "I need more input." Callers can't tell the two apart, and on the fast path the decoder discards the value entirely. 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). OSM reports that 1.2.1 differs from 1.2.0 only in the version bump and this commit's decoder changes.
The practical advice is simple. Check which Brotli versions you run, including in containers, CI runners and laptops. Upgrade first the services that call outside servers or accept compressed request bodies, then the rest. If a library or app has no patch yet, disable Brotli decoding until one arrives.