Brotli CVE-2026-111497: Patch Node.js, Bun and Python Apps

Brotli CVE-2026-111497: Patch Node.js, Bun and Python Apps

Brotli CVE-2026-111497: Patch Node.js, Bun and Python Apps

CVE-2026-111497 is a memory-corruption bug in Google's Brotli decoder, the C code that unpacks Content-Encoding: br data. Crafted compressed data writes past the end of a buffer, which can crash the program, leak memory or run the attacker's code. Node.js, Bun, Python's Brotli and brotlicffi packages and Envoy each ship their own copy of that decoder, so each has to be updated on its own. This guide shows when an app is actually exposed, how to check a server in one command, and how to roll the fix out without missing a container.

How serious it is

  • Google rates it 9.2 (critical) on CVSS 4.0, Node.js rates it high, Red Hat 8.1.
  • Imperva's researchers ran their own code on an unpatched Node.js 24.22.0 on Linux ARM64, both through a fetched response and through an Express request body. The exploit is not public.
  • CISA's assessment of October 23 recorded no exploitation in the wild, and there is no reliable public proof of concept.
  • The flaw works both ways: a server that unpacks compressed input can be attacked by a client, and a client that unpacks compressed responses can be attacked by a server.

The fix was merged into Brotli's source on February 27, but no Brotli release carried it until October 21, which is why the patched runtimes all appeared in the same week.

Are you exposed?

Only code that decodes Brotli data someone else controls is at risk:

  • Node.js and Bun - the built-in fetch() reading a response sent with Content-Encoding: br, node:zlib Brotli calls on untrusted data, and request-body parsers that unpack Brotli uploads (Express 5, body-parser 2). A plain Node.js HTTP server does not decode request bodies by itself.
  • Python - having the Brotli or brotlicffi package installed is enough: requests, urllib3, httpx and aiohttp then decode Brotli responses on their own, even if your code never imports Brotli.
  • Envoy and Istio - only if a Brotli decompressor filter is configured.

Any service that calls third-party APIs, webhooks, payment providers or scrapes pages runs fetch() against servers you do not control. Removing br from Accept-Encoding is not a fix: a server can send Brotli anyway.

Software Affected Fixed in
Node.js 22.x, 24.x, 26.x before the fix; 20.x and older (end of life) 22.23.4, 24.22.1, 26.12.1
Bun 1.4.3 and earlier 1.4.4
Python Brotli 1.2.0 and earlier 1.2.1
Python brotlicffi 1.2.0.x and earlier 1.2.1.0
Google Brotli (C library) 1.0.3 - 1.2.0 1.0.10, 1.1.1, 1.2.1
Envoy 1.39.2, 1.38.5, 1.37.7, 1.36.11 1.40.0, 1.39.3, 1.38.6, 1.37.8, 1.36.12
Istio 1.31.0 - 1.31.1, 1.30.0 - 1.30.5, 1.29.0 - 1.29.8 1.31.2, 1.30.6, 1.29.9

Check a server in one command

This POSIX shell script looks at the Bun, Node.js and Python on the machine (or inside a container) and says which are older than the fix. Save it as brotli-check.sh:

#!/bin/sh
# CVE-2026-111497 (Brotli decoder): which runtimes on this host are older than the fixes?
ver_lt() { [ "$1" = "$2" ] && return 1; [ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n1)" = "$1" ]; }
if command -v bun >/dev/null 2>&1; then
  v=$(bun --version)
  if ver_lt "$v" 1.4.4; then echo "bun $v: VULNERABLE, upgrade to 1.4.4+"; else echo "bun $v: fixed"; fi
fi
if command -v node >/dev/null 2>&1; then
  v=$(node -p "process.versions.bun ? '' : process.versions.node")
  if [ -z "$v" ]; then echo "node: this is Bun's node shim, see the bun line"; else major=${v%%.*}
  case $major in
    22) fix=22.23.4 ;; 24) fix=24.22.1 ;; 26) fix=26.12.1 ;;
    *) fix= ;;
  esac
  if [ -z "$fix" ]; then echo "node $v: no fixed release for this line, move to 22, 24 or 26"
  elif ver_lt "$v" "$fix"; then echo "node $v: VULNERABLE, upgrade to $fix+"
  else echo "node $v: fixed"; fi
  fi
fi
for py in python3 python; do
  command -v $py >/dev/null 2>&1 || continue
  $py - <<'PY'
from importlib import metadata
for pkg, fix in (("Brotli", "1.2.1"), ("brotlicffi", "1.2.1.0")):
    try:
        v = metadata.version(pkg)
    except metadata.PackageNotFoundError:
        print(f"python {pkg}: not installed")
        continue
    a = [int(x) for x in v.split(".") if x.isdigit()]
    b = [int(x) for x in fix.split(".")]
    print(f"python {pkg} {v}: {'VULNERABLE, upgrade to ' + fix + '+' if a < b else 'fixed'}")
PY
  break
done
sh brotli-check.sh
docker exec my-app sh -s < brotli-check.sh   # the same check inside a running container

Output checked on 2026-10-24 (a developer laptop, then official Docker images):

bun 1.4.1: VULNERABLE, upgrade to 1.4.4+
node 26.6.0: VULNERABLE, upgrade to 26.12.1+
python Brotli: not installed
python brotlicffi: not installed
bun 1.4.4: fixed
node: this is Bun's node shim, see the bun line
node 22.23.4: fixed
node 16.20.2: no fixed release for this line, move to 22, 24 or 26
python Brotli 1.1.0: VULNERABLE, upgrade to 1.2.1+
python brotlicffi: not installed

Run it in every container, not only on the host: the host's Node.js says nothing about the one baked into an image.

How to roll out the fix

  1. Find every copy. Images are the usual miss. List what you run: docker ps --format '{{.Image}}', then the FROM lines of your Dockerfiles. A tag like node:22 or oven/bun:alpine only moves forward when you pull it; a pinned tag such as oven/bun:1.4.1-slim never does.
  2. Update the runtime. Bump pinned tags (oven/bun:1.4.4-slim, node:22.23.4-alpine), bun upgrade and your Node.js packages on hosts, and pip install -U "Brotli>=1.2.1" (or brotlicffi>=1.2.1.0) in Python environments. If a Python app does not need Brotli, pip uninstall Brotli brotlicffi also closes the path: the HTTP clients fall back to gzip and deflate.
  3. Rebuild and replace. docker compose build --pull && docker compose up -d. A running process keeps the old decoder until it restarts, so restart services on hosts as well.
  4. Verify. Run the check script again inside each container (docker exec <name> bun --version is the quick version). Lockfiles with --frozen-lockfile can fail the rebuild after you bump dependencies: commit the updated lockfile together with package.json.
  5. Cannot update yet? Reject requests with Content-Encoding: br at the proxy before anything decodes the body, and avoid fetching from untrusted hosts. Vercel notes that firewall rules do not cover responses your own code fetches from other servers - only the update does.

For a Node.js stack on a VM see Cloud Server for Node.js, for Python Cloud Server for Python and Flask, and for images that rebuild cleanly Cloud Server for Docker Swarm.

What we did

Within days of the fixes we moved every DCXV service that runs on Bun to 1.4.4: pinned base images went to fixed tags, and all images were rebuilt with a fresh pull. Our Node.js components do not decode Brotli bodies, and our proxies have no Brotli decompression. Customer servers are managed by their owners: if you run Node.js, Bun or Python on a DCXV cloud server, run the check above today, or ask us about managed server administration.

Sources (checked 2026-10-24): the Node.js October 2026 security releases (22.23.4, 24.22.1, 26.12.1), the Bun 1.4.4 release, the CISA assessment of October 23, 2026 and the Imperva research.

PHP2Shell: Check and Patch the PHP RCE Flaws on Your Server
clouddedicatedhosting

PHP2Shell: Check and Patch the PHP RCE Flaws on Your Server

PHP2Shell (CVE-2026-109618, CVE-2026-109619) lets an unauthenticated request run code in PHP. Fixed versions, a tested check script, php.ini stopgaps and an upgrade plan.

Brotli CVE-2026-111497: Patch Node.js, Bun and Python Apps
cloudnetworkinginfrastructure

Brotli CVE-2026-111497: Patch Node.js, Bun and Python Apps

A Brotli decoder flaw (CVE-2026-111497) can run code through fetch() in Node.js and Bun or through Python HTTP clients. Fixed versions, a tested check script and the rebuild steps.

How to Size a Cloud Server for SaaS: CPU, RAM, NVMe, Backups
cloudinfrastructurepricing

How to Size a Cloud Server for SaaS: CPU, RAM, NVMe, Backups

Size a cloud server for a SaaS app in Docker and Node.js: memory budget, CPU limits, NVMe and backups, a k6 load test, full monthly price and a worksheet.

Self-Hosted AI Coding Agents on EU VPS: Hardened Setup
aicloudhosting

Self-Hosted AI Coding Agents on EU VPS: Hardened Setup

Run AI coding agents on an EU VPS with limits: disposable workspaces, egress allowlist, scoped tokens, resource caps, tested code, honest risks and server cost.

Fix IPv4 Geolocation After a Transfer: Step-by-Step
ipv4networkingtransfer

Fix IPv4 Geolocation After a Transfer: Step-by-Step

Your transferred IPv4 block still shows the previous country? Learn how to verify WHOIS, BGP and GeoIP records and request corrections safely, step by step.