
The node2shell Brotli vulnerability (CVE-2026-111497, CVSS v4.0 9.2) is an out-of-bounds write in Google's Brotli decoder. Node.js disclosed it on October 21, and code execution has already been shown against Node.js. Attacker bytes reach the decoder through request bodies, through responses to your own outbound fetches, and through Brotli copies that scanners did not flag.
Key takeaways
- CVE-2026-111497 (node2shell) is an out-of-bounds write in Brotli 1.0.3-1.2.0, rated CVSS v4.0 9.2.
- A malicious server can trigger it through outbound fetches in urllib3 and requests, even when the client does not advertise Brotli.
- Fixed in February 2026 but unreleased until October; as of October 23, pip-audit, Dependabot and Safety did not flag vulnerable Brotli or brotlicffi.
- RCE was demonstrated against unmodified Node.js 24.22.0; no in-the-wild exploitation had been reported as of October 22.
What is the node2shell Brotli vulnerability?
It is an out-of-bounds write in Brotli 1.0.3 through 1.2.0, on all platforms, in DecodeBlockTypeAndLength(), the function that handles Huffman block switches.
The function returns a plain boolean: BROTLI_FALSE means either “malformed stream” or “need more input,” and the fast path ignores it. A crafted stream declares a single block type, exhausts its length and forces a block switch that cannot succeed. The decoder continues with stale state and writes past a small working buffer: CWE-252 (unchecked return value) leading to CWE-787 (out-of-bounds write).
Upstream commit 0ed4268 swaps the boolean for an error code, BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH (-17), and stops decoding on both paths. OSM diffed the releases: Brotli 1.2.1 contains only that change plus a version bump. Older lines are patched in 1.0.10 and 1.1.1.
Can a malicious server exploit your HTTP client?
Yes, and most teams leave this half out of scope. Inbound, any middleware that decodes Content-Encoding: br on request bodies, including Node’s body-parser, feeds attacker bytes straight to the decoder.
Outbound needs no inbound exposure. Webhook delivery, link previews, crawlers and “fetch this URL” features let an attacker’s server answer with a Brotli body. Dropping br from Accept-Encoding does not help in urllib3, and therefore requests: it picks the decoder from the response’s Content-Encoding header, not from what the client advertised. httpx with the brotli extra, aiohttp with Brotli installed, Scrapy (which installs Brotli) and Node’s built-in fetch() also decode automatically.
During SSRF testing, we point these features at a controlled server that returns Brotli unasked and check whether decoding happens before application logic sees the response.
Which products ship fixes?
Node.js is fixed in 22.23.4, 24.22.1 and 26.12.1. A day after its disclosure, the PyPI packages Brotli (1.2.0 and earlier) and brotlicffi (1.2.0.x) were confirmed vulnerable; fixes are Brotli 1.2.1 and brotlicffi 1.2.1.0.
- libbrotli: 1.2.1, or 1.0.10 and 1.1.1 for older lines
- Bun: 1.4.4; rebuild compiled executables that bundle it
- Envoy: 1.40.0, 1.39.3, 1.38.6, 1.37.8 (1.36.12 is fixed but unsupported)
- Istio: 1.29.9, 1.30.6, 1.31.2 (1.29 is end of life)
curl and libcurl need an updated Brotli dependency; statically linked copies need a rebuild. In Envoy and Istio, decoding happens in the proxy, so exposure depends on whether a Brotli decompressor sits in the filter chain. Apache and Nginx do not decode Brotli by default.
Why don't pip-audit or Dependabot flag CVE-2026-111497?
The root cause was fixed in February, but nobody labeled it a security issue and no release shipped for eight months. As of October 23, advisory databases had not mapped the CVE to either PyPI package, and the fixed releases’ notes do not mention it. So pip-audit, Dependabot and Safety missed vulnerable installs of Brotli, which is downloaded 82.8 million times a month.
Even after mapping, compiled copies stay hidden. Python wheels carry their own Brotli, so patching the OS libbrotli does not change what a virtualenv or container loads. Vendored and static copies often have no package record, and an SBOM helps only where someone recorded the component.
Can node2shell execute code, or only crash the process?
Against Node.js, yes: Imperva reported that researchers exploited an unmodified Node.js 24.22.0 build. Elsewhere the bug is a plausible primitive with no demonstrated chain. OpenAI says it found the flaw in February and, per Aikido, reported it as unauthenticated RCE in both directions: malicious client against server, malicious server against client.
OSM built 1.2.0 and 1.2.1 with AddressSanitizer. Version 1.2.0 consumed a roughly 23 MB crafted stream while reporting “needs more input,” whether fed whole or byte by byte, so chunking is not a mitigation. Version 1.2.1 rejected it with error -17 every time.
Checklist: what to do today
- Inventory. Check every virtualenv (pip show brotli brotlicffi), container image, serverless bundle and sidecar; our container security assessment covers images.
- Upgrade and restart. Move to the fixed versions above, regenerate lockfiles, rebuild images that bundle the decoder and restart so the new native code loads. For dynamically linked libbrotli, install the vendor update.
- Map your mesh. List Envoy and Istio filter chains that decode Brotli and prioritize them in your Kubernetes review.
- Test outbound. Point every outbound fetch feature at a server that returns Brotli unprompted.
- Disable where you can’t patch. Uninstall unused bindings such as httpx[brotli]. At the edge, reject request bodies with br in Content-Encoding, case-insensitively, before any decoder runs.
- Review telemetry. Correlate native crashes, worker restarts and OOM kills with Brotli traffic.
FAQ
Am I affected if my app never imports Brotli?
Possibly. urllib3, requests, httpx with the brotli extra, aiohttp and Scrapy decode Brotli automatically when the binding is installed, and Scrapy installs it by default.
Is CVE-2026-111497 exploited in the wild?
Not as of October 22, 2026, though a working exploit was demonstrated against an unmodified Node.js 24.22.0 build.
Are nginx or Apache vulnerable to node2shell?
Not by default. Neither decodes Brotli out of the box, and Apache's standard mod_brotli does not decode Brotli.
If your product fetches URLs, delivers webhooks or decodes compressed bodies, an API penetration test from agent::offense will identify which decoders attacker-controlled bytes can reach, in both directions.