- Severity
- Critical
- CVSS
- 9.8 (CVSS v3.1), 9.2 (CVSS v4.0)
- Status
- Exploited in the wild
- Fix
- Patch available
- Affected
- Node.js before 26.12.1, 24.22.1 and 22.23.4, end-of-life branches, Bun before 1.4.4, and Python Brotli before 1.2.1 and brotlicffi before 1.2.1.0
CVE-2026-111497, known as Node2Shell and more recently HTTP2Shell, is an out-of-bounds write in Google's Brotli C decoder that may allow remote code execution (RCE). Node.js and Bun bundle the decoder and have released fixes, and the same code is compiled into the Python Brotli and brotlicffi packages.
The CVE record rates it critical (CVSS 3.1: 9.8, CVSS 4.0: 9.2), although the Node.js advisory classifies it as High. CISA added it to its Known Exploited Vulnerabilities Catalog on 27 October 2026, confirming exploitation in the wild.
Update to Node.js 26.12.1, 24.22.1 or 22.23.4, or a newer patched release in the same branch. Applications using Express 5, body-parser 2.x, fetch() or the node:zlib Brotli APIs should review their exposure now.
For Python, upgrade to Brotli 1.2.1 and brotlicffi 1.2.1.0 or later. Google's 1.2.1 release notes on GitHub name the CVE, and the GitHub advisory lists both versions as the fixes. Check your installed versions directly, as a package manager may resolve to an older release than you expect. Run the command for each package you have installed:
pip install -U "Brotli>=1.2.1"
pip install -U "brotlicffi>=1.2.1.0"
Updated 28 October 2026: CISA has added CVE-2026-111497 to its Known Exploited Vulnerabilities Catalog, confirming that it is being exploited in the wild. Earlier updates are listed in the update log at the end.
Exploitation status
On 27 October 2026, CISA added CVE-2026-111497 to its Known Exploited Vulnerabilities Catalog, which means it has evidence of exploitation in the wild. CISA has not published details of the attacks.
The GitHub advisory states that a crafted Brotli stream can corrupt adjacent decoder state memory, disclose memory contents, cause a denial of service or potentially allow arbitrary code execution. Which of these applies depends on the input and the execution path.
Public GitHub repositories now claim to demonstrate both denial of service and remote code execution. We have not verified that any of them achieve code execution, and we are not linking to them. Treat patching as urgent, starting with internet-facing services and anything that fetches data from external URLs.
Root cause
The flaw is in the Brotli decoder (c/dec/decode.c). The upstream fix is in a commit (0ed4268) released in Brotli 1.2.1 on 21 October 2026. Every project that bundles its own copy of the decoder has had to pick up that fix separately, which is why Node.js, Bun and the Python packages each have their own patched release.
A Brotli stream is divided into blocks, and the decoder reads a "block switch" each time it moves to a new block of literals, commands or distances. When a stream declares only one block type for a category, a block switch should not occur, and before the fix DecodeBlockTypeAndLength() handled that case by returning false. That was the same value it used to signal that it needed more input.
The decoder's fast path ignored that return value and carried on as if the switch had succeeded. The GitHub advisory describes the result as corrupting adjacent decoder state memory. The streaming path treated the same value as a request for more input, so a malformed stream was never rejected.
The fix gives the invalid case its own error code, BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH, and checks for it on both paths so decoding stops as soon as it is reported.
Node.js installed through an operating system package manager is sometimes built against the OS-provided Brotli instead of its own copy. In that case, node --version may not tell you whether you are protected. Update the operating system's Brotli package and follow your distribution's security notices, as distributions may backport the fix without changing the version number.
Other software that bundles or links against Brotli may be affected too, so check vendor advisories for anything in your stack that decompresses Brotli data.
Who is affected
You are affected if you run an affected version of Node.js, Bun, or the Python Brotli or brotlicffi packages, and your application decompresses Brotli data that an attacker can control.
Node.js and Bun
Common attack paths include:
- Express 5 and body-parser 2.x: applications using body parsers that accept Brotli-compressed request bodies automatically decompress requests marked
Content-Encoding: br. - Outbound requests: Node.js's built-in
fetch()automatically decompresses supported compressed HTTP responses. A hostile or compromised upstream server could therefore supply attacker-controlled Brotli data. Pay particular attention to requests involving untrusted hosts or URLs supplied by users. - Direct use of
node:zlib: any code or dependency passing untrusted input to the Brotli decompression functions.
Python
Brotli is Google's Python binding, and its compiled extension includes the C decoder. brotlicffi, mainly used on PyPy, ships its own copy of the same C code.
According to OpenSourceMalware, these clients request Brotli (Accept-Encoding: br) and decompress Brotli responses for you when a supported package is installed:
- urllib3, which also covers requests, with
Brotliorbrotlicffi - httpx, if installed with its
brotliextra - aiohttp, with
Brotli - Scrapy, plus any tool built on one of these clients
Either package is often pulled in as a transitive dependency, for example through urllib3[brotli] or httpx[brotli], so it may be present without anyone having added it directly.
The risky code paths are the same as on Node.js. Outbound, the risk is anything that fetches from servers you don't control, such as webhook senders, link previews, crawlers and features that fetch a user-supplied URL. Inbound, it's any framework or middleware that decompresses br request bodies before your code sees them, which is the Python counterpart to the Express 5 case.
Affected and fixed versions
| Software | Action |
|---|---|
| Node.js 26.x | Upgrade to 26.12.1 or later |
| Node.js 24.x | Upgrade to 24.22.1 or later |
| Node.js 22.x | Upgrade to 22.23.4 or later |
| Node.js 25.x, 23.x, 20.x and older | End-of-life, migrate to a supported release |
| Bun before 1.4.4 | Upgrade to 1.4.4 or later |
Python Brotli 1.2.0 and earlier | Upgrade to 1.2.1 or later |
Python brotlicffi 1.2.0.2 and earlier | Upgrade to 1.2.1.0 or later |
Upstream Brotli 1.0.3 to 1.2.0 is listed as affected, with the fix in 1.0.10, 1.1.1 and 1.2.1. OpenSourceMalware has since reported the same unchecked code pattern in every PyPI release of Brotli it examined, back to 0.5.2, so versions older than 1.0.3 should not be treated as safe.
On PyPI, Brotli 1.2.1 is the only fixed release. There is no patched 1.0.x or 1.1.x release on PyPI, so pinning to an older version is not an option. OpenSourceMalware compared the 1.2.0 and 1.2.1 source distributions and found that the only changes are the upstream fix and the version bump.
How to check whether you are affected
Start by checking the Node.js version on your hosts, CI runners and deployed containers:
node --version
For a built image, check the runtime inside the image rather than relying solely on your package inventory:
docker run --rm --entrypoint node your-image:tag --version
Or on a container directly:
docker exec my-container node --version
Identify applications that decompress untrusted Brotli data. Review Express and body-parser configurations, outbound fetch() calls to untrusted or user-supplied URLs, and direct calls to Brotli decompression functions in node:zlib.
For Python, check each environment and virtualenv. Any package that is not installed is reported as not found, and the Required-by line shows which dependency pulled in an installed package:
python -m pip show Brotli brotlicffi
For a built image:
docker run --rm --entrypoint python your-image:tag -m pip show Brotli brotlicffi
The PyPI packages were initially missing from advisory databases. As of 24 October 2026, PyPI lists advisories against the affected versions of both packages (including PYSEC-2026-4322 and GHSA-9v8h-qqgm-4m35), so tools such as pip-audit should now flag them. Other scanners may lag behind, so confirm the installed version directly if a scan comes back clean.
Repeat these checks across production services, scheduled jobs, serverless functions, and build environments. After patching, verify the version in the deployed workload and not just in the source repository, Dockerfile or lock file.
Mitigation
Updating is the only complete fix. For Bun, that means upgrading to 1.4.4 or later. For distribution-built Node.js, it means updating the system Brotli package.
- Apply the update: upgrade to a fixed release in your branch, prioritising internet-facing services and anything that fetches data from external URLs.
- Update Python packages: upgrade
Brotliandbrotlicffiin every environment. If you pin dependencies, set the pins to at leastBrotli1.2.1 andbrotlicffi1.2.1.0 in your requirements or lock files, otherwise the old version will return on the next build. - Rebuild containers: rebuilding alone is not enough if the base image is fixed to an old version such as
node:24.22.0. Change the tag to a patched release, then rebuild and redeploy. - Check managed platforms: if a hosting provider or serverless platform supplies Node.js for you, confirm which version it is running, as providers do not always update immediately.
- Plan to migrate end-of-life versions: Node.js 25.x, 23.x, 20.x and older are out of support and no patch has been released for them.
Stop-gap mitigations
At the time of writing, Node.js has not published an official workaround. Restricting Brotli-compressed request bodies before they reach Node.js narrows the inbound attack surface. It does not protect data your application fetches itself, such as fetch() responses, and is not a substitute for patching. Ensure you test these changes before deploying to production.
Express
With Express, you can reject Brotli-encoded request bodies before they reach the body parser. Register this middleware before any body parsers:
app.use((req, res, next) => {
if (/\bbr\b/i.test(req.headers['content-encoding'] || '')) {
return res.status(415).send('Unsupported Content-Encoding');
}
next();
});
Python
If you can't upgrade straight away, uninstalling Brotli and brotlicffi removes the vulnerable decoder. Without either package, the clients above stop requesting Brotli and use gzip or deflate instead, although any code that imports either package directly will break.
You can also reduce exposure by sending your own Accept-Encoding header without br and refusing inbound requests that arrive Brotli-encoded. This only helps with well-behaved servers on the outbound side. A hostile server can send a Brotli response regardless of what you asked for, and the clients will still decode it while either package is installed, so uninstalling is the stronger stop-gap.
Update log
28 October 2026
CISA added CVE-2026-111497 to its Known Exploited Vulnerabilities Catalog on 27 October 2026. Updated the exploitation status, which previously said we were not aware of confirmed exploitation in the wild.
24 October 2026
Added the Python Brotli and brotlicffi packages, which bundle the same vulnerable decoder and were fixed in 1.2.1 and 1.2.1.0. PyPI now lists advisories against the affected versions. Added the HTTP2Shell name used by Aikido, and a section explaining where the vulnerability sits, as it applies to every affected project.
23 October 2026
Initial publication covering Node.js and Bun.
References
- Node.js: October 2026 Security Releases
- Tenable: CVE-2026-111497
- Node.js v22.23.4 release notes
- Imperva: Node2Shell, From Brotli Data to Remote Code Execution
- Aikido: Node2Shell
- Aikido: Node2Shell evolves to HTTP2Shell
- OpenSourceMalware: Python Packages Vulnerable to Node2Shell
- Bun v1.4.4 release notes
- GitHub Advisory Database: GHSA-9v8h-qqgm-4m35
- CISA: Known Exploited Vulnerabilities Catalog
- PyPI: Brotli
- PyPI: brotlicffi

