Brotli Vulnerability CVE-2026-111497 (Node2Shell / HTTP2Shell)
How to Check Exposure and Patch Node.js, Python, Bun and Envoy
CVE-2026-111497 (HTTP2Shell): a crafted Brotli stream causes an out-of-bounds write. Fixed versions for Node.js, Python, Bun, check commands and mitigations.
CVE-2026-111497 is an out-of-bounds write in Google's Brotli decoder (versions 1.0.3 to 1.2.0) that a crafted compressed stream can trigger. It was first called "Node2Shell" in the Node.js disclosure and became "HTTP2Shell" once it turned out to affect HTTP libraries and applications broadly. Node.js, Python, Bun, Envoy, Istio, curl and anything else that decodes Brotli-compressed HTTP traffic is in scope. Check which Brotli version you run and which code paths feed it untrusted data, then update to a fixed release (libbrotli 1.2.1; Node.js 22.23.4, 24.22.1 or 26.12.1; and so on).
This article is based on Aikido Security's write-up and on coverage of the October 2026 Node.js security release, published between October 21 and 24, 2026. It covers how to tell whether you are exposed, what to do per runtime, and what to do while you cannot patch. Versions and dates are limited to what those sources confirm; where something is unclear we say "check the official advisory". Severity differs by source: Aikido's article rates it CVSS v4.0 9.2 (Critical), while Node.js rates it High.
The short version
- What: DecodeBlockTypeAndLength() in the Brotli decoder mishandles its return value, so a crafted stream causes an out-of-bounds write. The impact ranges from a process crash and memory disclosure to memory corruption and possible arbitrary code execution
- Who: anyone whose environment decodes Brotli data from an untrusted source. A request with Content-Encoding: br and a br response fetched from an external server are both entry points
- What to do: identify the runtime and package versions you use and update. If you cannot, turn Brotli decoding off. Dependency scanners may not flag the PyPI Brotli package, so check manually
Affected and fixed versions
The table lists the affected and fixed versions confirmed by the sources. OS vendors sometimes backport the fix without changing the version number, so an old-looking number can already be patched. Conversely, do not call something safe on the version number alone; read your distribution's security advisory.
| Product | Affected | Fixed |
|---|---|---|
| Google Brotli (libbrotli) | 1.0.3 to 1.2.0 (all platforms) | 1.2.1 (1.0.10 / 1.1.1 on the older lines) |
PyPI Brotli | 1.2.0 and earlier | 1.2.1 |
PyPI brotlicffi | 1.2.0.x | 1.2.1.0 |
| Node.js | Unpatched 22, 24 and 26 releases (demonstrated on 24.22.0) | 22.23.4 / 24.22.1 / 26.12.1. No fix for Node.js 20 and earlier |
| Bun | Before 1.4.4 | 1.4.4 |
| Envoy | Unpatched releases | 1.40.0 / 1.39.3 / 1.38.6 / 1.37.8 (1.36.12 also has it, but 1.36 is out of support) |
| Istio | Unpatched releases | 1.30.6 / 1.31.2 (1.29.9 exists, but 1.29 is EOL) |
| curl / libcurl | Builds that depend on Brotli | Update the Brotli side (1.2.1, patched older lines, or your distribution's package) |
| Apache / Nginx | Not affected by default, since neither decodes Brotli by default | Apache's stock mod_brotli does not decode either |
Where the table says "before" or "unpatched", the sources do not give an exact lower bound, so confirm the precise range in each project's own advisory. The Python advisory is GHSA-9v8h-qqgm-4m35.
How the vulnerability works
Brotli is the compression behind Content-Encoding: br. It produces smaller output than gzip, so browsers, CDNs and API servers use it widely. The bug is on the decoding side. The Brotli decoder has a function, DecodeBlockTypeAndLength(), that returns a bool. A false return means both "the stream is invalid" and "more input is needed", so the caller cannot tell the two apart. On the fast path the return value was dropped altogether. In CWE terms this is CWE-252 (unchecked return value) leading to CWE-787 (out-of-bounds write).
An attacker builds a stream that forces an impossible block switch. The decoder does not notice the stream is invalid, keeps decoding with the stale block state, and writes past the end of the buffer. The result can be a crash (denial of service), memory disclosure, memory corruption and, under the right conditions, arbitrary code execution. How easy it is to exploit depends on memory layout, OS mitigations and the runtime's implementation, so the outcome is not the same everywhere.
The upstream fix is google/brotli commit 0ed4268. It adds the error code BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH (value -17) so that an invalid block switch is reported as an error. In other words, this is not a Node.js or Python bug; every product that ships the Brotli code had it. That is why the nickname moved from Node2Shell to HTTP2Shell.
Attack paths: both inbound and outbound
The sources describe the attack as bidirectional. It is not only your server being attacked; your own program connecting to a malicious server is just as exposed, and that case is easy to overlook.
- Inbound: apps or middleware that decode a request body sent with Content-Encoding: br. The sources use Express 5 on Node.js as an example. The attacker only needs to POST a crafted Brotli body
- Outbound: your program fetches and decodes a Brotli response from a malicious server. Webhook verification, URL previews (link thumbnails), crawlers, third-party API integrations and any fetch-by-URL feature fall here
- Indirect: the application may not care about Brotli, yet the HTTP client library finds a Brotli package and enables it automatically. In Python, urllib3 (including via requests), httpx (the brotli extra), aiohttp and Scrapy do this

In Python especially, merely having Brotli installed deep in the dependency tree makes the HTTP client send br in Accept-Encoding and decode the answer. The Brotli package sees about 82.8 million downloads a month, and it is often there as someone else's dependency rather than something you installed deliberately.
As of October 22, 2026, no exploitation in the wild had been reported. Researchers including those at Imperva, however, have demonstrated exploitation on an unmodified Node.js 24.22.0 as a research demo. With a public demo, assume working exploit code will spread quickly and move fast.
How to check whether you are exposed
Work through three questions: which runtime and version you run, whether a Brotli package is installed, and whether any path decodes untrusted Brotli data. Start with Python packages. For containers, inspect the image that actually runs.
# 1. Brotli packages and versions in the Python environment
pip show Brotli brotlicffi
# 2. Inspect a container image (replace the image name)
docker run --rm <image> pip show Brotli brotlicffi
# 3. What pulled Brotli in? (reverse dependency lookup)
pipdeptree -r -p Brotli
# 4. Is it in a lockfile or requirements file?
grep -i brotli poetry.lock uv.lock requirements*.txtFor Node.js, check the runtime version and the Brotli version it bundles. process.versions.brotli returns the bundled Brotli version. Treat the Node.js release number as the primary signal and the bundled Brotli number as a secondary hint.
# Node.js version (fixed: 22.23.4 / 24.22.1 / 26.12.1)
node -v
# Brotli version bundled with Node.js
node -p process.versions.brotliThen review your design for paths that decode untrusted Brotli data.
- Does any public server accept and decode requests with Content-Encoding: br (Express 5 body parsers, API gateways, Envoy or Istio filters)?
- Does anything fetch external URLs (webhook delivery, URL previews, image fetching, crawlers, third-party APIs)?
- Does that HTTP client send br in Accept-Encoding? Check the library's defaults
- Do several container images, serverless functions or CI runners each carry their own copy of the same Brotli library?
Fixes by language and platform
Node.js
Node.js fixed this in its October 2026 security release, which addressed 10 vulnerabilities, 4 of them rated High. The fixed versions are 22.23.4, 24.22.1 and 26.12.1. No fix is provided for Node.js 20 and earlier, so if you are on those lines your only real option is to move to a supported line (22 or later). If you cannot move immediately, use the mitigations below (reject br requests, disable outbound br) in the meantime.
Also check that your Docker base image (a tag such as node:22) has not gone stale. The tag name can stay the same while an already-built image keeps the old Node.js. The fix only lands once you rebuild the image and redeploy.
Python
On PyPI, Brotli 1.2.0 and earlier and brotlicffi 1.2.0.x are affected; the fixed versions are 1.2.1 and 1.2.1.0. If you pin them in requirements or a lockfile, raise the pin, regenerate the lock and rebuild the container image. urllib3, httpx, aiohttp and Scrapy use the Brotli package automatically when it is present, so updating the package is the fix; you do not need to change those libraries.
# Update to the fixed versions (use pip / uv / poetry as appropriate)
pip install -U "Brotli>=1.2.1" "brotlicffi>=1.2.1.0"
# Verify after updating
pip show Brotli brotlicffiNote that many Python dependency-analysis tools do not flag this issue (see below). Brotli is distributed as a wheel containing compiled C code, so it carries its own copy independent of the system libbrotli. Updating the OS package does not update the Brotli inside a Python virtual environment.
Bun
Bun fixed this in 1.4.4. Update with bun upgrade, and raise the Bun version pinned in your CI and container images as well.
Envoy and Istio
Envoy is fixed in 1.40.0, 1.39.3, 1.38.6 and 1.37.8. The fix is also in 1.36.12, but the 1.36 line is out of support. Istio's fixed versions are 1.30.6 and 1.31.2; 1.29.9 exists too, but 1.29 is end of life. In a service mesh or API gateway, the proxy is exposed when its Brotli decompressor filter is enabled. If your configuration does not use that filter, exposure is limited, but confirm it from the configuration before concluding that.
curl and OS packages
curl and libcurl use a Brotli library as an external dependency, so what needs updating is the linked Brotli, not curl itself. Move to libbrotli 1.2.1, the patched older lines (1.0.10, 1.1.1) or your distribution's fixed package. On Debian-family, RHEL-family and Alpine systems the fix may arrive without a version change, so check each distribution's security tracker for how it handles CVE-2026-111497. Statically linked binaries and apps that bundle Brotli are not fixed by an OS update and must be rebuilt.
Mitigations while you cannot patch
If a fixed version is not available (Node.js 20 or earlier, verification still pending, waiting on a vendor), stop using Brotli decoding to close the entry point. These are not root-cause fixes, and they do not help against decoders bundled by other runtimes. The lasting fix is updating.
Python mitigations
- Uninstall Brotli and brotlicffi. HTTP clients fall back to gzip or deflate, but that is not guaranteed for every library, so test it
- Remove extras such as httpx[brotli] from your dependencies and regenerate the lockfile
- Restart the environment (or redeploy the container) so already-loaded modules are replaced
- Decoders bundled by other runtimes, such as Node.js, remain, so do not stop at Python
Inbound mitigations
At the proxy, load balancer or application middleware, reject requests whose Content-Encoding contains br. Compare case-insensitively and also match when br appears inside a list such as gzip, br. A naive exact-match check on the header value lets BR or gzip, br slip through. Ordinary API clients rarely send request bodies in Brotli, so rejecting them usually has little side effect.
Outbound mitigations
Remove br from Accept-Encoding. That alone is not enough: a malicious server can ignore Accept-Encoding and still answer with Content-Encoding: br. You also need to disable decoding of br responses in the client, or reject them. Start with features where you do not choose the other side, such as webhooks, URL previews and crawlers.
Scanners that do not flag this
As of October 23, 2026, pip-audit, Dependabot and Safety had not mapped this CVE to the PyPI Brotli and brotlicffi packages, so these tools raise no alert. The release notes of the fixed versions do not mention the CVE either. A green scanner therefore does not mean you are safe. Check versions directly with the commands above, and build manual verification into your routine until the vulnerability databases catch up.
This is not the first time such a gap has mattered. In the LiteLLM 1.107.0 tampering incident, people had to check their dependencies proactively. In the urgent PHP vulnerabilities CVE-2026-109618/109619, vendor information and scanner coverage also diverged for a while. There is a delay between a vulnerability being published and tools detecting it, and during that window you have to check yourself.
Timeline
| Date | Event |
|---|---|
| February 2026 | OpenAI discovers the issue and reports it as unauthenticated remote code execution. The source is fixed, but it is not recognized as a security issue and the release comes later |
| October 21, 2026 | Node.js discloses the CVE (a release fixing 10 vulnerabilities, 4 of them High) |
| October 22 | The Python-side fix lands. No exploitation in the wild reported at this point |
| October 23 | Scope widens to other languages and HTTP applications. Patches ship for libbrotli, Python, C++, Node.js, Bun and Envoy |
| As of October 23 | pip-audit, Dependabot and Safety do not map the CVE to the PyPI Brotli packages and do not detect it |
| October 21 to 24 | Discussed on Hacker News (319 points). Researchers demonstrate exploitation on an unmodified Node.js 24.22.0 (research demo) |
OpenAI's disclosure is published at patchtheplanet.org/brotli. For the detailed technical history and the latest exploitation status, check the official announcements and each vendor's advisory. The status in this article reflects what could be confirmed up to October 24, 2026.
Checklist for today
- List the versions of Node.js, Bun, Envoy or Istio, and the Python Brotli packages you use, and compare them with the table above
- Inspect the contents of container images (the image that actually runs, not the source)
- Find every path that decodes untrusted Brotli data (Content-Encoding: br requests, webhooks, URL previews, crawlers)
- Update to the fixed versions, rebuild images, redeploy and regenerate lockfiles
- For anything you cannot update, add rejection of br requests and disable outbound br
- Do not trust scanner results alone; keep the output of the check commands in your ticket or records
Frequently asked questions
What causes CVE-2026-111497?
In Google Brotli's decoder (1.0.3 to 1.2.0), DecodeBlockTypeAndLength() cannot tell an invalid stream from insufficient input through its return value, and the fast path discarded the return value. A crafted stream forces an impossible block switch, decoding continues with stale block state, and an out-of-bounds write results.
Are Node2Shell and HTTP2Shell different vulnerabilities?
No, they are nicknames for the same CVE-2026-111497. It was called Node2Shell in the Node.js disclosure, then HTTP2Shell once it became clear that HTTP libraries and applications in general were affected.
Am I affected if I run Nginx or Apache?
Apache and Nginx do not decode Brotli by default, and Apache's stock mod_brotli does not decode either, so they are normally out of scope. But a Node.js or Python application running on the same server that decodes Brotli is affected.
If pip-audit or Dependabot report nothing, am I safe?
Not necessarily. As of October 23, 2026, pip-audit, Dependabot and Safety do not map this CVE to the PyPI Brotli or brotlicffi packages, so they do not detect it. Check the version directly with pip show.
I am on Node.js 20. What should I do?
No fix is provided for Node.js 20 and earlier. Moving to a supported line, 22 or later, is the lasting answer. Until you can, close the entry points by rejecting requests whose Content-Encoding contains br and by disabling outbound br.
Is removing br from Accept-Encoding enough?
No. A malicious server can ignore Accept-Encoding and answer with br anyway, so you also need to disable decoding of br responses in the client or reject them.
Has this been exploited yet?
As of October 22, 2026, no exploitation in the wild had been reported. Researchers including those at Imperva have shown it working on an unmodified Node.js 24.22.0 as a research demo. Check the official announcements for the latest status.
Related free tools (no sign-up, instant results)
Feel free to contact us
Contact Us