
Python Packages Vulnerable to Node2Shell
Analysis of CVE-2026-111497 (Node2Shell), an out-of-bounds write in Google's Brotli C decoder, showing it also affects the PyPI packages Brotli (all releases up to 1.2.0) and brotlicffi (up to 1.2.0.2). The author diffed the 1.2.0 and 1.2.1 sdists and confirmed the behaviour with AddressSanitizer. Fixes are Brotli 1.2.1 and brotlicffi 1.2.1.0, both patched without release notes. No advisory database lists either package yet.
What it is
CVE-2026-111497 ("Node2Shell", CNA: Google, CVSS 4.0 9.2) is an out-of-bounds write in the Brotli C decoder (c/dec/decode.c in google/brotli). It is not a Node.js bug. The PyPI packages Brotli and brotlicffi compile the same decoder, so they are affected. The CVE record names only github.com/google/brotli and does not mention PyPI.
How it works
DecodeBlockTypeAndLength() returns a plain boolean, so "malformed stream" and "need more input" look the same to callers. On the fast (unsafe) path the BROTLI_SAFE macro discards the return value. A stream that declares one block type and then exhausts the block length forces a block switch that cannot succeed. The decoder then either reports "needs more input" for a complete stream or continues with invalid block state, which causes the write. The CWE pairing is CWE-252 leading to CWE-787.
The upstream fix is commit 0ed4268. It returns a BrotliDecoderErrorCode, adds BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH (-17), and stops decoding on both paths.
Preconditions / Affected
- Brotli: every PyPI release up to 1.2.0 (including 0.5.2, 0.6.0, 1.0.x, 1.1.0). The author found no safe older version. Fixed in 1.2.1 (22 October 2026), whose sdist differs from 1.2.0 only in
version.h,decode.canddecode.h. - brotlicffi: 1.2.0.1 (March 2026) and 1.2.0.2 (August 2026) bundle the vulnerable decoder. Earlier releases were not checked. Fixed in 1.2.1.0 (23 October 2026).
- Upstream fixed versions are 1.0.10, 1.1.1 and 1.2.1.
- Exposure comes from clients that decode
Content-Encoding: brautomatically when Brotli is installed: urllib3 (and so requests), httpx with the brotli extra, aiohttp, Scrapy. Webhook delivery, URL previews, crawlers and "fetch this URL" features hand attacker-controlled data to the decoder. Middleware that decodes inboundbrrequest bodies is also exposed. - Brotli 1.1.0 was the only release between August 2023 and October 2025, so many environments have it pinned.
What to do
Upgrade, then rebuild container images or wheels that bundle either package:
pip install -U "Brotli>=1.2.1" "brotlicffi>=1.2.1.0"Check each environment with pip show Brotli and pip show brotlicffi. pip-audit, Dependabot and Safety will not flag this yet: OSV has only a Git range, the GitHub Advisory entry lists no PyPI package, and google/brotli has published no security advisory.
If you cannot upgrade, either uninstall both packages (the HTTP clients above fall back to gzip/deflate) or strip br from outbound Accept-Encoding and reject inbound Content-Encoding: br.
Caveats
- The author built the Brotli 1.2.0 and 1.2.1 sdists with AddressSanitizer. The crafted stream made 1.2.0 consume about 23 MB and return NEEDS_MORE_INPUT, in one shot and in 1-, 13-, 4096- and 65536-byte chunks. 1.2.1 returned error -17 every time.
- The memory corruption and code execution were not reproduced in the Python extension. The author relies on the Node.js write-ups because the code is the same.
- brotlicffi sdists were not diffed or fuzzed.
- From Python,
brotli.decompress()raises a barebrotli.error, so the error code is not visible. ADecompressor()fed incrementally never finishes on 1.2.0. - The author is submitting PYSEC entries and a GitHub advisory package mapping. Both were pending as of 23 October 2026.
Organisations named here
- CWE-252
- CWE-787
- Imperva
- OSM Security
- silent patching
CVEs named here
- CVE-2026-111497
Technologies named here
- PyPI Brotli
- AddressSanitizer
- PyPI brotlicffi
- C harness against each sdist's decoder
- google/brotli C library
- pip-audit, Dependabot and Safety
- OSV, PYSEC and GitHub Advisory Database
- Brotli
- PyPI
- Python
- Node.js
- pip
- brotlicffi
Techniques named here
- Unchecked return value in DecodeBlockTypeAndLength
- Sdist diffing to identify a silent security patch
Threat actors named here
- Node2Shell
- PHP2Shell
Related in AppSec
Flowise MCP Security Bypass Enables RCE
Inside an Oracle Database SQL Injection Attack | Huntress
OASIS
