SecurityNode.jsPythonBrotliDevOps

HTTP2Shell (CVE-2026-111497): Brotli Patch Guide for Node, Python, Bun

person
LaunchBoosts Research Desk·AI-assisted research
8 min read

Researched and drafted with AI assistance from the 6 public sources listed at the end of this article, then published after automated editorial checks. Spotted an error? Tell us at support@launchboosts.com.

HTTP2Shell (CVE-2026-111497): Brotli Patch Guide for Node, Python, Bun — LaunchBoosts

HTTP2Shell (CVE-2026-111497) is a memory-safety bug in Google's Brotli decoder. An attacker can send compressed data, either as a request body your server accepts or as a response your server fetches, to crash the process, leak memory or, in some cases, run code. The fix is an upgrade: Node.js 22.23.4 / 24.22.1 / 26.12.1, Bun 1.4.4, Brotli 1.2.1 (or 1.1.1 / 1.0.10), and the Python packages Brotli 1.2.1 and brotlicffi 1.2.1.0. Everything that bundles the library also needs to be rebuilt or updated. Below: what's affected, how to find it in your stack, and what to do if you can't patch today.

What happened, and why the name changed

Node.js published security releases on October 21, 2026, fixing ten vulnerabilities. The official Node.js advisory describes CVE-2026-111497 this way: malformed compressed input can "write past the end of an eight-byte internal buffer." An invalid block switch was reported as a temporary need for more input rather than a format error, so the streaming decoder kept appending data. Node.js rates it High and credits OpenAI Codex Security (Khai Tran and Sylvie Mayer) with the report.

The bug isn't specific to Node. It lives in the upstream Brotli decoder, in DecodeBlockTypeAndLength(). That function returns a plain boolean, so "malformed stream" and "need more input" look the same, and on the fast path the return value is ignored. Aikido's analysis has the details. Google, the CNA for the CVE, scores it 9.2 Critical under CVSS 4.0, according to Cycode. So you'll see "High" from Node.js and "Critical" from Google for the same bug.

Once Python, Bun, Envoy, Istio and curl were shown to carry the same decoder, the nickname changed from "Node2Shell" to "HTTP2Shell." Two details make this worse than a typical library CVE:

  • It's old. Miggo traced the bug to a Brotli change on February 26, 2018, which shipped in Brotli 1.0.3. Node.js has carried it since it added Brotli support in January 2019.
  • The fix sat unreleased for eight months. The fix was committed to google/brotli on February 27, 2026, but wasn't treated as a security issue. Patched releases only shipped on October 21, 2026.

It also works in both directions. A malicious client can attack an unpatched server, and a malicious server can attack an unpatched client that accepts compressed responses.

Timeline

Date (2026) Event
Feb 27 Fix committed to google/brotli, with no release or advisory
Oct 21 Node.js 22.23.4, 24.22.1, 26.12.1 released; Brotli 1.0.10, 1.1.1, 1.2.1 released
Oct 22 CVE published; Bun 1.4.4 released; Python Brotli/brotlicffi updates; Imperva publishes a code-execution write-up
Oct 23 Python, Envoy, Istio and curl confirmed affected; no in-the-wild exploitation reported; not in CISA KEV

Sources disagree slightly on whether Node's disclosure was October 21 or 22. Aikido notes the discrepancy. The Node.js releases themselves are dated October 21.

How exploitable is it?

Imperva's Red Team got code execution on the official Node.js 24.22.0 Linux arm64 image. They used two paths: Brotli request bodies parsed by Express 5 / body-parser 2 (json() or raw()), and Brotli responses read by the built-in fetch(). The exploit didn't work every time; it took several attempts in their setup. The same inputs were rejected by 24.22.1. Miggo notes that other public proofs of concept reach code execution only in deliberately weakened lab setups.

For Python, Cycode says code execution has not been shown, but memory corruption in a long-running worker is still serious. Aikido's advice: "Treat it as urgent anyway."

No login is needed. The attacker only needs a way to get Brotli bytes into your decoder.

What's affected and the fixed versions

This table combines the Node.js advisory with fixed-version lists from Aikido and Cycode.

Component Vulnerable Fixed in
Node.js 26.x / 24.x / 22.x Below the fixed release 26.12.1 / 24.22.1 / 22.23.4
Node.js 20 and other EOL lines (21, 23, 25) All No fix. Move to a supported line
Bun Below 1.4.4 1.4.4 (rebuild bun build --compile binaries)
Google Brotli (libbrotli) 1.0.3–1.0.9, 1.1.0, 1.2.0 1.0.10, 1.1.1, 1.2.1
PyPI Brotli 1.2.0 and earlier 1.2.1
PyPI brotlicffi Before 1.2.1.0 1.2.1.0
Java brotli4j Earlier releases 1.24.0
Ruby brotli gem Earlier releases 0.9.1
Envoy (only if Brotli decompressor enabled) Earlier releases 1.40.0, 1.39.3, 1.38.6, 1.37.8
Istio Earlier releases 1.31.2, 1.30.6, 1.29.9 (1.29 is EOL)
curl/libcurl Builds linked to vulnerable Brotli Patched libbrotli or vendor package
curl_cffi Bundles Brotli 1.2.0 No fixed release as of Cycode's writeup
Go cbrotli Links system library Patch system libbrotli

What isn't affected by default: Apache's standard mod_brotli and Nginx don't decode Brotli request bodies by default, per Aikido. A bare Node.js http server doesn't decode incoming Brotli just by receiving it. The npm package called brotli is unrelated to the runtime's bundled copy. pip itself is not affected.

The hidden dependency problem

Many affected apps never call Brotli directly:

  • Node.js: Express 5, body-parser 2.x, the Koa body parsers (koa-bodyparser, @koa/bodyparser, koa-body, co-body) and @fastify/compress (with request decompression on) decode Brotli request bodies. On the outbound side, fetch() decodes Brotli responses. Miggo adds that axios, SuperAgent, got and Next.js server-side fetches decompress responses automatically. Express 4 / body-parser 1.x don't decode Brotli bodies.
  • Python: urllib3 (and therefore requests), httpx with the brotli extra, and aiohttp decode Brotli responses whenever brotli or brotlicffi is installed. The aiohttp server also decompresses Brotli request bodies by default when the package is present. Scrapy depends on brotli.
  • Desktop apps: Miggo reports that Electron v45.0.0, the latest release when they wrote it up, bundles the vulnerable Node.js 24.22.0. If you ship an Electron app that fetches remote content, watch for an Electron update.

One more trap, from Aikido: as of October 23, pip-audit, Dependabot and Safety were not flagging the vulnerable PyPI versions, because the advisory databases hadn't mapped the CVE to those packages yet. A clean scanner run doesn't mean you're safe this week.

How to find exposure in your stack

Work through these in order. The first three take minutes.

  1. Check every Node and Bun runtime, including the ones inside images. Run node -v and bun --version on hosts, and docker run --rm IMAGE_NAME node -v against each built image (replace IMAGE_NAME with the image tag). Include CI runners, build hosts, and anything installed via NodeSource or nvm. Miggo recommends rebuilding any image based on node tags built before October 22, 2026.
  2. Check every Python environment. Run pip show Brotli brotlicffi in each virtualenv and container. Then run pipdeptree -r -p Brotli to see what pulled it in. Search lockfiles too: grep -i brotli poetry.lock uv.lock requirements*.txt.
  3. Check OS packages. Look up your distribution's Brotli package (for example with dpkg -l | grep brotli or rpm -q brotli) and compare it against the distro's security advisory. Vendors often backport fixes without changing the upstream version number, so the version string alone can mislead. Miggo reported that Debian and Ubuntu hadn't shipped Node.js fixes as of October 23. Debian's Node.js links the system Brotli, so it stays exposed until that package is updated. Cycode notes Debian and Red Hat had shipped fixed packages for curl.
  4. Map the inbound path. List services that decompress request bodies: Express 5, body-parser 2, Koa parsers, @fastify/compress, the aiohttp server, and Envoy/Istio with the Brotli decompressor enabled.
  5. Map the outbound path. This is the one people miss. List every place your server fetches a URL that an attacker can influence: webhooks, link unfurling and previews, crawlers, scrapers, RSS/feed readers, image proxies, SSR data fetching, and AI agents that browse. Miggo points out that a WAF at the front door never sees these responses.
  6. Verify after deploying. Confirm the running workloads report the patched versions, not just the lockfile or the Dockerfile.

Fix in this order: internet-facing services that fetch attacker-influenced URLs, then public endpoints that decode compressed bodies, then everything else.

If you can't patch today

These measures reduce risk but don't fix the bug.

  • Inbound: reject requests whose Content-Encoding contains br at the proxy, load balancer or middleware, before the body is decoded. Cycode stresses matching case-insensitively and checking inside comma-separated lists (e.g. gzip, br). Turning off body inflation in your parser also works, but it rejects gzip bodies too.
  • Outbound (Python): uninstall Brotli and brotlicffi, drop extras like httpx[brotli], regenerate locks and restart. Clients fall back to gzip/deflate. Aikido warns that a server that sends Brotli anyway may then cause errors, and that this doesn't touch Brotli copies bundled into other runtimes.
  • Outbound (general): removing br from Accept-Encoding isn't enough on its own, because a malicious server can send Brotli regardless. You also need to reject responses with Content-Encoding: br before decoding. Axios lets you turn off automatic decompression. Node's fetch() doesn't, so for code that calls fetch() on untrusted URLs, upgrading Node is the only real fix.
  • WAF rules: Imperva, Vercel and Miggo have shipped rules for known payloads. All three say the runtime update is still required.
  • Monitoring: Imperva suggests watching for unexpected process exits and decoder errors during decompression. Neither is reliable proof of an attack on its own. Correlate them with the runtime version and the source of the compressed data.

If you run Dynatrace, the vendor has published its own notice stating which of its components are and aren't affected. Check your other vendors for similar notices. Anything that ships an embedded Node.js or libbrotli, such as CLIs, agents, desktop apps and sidecars, is in scope.

What it means for small teams and AI builders

Three things stand out for founders and small engineering teams.

Your outbound fetches are attack surface. AI products fetch a lot of URLs they don't control: agents browsing the web, RAG crawlers, link-preview features, webhook relays. Under this bug, each of those fetches is an attack path. If you build agentic features, keep a list of every component that makes outbound requests on a user's behalf, and the runtime it runs on.

End-of-life runtimes are now a concrete risk. Node.js 20 reached end of life on April 30, 2026, and it will not be patched for this. If a side project or internal tool still runs on 20, this CVE is a good reason to upgrade it.

Don't rely only on scanners. The PyPI advisory gap shows that dependency scanners lag. A short manual check (node -v, pip show, a lockfile grep) catches what the databases haven't mapped yet.

What to do now and what to watch

Today: upgrade Node.js, Bun and Python Brotli/brotlicffi, rebuild and redeploy container images, then confirm the running versions. Block br request bodies at the edge for anything you can't patch immediately.

This week, watch for:

  • Distro packages: Debian, Ubuntu and other vendors shipping fixed Brotli and Node.js packages.
  • Electron: a release that bundles a fixed Node.js.
  • curl_cffi: a release with patched Brotli.
  • Scanners: pip-audit, Dependabot and Safety mapping the CVE to the PyPI packages.
  • CISA KEV: whether the CVE is added, which would indicate confirmed exploitation in the wild.

Older posts on the LaunchBoosts blog cover other recent patch cycles, including the PHP2Shell and NGINX advisories. Checking your dependencies against both is worthwhile if you run mixed stacks.

Frequently asked questions

What is HTTP2Shell?

HTTP2Shell is the nickname for CVE-2026-111497, an out-of-bounds write in Google's Brotli decompression library. It was first called Node2Shell when Node.js disclosed it on October 21, 2026. The name changed once researchers showed that Python HTTP clients, Bun, Envoy, Istio, curl and other software using the same decoder are affected too.

Which Node.js versions fix CVE-2026-111497?

Node.js 22.23.4, 24.22.1 and 26.12.1 fix it, as do later releases in those lines. Node.js 20 and other end-of-life lines will not get a fix. Node.js bundles its own copy of Brotli, so updating the operating system's Brotli package does not protect your Node process. Upgrading the runtime is the fix.

Is my Python app affected if I never import brotli?

Possibly. urllib3 (and therefore requests), httpx with the brotli extra, and aiohttp all decode Brotli automatically whenever the brotli or brotlicffi package is installed. Scrapy pulls brotli in as a dependency. Run pip show Brotli brotlicffi in each environment and upgrade to Brotli 1.2.1 or brotlicffi 1.2.1.0 or later.

Is CVE-2026-111497 being exploited in the wild?

As of October 23, 2026, no in-the-wild exploitation had been reported, and the CVE was not in CISA's Known Exploited Vulnerabilities catalog. Imperva did show code execution against an unmodified Node.js 24.22.0 arm64 image, though it took several attempts, and public proofs of concept exist. Patch it as urgent.

Does blocking Content-Encoding: br at my load balancer protect me?

It only covers inbound request bodies. It does nothing for responses your server fetches from outside, such as webhooks, link previews or crawlers. A malicious server can send Brotli even if you didn't ask for it, and Node's built-in fetch() has no switch to turn decompression off. Upgrading the runtime or library is the only full fix.

Sources

  1. Node.js — October 2026 Security Releases— nodejs.org
  2. Aikido — Node2Shell Brotli vuln (CVE-2026-111497) evolves to HTTP2Shell— aikido.dev
  3. Cycode — node2shell (CVE-2026-111497): What to Patch and How to Find Exposed Services— cycode.com
  4. Imperva — Node2Shell: From Brotli Data to Remote Code Execution— imperva.com
  5. Miggo — Inside Node2Shell, the Eight-Year-Old Bug in Node.js's Brotli Decoder— miggo.io
  6. Dynatrace — Http2Shell: Node.js Brotli vulnerability (CVE-2026-111497)— dynatrace.com
person

LaunchBoosts Research Desk

AI-assisted research

Explainers on software and AI industry trends, drafted with AI assistance from the public sources cited in each article and published after automated editorial checks for length, independent sourcing and originality.