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 Brotli or brotlicffi
  • httpx, if installed with its brotli extra
  • 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

SoftwareAction
Node.js 26.xUpgrade to 26.12.1 or later
Node.js 24.xUpgrade to 24.22.1 or later
Node.js 22.xUpgrade to 22.23.4 or later
Node.js 25.x, 23.x, 20.x and olderEnd-of-life, migrate to a supported release
Bun before 1.4.4Upgrade to 1.4.4 or later
Python Brotli 1.2.0 and earlierUpgrade to 1.2.1 or later
Python brotlicffi 1.2.0.2 and earlierUpgrade 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 Brotli and brotlicffi in every environment. If you pin dependencies, set the pins to at least Brotli 1.2.1 and brotlicffi 1.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