AI provider API key leaked? Rotate it, cap spend, check usage
Replace and revoke the key, set a spend cap, and check usage. Steps for OpenAI, Anthropic, the Gemini API and Vertex AI, from each provider's docs.
CVE-2026-111497 is a Brotli decoder bug in Node.js and Bun. Check which runtime your server, image or host actually runs, then update to Node.js 22.23.4, 24.22.1 or 26.12.1, or Bun 1.4.4, and restart.

engines range check, the pip show check, the libbrotli package checks and three harmless "does this decompress Brotli?" tests, including one through Envoy. Those steps are marked Verified · Sources: linked below · Educational, not an auditIn October 2026, Node.js shipped security releases that fix CVE-2026-111497, an out-of-bounds write in the Brotli decoder that Node.js bundles (Node.js: October 21, 2026 security releases). Node.js says an attacker "who can supply Brotli data that an application decompresses with node:zlib can corrupt process memory, which can lead to a crash, disclosure of process memory, or remote code execution." Bun bundles the same decoder and shipped its own fix. GitHub's advisory database calls the bug "Node2Shell", and Bun's announcement on X calls it "HTTP2Shell" (Bun on X). Both names refer to this one CVE. Node.js's own post uses neither. Because the bug is in Brotli itself, other parts of your stack can be affected too (step 3).
Severity: Node.js rates it high. The CVE record, published by Google as the Brotli project's CVE authority, rates it Critical, CVSS 4.0 score 9.2 (NVD, CVE record). NVD's own analysis was still pending when we checked.
The version on your laptop isn't the one that matters. Check where the app is served from: the server, the Docker image, or the version your host is set to use.
Commands to check (Verified: we ran each one on a test machine using official node and oven/bun Docker images):
# On the server or in a shell where your app runs
node -v # e.g. v24.22.1
bun -v # only if you use Bun, e.g. 1.4.4
# Inside a Docker image you deploy (replace IMAGE)
docker run --rm IMAGE node -v
docker run --rm --entrypoint node IMAGE -v # if the image has its own entrypoint
grep -i '^FROM' Dockerfile # e.g. FROM node:22.23.3 is pinned to an affected version
# What your project asks hosts for
npm pkg get engines # e.g. { "node": ">=18" }
# At runtime (log this once at startup, then read your host's logs)
console.log("node", process.version, "bun", process.versions.bun ?? "-");
engines field is a range, not a version. On our test machine, "node": ">=18" accepted 20.20.2, 22.23.3 and 25.9.0, all of them unpatched. A range such as ">=22.23.4 <23 || >=24.22.1 <25 || >=26.12.1" accepted only the patched releases (Verified, using the semver package). How strictly a host follows engines depends on the host. (Docs-only)process.versions.brotli to judge Node. Node.js fixed this by cherry-picking the upstream patch (v24.22.1 release notes). On our test machine, patched and unpatched images reported the same Brotli version: 1.1.0 on 22.x, and 1.2.0 on 24.x and 26.x (Verified). Go by the Node version.process.version isn't Bun's version. Bun 1.4.3 and 1.4.4 both reported v26.3.0. In the oven/bun image, node -v also runs Bun (Verified). Use bun -v or process.versions.bun.Node.js limits the risk to apps that decompress Brotli data an attacker can supply. Many apps do this without calling node:zlib themselves. We ran two harmless tests with normal, valid Brotli data:
fetch(): on Node 22.23.4, 24.22.1 and 26.12.1, fetch() didn't ask for Brotli (it sent accept-encoding: gzip, deflate), but it still decoded a Brotli response when the server sent one (Verified). Bun 1.4.4 asks for Brotli by default (Verified), as Bun's advisory notes (GHSA-663w-cv8g-jj2p). So fetching URLs that users or third parties control is one way in.Content-Encoding: br on default settings (Verified). Other frameworks and middleware may behave differently. Check yours, or just update.Updating is simpler than proving you're not exposed. Treat any affected version as needing the fix.
| Runtime line | Affected | Fixed in |
|---|---|---|
| Node.js 26.x | before 26.12.1 | 26.12.1 |
| Node.js 24.x | before 24.22.1 | 24.22.1 |
| Node.js 22.x | before 22.23.4 | 22.23.4 |
| Node.js 25.x, 20.x and older | end-of-life, see note below | No release from Node.js |
| Bun | 1.0.21 up to, not including, 1.4.4 | 1.4.4 |
The Node.js lines come from the Node.js security release post and the release notes for each version, which list "(CVE-2026-111497) deps: brotli: cherry-pick". The Bun range comes from Bun's advisory, which says "Bun 1.4.4 updates brotli to 1.2.1" (GHSA-663w-cv8g-jj2p).
Node.js 20 and 25 are end-of-life: Node.js 20 reached end-of-life on April 30, 2026, and Node.js 25 on June 1, 2026 (Node.js releases). They get no fix, and Node.js says end-of-life versions "are always affected when a security release occurs" (Node.js). Move to 22.23.4, 24.22.1 or 26.12.1. Test your app on the supported line first.
Check your version against the table (Verified: on our test machine this printed OK v24.22.1 for node:24, UPDATE v22.23.3 for node:22.23.3, and NO FIX ON THIS LINE v20.20.2 for node:20):
node -e 'const f={22:"22.23.4",24:"24.22.1",26:"26.12.1"};const v=process.versions.node.split(".").map(Number);const t=f[v[0]];if(!t){console.log((v[0]>26?"LATER LINE, check nodejs.org ":"NO FIX ON THIS LINE ")+process.version)}else{const w=t.split(".").map(Number);console.log((v[1]>w[1]||v[1]===w[1]&&v[2]>=w[2]?"OK ":"UPDATE ")+process.version)}'
For Bun (Verified: printed OK 1.4.4 for oven/bun:1.4.4 and UPDATE 1.4.3 for oven/bun:1.4.3):
bun -e 'console.log(Bun.semver.satisfies(Bun.version,">=1.4.4")?"OK "+Bun.version:"UPDATE "+Bun.version)'
How to update depends on where your runtime comes from:
docker build --pull …, or pin a patched tag, such as FROM node:24.22.1. Then redeploy. Verified: on October 23, 2026, the official node:22, node:24 and node:26 images reported 22.23.4, 24.22.1 and 26.12.1, while images pinned to 22.23.3, 24.22.0 and 26.12.0 still reported those versions.bun upgrade, or a 1.4.4 or later image, then restart. Bun's advisory says executables built with bun build --compile stay affected until you rebuild them with 1.4.4 (GHSA-663w-cv8g-jj2p). (Docs-only)nodejs package "uses system provided brotli library" (Debian tracker). Follow your distribution's security notice for its nodejs and brotli packages. (Docs-only)A running process keeps the old runtime until it restarts. After updating, restart or redeploy, then run the check again where the app is served from.
No real workaround: Bun's advisory says decompress: false can be set per fetch() request, but "There is no process-wide workaround" (GHSA-663w-cv8g-jj2p). Update.
The bug is in Google's Brotli library itself, not in Node.js or Bun code. Bun's advisory says "Other projects that bundle brotli are affected in the same way" (GHSA-663w-cv8g-jj2p). Updating Node doesn't update any other copy of Brotli in your stack. Check these four places too.
Stopgaps: none of the official advisories for the components below describes a workaround. Updating is the fix. (Bun's per-request fetch() option is covered in step 2.)
The CVE record lists Brotli 1.0.3 through 1.2.0 as affected. It tells users to update "to the latest available version: 1.0.10 or 1.1.1 or 1.2.1" (NVD, CVE record). Google published all three releases, and each lists CVE-2026-111497 under SECURITY (v1.2.1, v1.1.1, v1.0.10). If you build or vendor Brotli from source, move to one of those releases on your line. (Docs-only)
# In your repo: is Brotli vendored or pinned anywhere?
grep -rniE 'google/brotli|brotli[-_ ]?v?1\.[0-2]' --include='*.txt' --include='*.cmake' --include='*.bzl' --include='Dockerfile*' .
brotli and brotlicffiThis matters if your Python backend decodes Brotli data it doesn't control, for example compressed request bodies. GitHub's reviewed advisory lists both PyPI packages as affected (GHSA-9v8h-qqgm-4m35):
| Package | Affected | Fixed in |
|---|---|---|
brotli | 1.0.3 up to, not including, 1.2.1 | 1.2.1 |
brotlicffi | 1.0.3 up to, not including, 1.2.1.0 | 1.2.1.0 |
Both fixed versions are published on PyPI. Neither package has a fixed release on an older line, so move to 1.2.1 or 1.2.1.0.
Check (Verified: in the official python:3.12-slim image, pip show reported 1.2.0 and 1.2.0.2 before the upgrade and 1.2.1 and 1.2.1.0 after. The one-liner printed UPDATE for both before and OK for both after):
pip show brotli brotlicffi | grep -E '^(Name|Version)' # "not found" means not installed in that environment
python -c 'from importlib.metadata import version as v
for p,f in (("brotli","1.2.1"),("brotlicffi","1.2.1.0")):
try: x=v(p)
except Exception: print(p,"not installed"); continue
t=lambda s: tuple(int(i) for i in s.split("."))
print(("OK " if t(x)>=t(f) else "UPDATE ")+p+" "+x)'
# Fix, then rebuild and redeploy the image or environment
pip install -U 'brotli>=1.2.1' 'brotlicffi>=1.2.1.0'
Run the check in the environment that serves traffic, such as the virtualenv or image, not just on your laptop. In our test, the brotli package's compiled module didn't link the system libbrotli (Verified), so updating the OS package doesn't fix the Python package. Update both.
A proxy in front of your app can decode Brotli before your app ever sees the request. Envoy has its own advisory for this CVE (GHSA-3wvj-j6qm-62mr, rated critical):
Envoy's release notes for the fixed versions don't mention this CVE (v1.39.3 release). The advisory is where Envoy lists the fix. (Docs-only)
Check whether your Envoy decodes Brotli request bodies. Look for the decompressor filter (envoy.filters.http.decompressor) with the Brotli decompressor library. Envoy's API docs say request decompression "is enabled by default if left empty" (decompressor.proto). So unless request_direction_config turns it off, that filter decodes request bodies.
# In your config files
grep -rn 'envoy.extensions.compression.brotli.decompressor' .
# On a running Envoy (admin interface; adjust the port)
envoy --version
curl -s localhost:9901/config_dump | grep -c 'compression.brotli.decompressor' # 0 = not configured
curl -s localhost:9901/stats | grep 'brotli.request.decompressed'
Verified: on our test machine, the official envoyproxy/envoy:v1.39.3 image, configured with the Brotli decompressor filter and no request_direction_config, decoded a normal Brotli-compressed request body before passing it upstream. The config_dump and stats commands above showed the filter and counted the decompressed request. If you use Envoy through another product, such as a mesh, gateway or ingress, check that product's own advisory for its patched release. (Docs-only)
We only list proxies whose vendor has published an advisory for this CVE. For any other proxy, gateway or sidecar, check whether it decompresses request bodies with Brotli, and check its vendor's advisories. (Docs-only)
libbrotliMany base images include the operating system's Brotli library because other programs, such as curl, link it. Node's official binary doesn't use it: ldd showed no libbrotli linked to node in the official node:22, node:24 and node:26 images, while curl in node:22 did link it (Verified). So check the image separately from Node.
# Debian / Ubuntu based images (replace IMAGE)
docker run --rm IMAGE sh -c "dpkg -l 'libbrotli*' | grep ^ii"
# Alpine based images
docker run --rm IMAGE sh -c "apk info -v | grep brotli"
# RPM based images (the package name varies, so match on brotli)
docker run --rm IMAGE sh -c "rpm -qa '*brotli*'"
No output means the image doesn't have the system library installed. Distributions often backport fixes without changing the upstream version number. Compare the full package version with your distribution's tracker, not with the 1.2.1 cutoff.
1.0.9-2+deb12u1 (DLA-4855-1) and trixie 1.1.0-2+deb13u1 (DSA-6582-1). Testing and unstable (forky, sid) show no fix yet. Verified: on October 24, 2026, the official node:22 and node:24 images (bookworm) had libbrotli1 1.0.9-2+b6 installed, and node:26 (trixie) had 1.1.0-2+b7. Those are the versions before the fix. Running apt-get update && apt-get install --only-upgrade libbrotli1 in node:22 installed 1.0.9-2+deb12u1. Plain debian:bookworm and debian:trixie didn't have the library installed, but offered the fixed versions.brotli 1.2.1-r0 for 3.23, 3.24 and edge, and 1.1.1-r0 for 3.21. The tracker didn't list 3.22 when we checked. Its repository offered brotli-libs-1.1.1-r0, which is built from a fixed upstream release (Verified: apk search in alpine:3.21 to 3.24). The base Alpine images had no Brotli package installed (Verified).brotli when we checked, so no fix has shipped yet. ubuntu:24.04 offered libbrotli1 1.1.0-2build2 (Verified). Watch the Ubuntu page for an update.To pick up a fix, rebuild with a fresh base image (docker build --pull) once the base image includes it. You can also add the package upgrade to your Dockerfile, then redeploy.
On a managed host or serverless platform, you usually don't install Node yourself. The fix still depends on which runtime your project runs on:
engines.process.version once at startup (step 1) so you can confirm what actually runs.We are not ranking hosts and don't name any host as affected. If you're not sure what your host runs, ask the host. (Docs-only)
Node.js credits "OpenAI Codex Security - Khai Tran and Sylvie Mayer" with reporting the vulnerability (Node.js). Envoy's advisory credits "OpenAI Security Research" (GHSA-3wvj-j6qm-62mr).
process.versions.brotli. It doesn't change with this fix.engines range such as >=18. It allows unpatched and end-of-life versions.bun build --compile executables.libbrotli each need their own update.Find every place this project sets or installs its JavaScript runtime: Dockerfile
FROM lines, package.json "engines", .nvmrc or .node-version files, CI workflow
files, and hosting or serverless config. List each one with the Node.js or Bun
version it pins or allows. Compare them with the releases that fix CVE-2026-111497:
Node.js 22.23.4, 24.22.1 or 26.12.1, or Bun 1.4.4 (Node.js 20 and 25 are
end-of-life with no fix). Also list any Python brotli or brotlicffi pins (fixed in
1.2.1 / 1.2.1.0), any vendored Brotli source (fixed in 1.0.10, 1.1.1, 1.2.1), and
any Envoy config using the Brotli decompressor. Propose the minimum change to pin
fixed versions and show the diff. Do not change anything else. Show the plan first and wait for my OK.
OK, or your host or distribution confirms the fix.Next.js security update · PHP RCE (PHP2Shell) · Poisoned dependency · Pre-launch checklist
This guide is educational and based on the vendor's public docs as of the review date. Platforms change: check the linked sources. Not a security audit. Disclaimer.
From BuiltSafely · builtsafely.com · https://builtsafely.com/fixes/node-brotli-rce/
The BuiltSafely weekly
Platform changes that affect the security of AI-built apps, checked against official docs. Free. Unsubscribe any time.