Guide

Node2Shell beyond Node.js: Brotli CVE-2026-111497 in Go, Java, .NET, PHP, Ruby, Linux and proxies

By Aman Singh · Published · 12 min read

CVE-2026-111497, better known as Node2Shell or HTTP2Shell and scored 9.2 out of 10 (Critical, CVSS 4.0), is usually described as a Node.js bug. But the code that is broken is Google's Brotli C decoder, versions 1.0.3 to 1.2.0. That decoder is copied into language runtimes, packages, proxies and every major Linux distribution. Each copy needs its own update, and as of 24 October 2026 several popular ones still had none.

The attack works in both directions: a malicious client can take over an unpatched server by sending it a Brotli-compressed request, and a malicious server can take over an unpatched client by sending it a Brotli-compressed response.

This guide lists every component I could confirm from its own repository, advisory or binary: what is affected, what is fixed, how to check, and what to do where there is no fix yet. Where I could, I tested the binaries themselves. The Node.js and Python details have their own guides: Node.js and Python.

On Node.js? Check and patch Node.js (Node2Shell) →

Each copy needs its own update. Fixing the operating system does not fix a copy bundled inside a runtime or a package, and the other way round.

Why one bug reaches so many languages

Brotli is the br compression used across the web. Most languages do not reimplement it; they wrap Google's C code, either by bundling a copy inside their own binary or by loading the system's libbrotlidec. The bug is a missing check: when a stream asks for a "block switch" it is not allowed to make, the old decoder treated it as "need more input", kept going, and could write past an internal buffer. The CVE record lists memory corruption, data disclosure, crashes and possible code execution. Google released 1.2.1, 1.1.1 and 1.0.10 on 21 October 2026; the fix itself had been in the source tree since February without being treated as a security issue.

Separate reimplementations are a different case. The Go port had the same logic error but, being memory-safe Go, it can only crash; the Rust port and Google's own Java, JavaScript and C# ports are separate code and are not reported as vulnerable to the code-execution bug.

Every affected component, in one table

ComponentBrotli sourceStatus, 24 October 2026Do this
Google Brotli (C)ItselfFixed: 1.2.1, 1.1.1, 1.0.10Update, or apply the patch to vendored copies
Node.jsBundledFixed: 26.12.1, 24.22.1, 22.23.4Update; 20.x and older get no fix
BunBundledFixed: 1.4.4Update; rebuild compiled executables
DenoRust portNot the C decoderNothing for this CVE
ElectronBundled Node.jsNot fixed: 45.0.0, 44.9.3, 43.8.3 ship Node.js 24.22.0Watch for a release with Node.js 24.22.1
Python brotli, brotlicffiBundledFixed: 1.2.1, 1.2.1.0Update and pin
pyarrow, Pillow (wheels)BundledNot fixedAvoid untrusted Brotli Parquet and WOFF2 fonts
Go (andybalholm/brotli)Go portCrash only; fixed in v1.2.7go get github.com/andybalholm/brotli@v1.2.7
Rust (brotli-decompressor)Rust portNot the C decoderNothing for this CVE
Java: Brotli4jBundled (JNI)Not released: fixed in source on 23 OctWatch for a release after 1.23.0
Java: org.brotli:decJava portNot the C decoderNothing for this CVE
.NETBundled 1.1.0Not fixedAvoid decoding untrusted Brotli; watch .NET updates
PHP ext-brotliBundled 1.2.0 or systemNot fixed (PR open)Build against a fixed system library
Ruby brotli gemBundled 1.2.0Not fixed (issue open)Avoid decoding untrusted Brotli
EnvoyBundledFixed: 1.40.0, 1.39.3, 1.38.6, 1.37.8, 1.36.12Update if the Brotli decompressor is configured
IstioEnvoyFixed: 1.31.2, 1.30.6, 1.29.9Update the control plane and proxies
curl / libcurlSystem or bundledFollows the library it usesUpdate the OS package or the curl build
Git for WindowsBundledNot fixed in 2.56.0.windows.3Watch for a newer release
DebianSystemFixed: DSA-6582-1, DLA-4855-1apt upgrade, restart services
AlpineSystemFixed in 3.21 to 3.24apk upgrade brotli-libs
UbuntuSystemNeeds triage on every releaseWatch for a USN
RHEL 8, 9, 10SystemAffected, no fix yet (Important)Watch for an RHSA
Amazon Linux 2023SystemPending fixWatch ALAS

Runtimes: Node.js, Bun, Deno, Electron

Node.js bundles Brotli and decodes it in more places than most people expect: Express 5 request bodies, fetch() and axios responses. The Node.js guide has a checker that detects the fix in the binary, plus stop-gaps. Distribution builds of Node.js (Debian's, for example) load the system library instead, so the OS package is what fixes them.

Bun 1.4.4, released 22 October, updates Brotli. Apps built with bun build --compile carry the runtime inside the executable, so rebuild them. Deno uses the Rust Brotli crate for its Node.js compatibility layer, not the C library.

Electron is the gap. Its three stable releases from 21 October, 45.0.0, 44.9.3 and 43.8.3, all bundle Node.js 24.22.0, the last unpatched build. Until a release with Node.js 24.22.1 or later is out, keep untrusted Brotli data away from the main process: do not decode user-supplied br files with zlib, and be careful with fetch() to servers you do not control.

Python, Go, Rust, Java, .NET, PHP, Ruby

Python

Update brotli to 1.2.1 and brotlicffi to 1.2.1.0. The harder part is the bundled copies: in tests, pyarrow 26.0.0 and Pillow 13.0.0 (Linux and macOS wheels) carried unpatched decoders that pip-audit did not flag, and the aiohttp web server decoded Brotli request bodies before middleware ran. The Python guide covers all of it, with a checker.

Go

The widely used github.com/andybalholm/brotli is a pure-Go translation of the C code. It had the same logic error, but Go's bounds checks turn it into a panic rather than memory corruption. It was fixed on 23 October in v1.2.7. A panic in a request handler can still take down a server that does not recover from it, so update anyway. Programs that use cgo bindings to the C library follow the system library instead.

Rust

brotli-decompressor (used by the brotli crate, reqwest, Deno and others) is a separate Rust implementation and is not the code this CVE is about. A Rust crate that links the C library through FFI is a different matter: check what it links.

Java

Brotli4j bundles the C library as a native JNI library. Its current release, 1.23.0, contains the unpatched decoder (the checker flagged its Linux native library); the project moved to Brotli 1.2.1 on 23 October, but no new release was on Maven Central as of 24 October. Netty uses Brotli4j to decode br when it is on the classpath. Google's pure-Java decoder, org.brotli:dec (used by OkHttp's Brotli support), is a separate port.

.NET

.NET bundles its own Brotli in System.IO.Compression, and the runtime repository still pins Brotli 1.1.0. No .NET update had addressed this CVE as of 24 October. I tested where it is reachable:

HttpClient against a server that always answers with Brotli
.NET 9.0.1
no              default HttpClientHandler      sent Accept-Encoding: (none)
DECODES BROTLI  AutomaticDecompression = All   sent Accept-Encoding: gzip, deflate, br
  • HttpClient does not decode Brotli by default. Code that sets AutomaticDecompression = DecompressionMethods.All or .Brotli does, so look for it in your HttpClient setup.
  • ASP.NET Core only decodes Brotli request bodies if you add the request decompression middleware (UseRequestDecompression). If you do not need compressed request bodies, remove it until .NET is patched.
  • BrotliStream and BrotliDecoder used directly on uploaded or downloaded data are the remaining path.

PHP

The brotli PHP extension (kjdev/php-ext-brotli) bundles Brotli 1.2.0 by default, and its update to 1.2.1 was still an open pull request on 24 October. It can also be built against the system library, which is the way to get a fix today on Debian or Alpine. More PHP apps meet Brotli through libcurl: Guzzle and Symfony HttpClient use curl, which decodes br when libcurl was built with Brotli. Check with curl_version(): on the XAMPP PHP 8.0 build I tested, brotli_version was empty, so it cannot decode Brotli at all. For this month's PHP core fixes, see the PHP2Shell guide.

Ruby

The brotli gem vendors Brotli 1.2.0, and the issue tracking the update was open on 24 October. Until a fixed gem is out, avoid calling Brotli.inflate on data from outside.

Proxies and servers: Envoy, Istio, nginx, curl

  • Envoy published GHSA-3wvj-j6qm-62mr on 23 October: only deployments with the Brotli decompressor filter configured are affected, fixed in 1.40.0, 1.39.3, 1.38.6, 1.37.8 and 1.36.12.
  • Istio shipped the Envoy fix in 1.31.2, 1.30.6 and 1.29.9 (bulletin ISTIO-SECURITY-2026-007, 15 October).
  • nginx and Apache use Brotli to compress responses (ngx_brotli, mod_brotli) and do not decode request bodies with it by default.
  • curl only decodes Brotli when asked to. In a test against a server that always sends Brotli, the CLI returned raw bytes until I added --compressed, which offers deflate, gzip, br, zstd. In programs, the equivalent is setting CURLOPT_ACCEPT_ENCODING.
curl 7.81.0, Ubuntu 22.04 (system libbrotlidec 1.0.9)
$ curl -s https://example.test/ | head -c 8     # raw bytes: curl did not decode
$ curl -s --compressed https://example.test/   # decoded: sends "deflate, gzip, br, zstd"

Linux distributions and containers

Anything that loads the system libbrotlidec is fixed by one package update and a restart: curl and libcurl, distribution builds of Node.js and PHP, Python's python3-brotli and more. The status differs a lot between distributions:

DistributionStatusFixed package
Debian 12 bookwormFixed (DLA-4855-1)brotli 1.0.9-2+deb12u1
Debian 13 trixieFixed (DSA-6582-1)brotli 1.1.0-2+deb13u1
Debian testing, unstableNot fixed-
Ubuntu (all releases)Needs triage-
Alpine 3.21, 3.22Fixedbrotli 1.1.1-r0
Alpine 3.23, 3.24Fixedbrotli 1.2.1-r0
RHEL 8, 9, 10Affected, Important-
Amazon Linux 2023Pending fix-
Check the installed package
# Debian / Ubuntu: fixed builds are 1.0.9-2+deb12u1 (bookworm), 1.1.0-2+deb13u1 (trixie)
dpkg -l libbrotli1

# Alpine: want 1.1.1-r0 (3.21, 3.22) or 1.2.1-r0 (3.23, 3.24)
apk info -v brotli-libs

# RHEL, Fedora, Amazon Linux
rpm -q brotli
Update
# Debian
sudo apt-get update && sudo apt-get install --only-upgrade libbrotli1

# Alpine (also in Dockerfiles)
apk update && apk upgrade brotli-libs

# Then restart services that load it, for example curl-based workers, PHP-FPM, Node.js
# from the distribution, and rebuild container images

Containers keep whatever was installed when the image was built. Rebuild from an updated base image (docker build --pull) and redeploy; patching the host does nothing for them.

Check any machine or image

Do not rely on Dependabot, pip-audit or npm audit alone. They only know about packages that have an advisory: they flag Python's brotli and brotlicffi, but not runtimes such as Node.js or .NET, copies bundled inside other packages, or operating system libraries.

The fix added a new error name to the C decoder's string table, so a compiled file that contains the decoder's error names but not the new one is unpatched. The Python checker from the Python guide uses this and scans any folder you give it, whatever language the files belong to. It only needs Python 3.8 or later on the machine doing the scan:

Terminal
# Any folder: system libraries, an app, a JDK, an extracted image
python3 brotli_check.py /usr/lib /opt/myapp

# Inside a container that has Python
docker run --rm -v "$PWD:/check" my-image python3 /check/brotli_check.py /usr/lib /app
What it found on my machines (summarised)
VULNERABLE /usr/lib/x86_64-linux-gnu/libbrotlidec.so.1.0.9             (Ubuntu 22.04)
VULNERABLE D:\Program Files\Git\mingw64\bin\libbrotlidec.dll          (Git for Windows 2.44.0)
VULNERABLE mingit\ucrt64\bin\libbrotlidec.dll                          (Git for Windows 2.56.0.windows.3)
VULNERABLE brotli4j\native-linux-x86_64\...\libbrotli.so               (Brotli4j 1.23.0)
VULNERABLE dotnet\shared\Microsoft.NETCore.App\3.1.32\clrcompression.dll (.NET Core 3.1)

It cannot read builds that strip the error names, such as .NET's current Windows DLL; check those by version. For everything else, these are the quick checks:

Quick checks by ecosystem
node -v                         # 26.12.1, 24.22.1 or 22.23.4
bun --version                   # 1.4.4 or later
go version -m ./server | grep andybalholm/brotli   # v1.2.7 or later
dotnet --list-runtimes          # see the .NET section: no fixed runtime yet
php --ri brotli                 # extension version; check the bundled library
php -r 'var_dump(curl_version()["brotli_version"] ?? null);'   # libcurl's Brotli
gem list brotli                 # Ruby gem version
mvn dependency:tree | grep -i brotli   # or: gradle dependencies | grep -i brotli
envoy --version                 # 1.40.0, 1.39.3, 1.38.6, 1.37.8 or 1.36.12
curl -V                         # shows brotli/x.y.z (distribution backports keep the old number)

What to fix first

  1. 1
    Anything that decodes Brotli from strangers. Public APIs that accept compressed request bodies (Express 5, aiohttp, ASP.NET Core with request decompression), Envoy with the decompressor filter, and services that fetch user-supplied URLs.
  2. 2
    Runtimes with a fix: Node.js, Bun, Python packages, the Go module, Envoy and Istio. Update, rebuild images, restart.
  3. 3
    The operating system package, on distributions that have one, then restart everything that loads it.
  4. 4
    Copies with no fix yet (.NET, Electron, Brotli4j, PHP and Ruby extensions, pyarrow, Pillow): keep untrusted Brotli data away from them and check again weekly.

Common questions

What are Node2Shell and HTTP2Shell?+
Both are nicknames for CVE-2026-111497, an out-of-bounds write in Google's Brotli C decoder scored 9.2 out of 10 (Critical, CVSS 4.0). It was first reported through Node.js (Node2Shell); HTTP2Shell reflects that any HTTP client or server that decodes Brotli can be affected.
Which languages are affected by the Brotli vulnerability CVE-2026-111497?+
Any that use Google's Brotli C decoder from 1.0.3 to 1.2.0: Node.js, Bun, Python (brotli, brotlicffi, pyarrow, Pillow), Java through Brotli4j, .NET, the PHP and Ruby extensions, and anything linking the system libbrotlidec, such as curl. Pure ports in Go, Rust, Java and JavaScript are separate code.
Is Go affected by CVE-2026-111497?+
The pure-Go andybalholm/brotli package had the same logic error, but in Go it can only cause a panic, not memory corruption. It was fixed in v1.2.7 on 23 October 2026. Programs that use cgo bindings to the C library depend on the system library instead.
Is .NET affected by the Brotli vulnerability?+
.NET bundles Brotli 1.1.0, which is in the affected range, and no .NET update had fixed it as of 24 October 2026. HttpClient only decodes Brotli when AutomaticDecompression includes it, and ASP.NET Core only when request decompression middleware is added.
Does updating libbrotli fix Node.js or Python?+
Only for builds that load the system library, such as Debian's nodejs and python3-brotli packages. Official Node.js builds and PyPI wheels bundle their own copy and need their own update.
Are nginx and Apache affected?+
ngx_brotli and mod_brotli compress responses and do not decode request bodies with Brotli by default. Other software on the same server, such as curl, PHP extensions or the application runtime, may still need updates.

Want your stack checked?

I update runtimes, dependencies and base images across Node.js, Python and PHP services, and verify the fix where the code runs. See Node.js, Python and Next.js bug fixing or PHP security updates.

Sources

Next steps

Keep reading

Need a hand with this?

Tell me what you are working on. Free scoping call, fixed quote within 48 hours.

Book a call

← All guides