
Python packages are also vulnerable to the Node2Shell Brotli flaw (CVE-2026-111497)
Python2Shell is the Python-side impact of CVE-2026-111497 (Node2Shell), a Brotli decoder flaw (CVSS 4.0 9.2) in DecodeBlockTypeAndLength() that mixes an unchecked return value with an out-of-bounds write. Brotli 1.2.0 and earlier, and brotlicffi 1.2.0.x, are affected through urllib3, requests, httpx, aiohttp and Scrapy. Fixes are Brotli 1.2.1 and brotlicffi 1.2.1.0; as of 23 October 2026 advisory databases do not map the CVE to either package. The post lists checks and workarounds.
What it is
Python2Shell is the name the post gives to CVE-2026-111497 (Node2Shell) as it affects the PyPI packages Brotli and brotlicffi. Both compile the same Brotli decoder that Node.js bundles. The CVE record pairs CWE-252 (unchecked return value) with CWE-787 (out-of-bounds write) and scores it CVSS 4.0 9.2. Brotli has 82.8 million downloads per month.
How it works
DecodeBlockTypeAndLength() handles block switches, where a stream changes Huffman tree. In vulnerable versions it returns a plain boolean, so BROTLI_FALSE means either "malformed stream" or "need more input", and callers cannot tell which. On the fast path the decoder discards the return value entirely.
A crafted stream declares a single block type and then exhausts 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, returns an error code and adds BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH (-17). OSM found 1.2.1 differs from 1.2.0 only in the version bump and this commit's decoder changes.
Preconditions / Affected
Affected: Brotli 1.2.0 and earlier, brotlicffi 1.2.0.x. Your code need not import either package. urllib3 (so requests), httpx with the brotli extra, aiohttp and Scrapy decode Brotli automatically when the package is installed. Scrapy installs Brotli as a dependency.
Attacker data reaches the decoder two ways:
- Outbound: your app fetches a Brotli response from an attacker-controlled server (webhooks, URL previews, crawlers, "fetch this URL" features).
- Inbound: your framework or middleware decodes a request body sent with
Content-Encoding: br.
What to do
Upgrade to Brotli 1.2.1 or brotlicffi 1.2.1.0:
pip install -U "Brotli>=1.2.1"
pip install -U "brotlicffi>=1.2.1.0"With Poetry, uv or pip-tools, update the constraint and regenerate the lockfile. Rebuild container images and wheels that bundle either package. Check laptops, CI runners, servers and containers. If the bindings come from a Linux distribution package, wait for the distribution's fix.
To check exposure:
pip show Brotli brotlicffi
docker run --rm <image> pip show Brotli brotlicffi
pipdeptree -r -p Brotli
grep -i brotli poetry.lock uv.lock requirements*.txtPatch first the services that call servers you do not control or accept Content-Encoding: br bodies.
If you cannot upgrade yet, uninstall Brotli and brotlicffi. The HTTP clients fall back to gzip and deflate. Also remove extras such as httpx[brotli], or the next install restores the package. You can also strip br from Accept-Encoding on outbound requests and reject Content-Encoding: br inbound at the proxy, load balancer or middleware.
Caveats
- pip-audit, Dependabot and Safety will not flag this as of 23 October 2026. The CVE record, OSV and the GitHub Advisory Database do not list either PyPI package. The release notes for both fixed versions omit the CVE. OSM is submitting PYSEC entries and a package mapping.
- Header filtering does not protect outbound traffic: a malicious server can send Brotli regardless, and urllib3 decodes based on the response's Content-Encoding header. Only uninstalling covers both directions.
- OSM did not pursue memory corruption or code execution in the Python extension. Under AddressSanitizer, 1.2.0 consumed a roughly 23 MB crafted stream and kept asking for more input, even in one-byte chunks, while 1.2.1 rejected it with error -17. The decoder code is the same that researchers exploited against Node.js 24.22.0, per Imperva and others.
- The Hacker News reported no exploitation in the wild for Node.js as of 22 October 2026.
brotli.decompress()raises only a genericbrotli.error, so the error code is not visible. ADecompressor()fed the stream incrementally never finishes on 1.2.0.
Timeline: fix first committed February 2026. Upstream fixed releases and Node.js patches came 21 October 2026. Brotli 1.2.1 reached PyPI 22 October, and brotlicffi 1.2.1.0 on 23 October.
Organisations named here
- CWE-252
- CWE-787
- Imperva
- Python2Shell
CVEs named here
- CVE-2026-111497
Technologies named here
- Aikido
- brotlicffi 1.2.0.x, fixed in 1.2.1.0
- pip-audit
- Node.js
- Dependabot
- httpx with the brotli extra
- pipdeptree
- AddressSanitizer
- OSV and GitHub Advisory Database
- Scrapy
- Express 5
- OpenSourceMalware.com
- Linux distribution packages of the Python Brotli bindings
- Poetry, uv, pip-tools
- Brotli
- PyPI
- Python
- urllib3
- httpx
- OpenSourceMalware
- brotlicffi
Techniques named here
- Request body compressed with Content-Encoding
- OSM test
Threat actors named here
- Node2Shell
Related in AppSec
Flowise MCP Security Bypass Enables RCE
Inside an Oracle Database SQL Injection Attack | Huntress
OASIS
