BuiltSafely

Home/Fixes

Trends

Is my AI-built app's Node server affected by the Brotli RCE?

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.

  • Docs-only
  • Reviewed Oct 2026
  • 23 official sources
Sources Last checked October 24, 2026 · Docs-only (nodejs.org, the Bun and Google Brotli release notes, the GitHub, Envoy and PyPI advisories and pages, the Debian, Alpine and Ubuntu trackers, and NVD; we did not reproduce the vulnerability). On a test machine with official Docker images, we ran the version commands, the version-check one-liners, the 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 audit

In 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.

1. Quick self-check: which Node or Bun actually runs your app?

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 ?? "-");
  • The 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)
  • Don't use 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.
  • Under Bun, 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.

Does your app decompress Brotli?

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:

  • Outgoing 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.
  • Incoming request bodies: in our test, a widely used Node web framework's JSON body parser decoded a request body sent with 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.

2. The fix: update Node.js or Bun, then restart or redeploy

Runtime lineAffectedFixed in
Node.js 26.xbefore 26.12.126.12.1
Node.js 24.xbefore 24.22.124.22.1
Node.js 22.xbefore 22.23.422.23.4
Node.js 25.x, 20.x and olderend-of-life, see note belowNo release from Node.js
Bun1.0.21 up to, not including, 1.4.41.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: rebuild with a fresh base image, for example 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.
  • A server you manage: install the fixed release from nodejs.org or your version manager, then restart the app process. (Docs-only)
  • Bun: 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)
  • Linux distribution packages: some distributions build Node against the system Brotli library. For example, Debian's security tracker notes that its 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.

3. Patched Node? Check the rest of your stack

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.)

Google's Brotli library

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*' .

Python: brotli and brotlicffi

This 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):

PackageAffectedFixed in
brotli1.0.3 up to, not including, 1.2.11.2.1
brotlicffi1.0.3 up to, not including, 1.2.1.01.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.

Reverse proxies and sidecars that decompress requests

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):

  • Vulnerable: Envoy v1.39.2, v1.38.5, v1.37.7 and v1.36.11, per the advisory.
  • Fixed: v1.40.0, v1.39.3, v1.38.6, v1.37.8 and v1.36.12.
  • Who's exposed: the advisory says the impact is on "Envoy deployments that have Brotli decompressor configured."

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)

Base Docker images with a system libbrotli

Many 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.

  • Debian (Debian tracker): fixed in bookworm 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.
  • Alpine (Alpine security tracker): fixed in 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).
  • Ubuntu (Ubuntu CVE page): every listed release showed "Needs evaluation" for 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.

4. If a host runs Node for you

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:

  • Check the Node.js version your project or function is set to use in the host's settings or config file, and in engines.
  • Check the host's changelog or status page to see whether it has rolled out 22.23.4, 24.22.1 or 26.12.1 for that line, and whether you need to redeploy to pick it up.
  • If the project is set to an end-of-life line (Node.js 20 or older, or 25), move it to a supported line.
  • Log 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)

5. Who found it

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).

What not to do

  • Don't check only your laptop. Check the server, the image, or the host setting the app actually runs on.
  • Don't judge Node by process.versions.brotli. It doesn't change with this fix.
  • Don't rely on a loose engines range such as >=18. It allows unpatched and end-of-life versions.
  • Don't stop at updating. Restart or redeploy, and rebuild any bun build --compile executables.
  • Don't assume a Node update covers everything. Python packages, proxies and the base image's libbrotli each need their own update.

AI prompt

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.

How to verify

  1. Run the self-check in step 1 and write down every place Node.js or Bun runs your app.
  2. Where it runs, the check in step 2 prints OK, or your host or distribution confirms the fix.
  3. For each item in step 3 that applies, the check shows a fixed version, or the component isn't present.
  4. After you restart or redeploy, check the running version again where the app is served from, for example in the startup log line.

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.

The BuiltSafely weekly

One email a week. What changed, and the one fix that matters.

Platform changes that affect the security of AI-built apps, checked against official docs. Free. Unsubscribe any time.