Node2Shell: Brotli Flaw Hits Python Packages
The Node2Shell Brotli flaw (CVE-2026-111497), disclosed alongside Node.js fixes on October 21, 2026, also reaches Python through the PyPI Brotli and brotlicffi packages. Both compile Google’s vulnerable Brotli C decoder, and popular HTTP clients such as requests, httpx and aiohttp use them to decompress responses automatically once they are installed.
That makes exposure easy to miss. A Python service can hand attacker-controlled Brotli data to the decoder without a single Brotli import in its own code. No exploitation in the wild has been reported, but researchers have already shown Remote Code Execution (RCE) against Node.js through the same decoder code, so Python teams should move to the fixed versions, Brotli 1.2.1 and brotlicffi 1.2.1.0, without waiting.
Key Takeaways
- Shared Decoder Bug: CVE-2026-111497 is an out-of-bounds write in Google’s Brotli C decoder, versions 1.0.3 through 1.2.0, scored 9.2 under CVSS v4.0
- Python Exposure: PyPI Brotli 1.2.0 and earlier and brotlicffi 1.2.0.x and earlier bundle the flawed decoder; the fixed versions are Brotli 1.2.1 and brotlicffi 1.2.1.0
- Silent Path: urllib3, requests, httpx and aiohttp decode Brotli automatically when a backend is installed, so applications can be exposed without calling Brotli directly
- Exploitation Status: No in-the-wild exploitation has been reported, and public RCE research covers Node.js, not the Python extension
- Next Step: Upgrade, rebuild images and restart long-running workers so the patched extension actually loads
CVE-2026-111497 at a Glance
The table below summarizes the Node2Shell vulnerability as it applies to Python environments.
| Attribute | Details |
|---|---|
| CVE ID | CVE-2026-111497 |
| Common Names | Node2Shell, also HTTP2Shell and Brotli2Shell |
| Weakness | CWE-787 (Out-of-Bounds Write), CWE-252 (Unchecked Return Value) |
| Severity | 9.2 Critical (CVSS v4.0, Google as CNA); 8.1 (CVSS v3.1, a Linux distribution advisory and the .NET advisory) |
| Affected Upstream Versions | Brotli 1.0.3 through 1.2.0 |
| Affected Python Packages | Brotli 1.2.0 and earlier; brotlicffi 1.2.0.x and earlier |
| Fixed Versions | Upstream Brotli 1.0.10, 1.1.1 and 1.2.1; PyPI Brotli 1.2.1; brotlicffi 1.2.1.0 |
| Python Advisories | PYSEC-2026-4322 (Brotli), PYSEC-2026-4323 (brotlicffi) |
| Exploitation Status | No in-the-wild exploitation reported as of October 26, 2026 |
| Reported By | Khai Tran and Sylvie Mayer, OpenAI Codex Security |
What Is the Node2Shell Brotli Vulnerability?
Node2Shell is the most widely used name for CVE-2026-111497, a memory safety flaw in the decoder of Google’s Brotli compression library. Its CVE record says a remote, unauthenticated attacker can use a crafted Brotli stream to corrupt adjacent decoder memory, with possible information disclosure, denial of service or arbitrary code execution.

Google, acting as the CVE Numbering Authority (CNA), published the record on October 22, 2026, with a CVSS v4.0 score of 9.2 (CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N). The Node2Shell name comes from researchers who demonstrated code execution against Node.js.
What Causes the Out-of-Bounds Write?
The bug sits in block switch handling in the decoder source file c/dec/decode.c. The DecodeBlockTypeAndLength() function returned an ambiguous result for an invalid block switch, and the fast decoding path ignored that return value. As the Node.js security release explains, the streaming decoder then treated a permanent format error as a temporary need for more input and kept appending bytes to an eight-byte internal buffer.
The upstream fix adds a dedicated error code, BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH (-17), so decoding stops on the malformed stream. The change entered Brotli’s source in February 2026 but reached tagged releases only on October 21, 2026, as Brotli 1.0.10, 1.1.1 and 1.2.1.
Why Does Node2Shell Affect Python Packages?
Python inherits the flaw because two PyPI packages compile Google’s C decoder into native extensions. Brotli is Google’s official CPython binding, and brotlicffi is a CFFI-based binding often used on PyPy. The PYSEC-2026-4322 advisory notes that Brotli 1.2.1 contains the upstream fix and otherwise differs from 1.2.0 only by a version bump.
The Brotli package alone draws over 82 million downloads a month, and it often arrives as a transitive dependency or optional extra that teams never chose directly.
Which Python Package Versions Are Affected?
Every release of both packages before the fixed versions is affected. Both fixes were published on PyPI on October 22, 2026, and the PyPI advisory database added entries for them on October 23.
| Package | Role | Affected Versions | Fixed Version | Advisory |
|---|---|---|---|---|
| Brotli | Google’s CPython binding | 1.2.0 and earlier | 1.2.1 | PYSEC-2026-4322 |
| brotlicffi | CFFI binding, common on PyPy | 1.2.0.x and earlier | 1.2.1.0 | PYSEC-2026-4323 |
A community analysis found that no advisory database listed the PyPI packages immediately after disclosure, so dependency scans run before October 23 may have missed them. Distribution-packaged Python bindings follow their own versioning and may carry backported fixes, so check the relevant Linux vendor advisory.
How Can Attackers Reach the Brotli Decoder in Python?
Exploitation requires a path that delivers attacker-controlled Brotli data to the decoder. The flaw works in both directions: a malicious server can target a vulnerable client, and a malicious client can target a vulnerable server.
Outbound HTTP Responses
Once Brotli or brotlicffi is installed, urllib3 and requests decode Brotli responses automatically, httpx does so with its brotli extra, and aiohttp does so when Brotli is present. Services that fetch attacker-influenced URLs, such as webhook senders, link previewers, crawlers and Scrapy-based scrapers, are the most direct targets.
Inbound Request Bodies
Applications or middleware that decompress request bodies sent with Content-Encoding: br pass client-supplied data straight to the decoder. This path depends on the framework and its configuration, so teams should confirm whether any proxy, middleware or handler decodes Brotli bodies.
Bundled Decoders Outside the PyPI Packages
Some Python libraries ship their own Brotli copy. Apache Arrow pins a bundled Brotli 1.0.9, and its tracking issue was still open on October 26, 2026. Further research showed a 534-byte input sending pyarrow into an endless loop with no network connection involved, and upgrading the Brotli package does not patch such embedded copies.
Has Node2Shell Been Exploited in the Wild?
As of October 26, 2026, no in-the-wild exploitation of CVE-2026-111497 has been reported. CISA’s Stakeholder-Specific Vulnerability Categorization (SSVC) entry in the CVE record, dated October 23, 2026, lists exploitation as “none,” automatable as “no” and technical impact as “total.”
That status can change quickly for a bug with this much detailed public research. Teams should watch for exploitation reports and any addition to CISA’s Known Exploited Vulnerabilities (KEV) catalog.
Is There a Public PoC for CVE-2026-111497?
There is no public, reliable RCE Proof-of-Concept (PoC), and Red Hat states that the attack complexity is rated high, partly because of platform hardening such as ASLR and NX. Published research demonstrates impact, which is not the same as a reliable, weaponized exploit.
For Python specifically, no public research has shown memory corruption or code execution in the Brotli or brotlicffi extensions. The concern comes from the shared decoder code that already produced code execution on Node.js.
What Have Researchers Demonstrated?
Results differ by platform, and the strongest evidence comes from Node.js:
- Node.js: Researchers ran code on the official Node.js 24.22.0 Linux arm64 image through fetch() responses and Express 5 or body-parser 2 request bodies; the proof took multiple attempts and did not succeed every time
- Python: The community analysis built Brotli 1.2.0 and 1.2.1 with AddressSanitizer; 1.2.0 accepted a crafted stream of about 23 MB and kept asking for more input, while 1.2.1 rejected it with error -17, and memory corruption was not pursued
- Other Software: Separate testing crashed a ClickHouse server with a single 23 MB request, gained instruction pointer control in FFmpeg through libjxl, and caused a native crash in a .NET test program
Severity ratings diverge as well. Microsoft’s .NET advisory scores the flaw 8.1 under CVSS v3.1 and lists information disclosure, denial-of-service (DoS) and elevation of privilege, not RCE.
Which Other Runtimes Need a Patch?
Python services often run beside components that bundle their own decoder, and each needs a separate update. Exposure depends on whether the component decodes untrusted Brotli data.
| Product | Fixed In | Exposure Condition |
|---|---|---|
| Node.js | 22.23.4, 24.22.1, 26.12.1 | Applications decompress untrusted Brotli data with node:zlib |
| .NET | 8.0.33, 9.0.22, 10.0.14, 11.0 RC3 | Brotli enabled in ASP.NET Core request decompression or HttpClient, or BrotliStream/BrotliDecoder used on untrusted data |
| Envoy | 1.40.0, 1.39.3, 1.38.6, 1.37.8, 1.36.12 | Brotli decompressor configured |
| Istio | 1.31.2, 1.30.6, 1.29.9 | Brotli decompression enabled, for example through an EnvoyFilter |
| Apache Arrow (including pyarrow) | No fix as of October 26, 2026 | Bundled Brotli 1.0.9 decodes Brotli-compressed data in pyarrow |
Linux distributions are shipping Brotli updates on separate schedules, so check each vendor’s security tracker.
How to Check if Your Python Environment Is Affected
Brotli rarely appears in a top-level requirements file, so the inventory has to cover every place Python runs:
- Find Installed Versions: Run pip show Brotli brotlicffi in every virtual environment, container image, CI runner and serverless layer
- Trace Dependencies: Use pipdeptree -r -p Brotli to see which packages pulled Brotli in
- Scan With Current Data: Run pip-audit, which draws on the PyPI advisory data where both packages are now listed
- Look for Embedded Copies: Inventory pyarrow, Node.js binaries, Envoy sidecars and other components that compile their own Brotli
Patch and Upgrade Steps for Brotli and brotlicffi
Upgrading the two packages closes the most common Python path, but only if every running process loads the fixed build:
- Upgrade with pip install -U “Brotli>=1.2.1” “brotlicffi>=1.2.1.0”
- Set those minimum versions in requirements files and regenerate lockfiles
- Rebuild container images and wheels that bundle either package, then redeploy
- Restart long-running workers and services, since a running process keeps the old extension in memory
Patch services that fetch untrusted URLs or accept compressed request bodies first. Afterward, confirm the version each running process actually loads.
How SOCRadar Can Help
A shared library flaw gets fixed across packages, runtimes and distributions at different speeds, which makes status tracking the hard part. SOCRadar helps security teams identify exposure and track patches across their environments through several key capabilities:
- Vulnerability Intelligence and CVE Radar: Track CVE-2026-111497 as upstream releases, vendor advisories, PoC availability and CISA KEV status change, so teams can reprioritize without checking dozens of advisories by hand.
- Attack Surface Management: Discover internet-facing assets built on affected technologies, such as Node.js services or Envoy proxies, so patching starts with the most exposed entry points.
- Supply Chain Intelligence: Monitor third-party vendors and suppliers whose products may bundle the vulnerable decoder, as their advisories and patch status change.
- Dark Web Monitoring: Get early warning if exploit code or targeting discussions for Node2Shell surface in underground channels.

Mitigations if You Cannot Patch Yet
These steps reduce exposure while an upgrade is pending, but none replaces the fixed versions:
- Remove the Backend: Uninstalling Brotli and brotlicffi makes common HTTP clients fall back to gzip or deflate, though servers that send Brotli anyway may then cause errors
- Block Inbound Brotli: Reject requests whose Content-Encoding includes br at the proxy or middleware layer, before any decoding
- Refuse Outbound Brotli: Stop advertising br and reject Brotli responses before decoding, since dropping br from Accept-Encoding alone does not stop a malicious server from sending it
Detection and Hunting Considerations
The vendor advisories for CVE-2026-111497 do not list indicators of compromise. The Node.js research notes that unexpected process exits during decompression and decoder errors can help prioritize investigation, but neither is a reliable standalone sign of exploitation.
Useful hunting hypotheses include crashes in Python workers that fetch external URLs, unexpected Content-Encoding: br headers in inbound logs, and crawler or webhook services contacting unfamiliar hosts. Edge WAF rules generally cannot inspect responses fetched from other servers or Brotli data inside files, so a clean result does not prove a service was never targeted.

