Node.js CVE-2026-111497: Brotli Decoder Out-of-Bounds Write Opens RCE on 22.x, 24.x and 26.x
Introduction
Node.js shipped its October 21 security release with ten CVEs, and the one that matters most is CVE-2026-111497: an out-of-bounds write in the bundled Brotli decoder that the project says can permit remote code execution. Every supported line — 22.x, 24.x and 26.x — is affected, there is no documented workaround, and a public proof-of-concept surfaced within a day. Upgrade to 22.23.4, 24.22.1 or 26.12.1, then rebuild anything that bakes the runtime in.
What Happened
On Wednesday, October 21, 2026, the Node.js project published fixes across its three supported release lines. The headline bug, CVE-2026-111497, is rated High and was reported by OpenAI Codex Security (Khai Tran and Sylvie Mayer). Matteo Collina and Antoine du Hamel landed the fix, which cherry-picks an upstream Brotli commit so the decoder now returns a new error, BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH, instead of carrying on and writing past its buffer.
Exploitation status as of October 22:
- A public PoC appeared shortly after the release. Reporting on it says that on a standard Node.js build it produced a process crash and a limited read of process memory; full code execution was only shown against a deliberately weakened build.
- Neither the Node.js project nor the outlets covering the release have reported in-the-wild exploitation.
- No CVSS score had been published at the time of writing.
The same release fixed nine other issues, several of which are worth caring about on their own:
| CVE | Severity | Issue | Lines |
|---|---|---|---|
| CVE-2026-111497 | High | Brotli decoder out-of-bounds write (RCE) | 26, 24, 22 |
| CVE-2026-106069 | High | TLS hostname check bypass when host loosely resolves to an IP | 26, 24, 22 |
| CVE-2026-105483 | High | TLS hostname bypass with fullwidth-digit IPs | 26, 24 |
| CVE-2026-105482 | High | dns.resolve truncates names containing NUL |
26, 24, 22 |
| CVE-2026-105481 | Medium | Keep-alive socket processes a response written before the request | 26, 24, 22 |
| CVE-2026-106072 | Medium | DNS SANs can authenticate IP endpoints with non-canonical IPv4 | 26, 24, 22 |
| CVE-2026-106074 | Medium | randomUUID() / randomInt() entropy caches frozen into snapshots and SEAs |
26, 24, 22 |
| CVE-2026-106070 | Low | ZipFile returns attacker-controlled prefix bytes | 26 |
| CVE-2026-106071 | Low | Permission Model wildcard over-grant | 26 |
| CVE-2026-106073 | Low | Permission Model bypass via fs.realpathSync |
26, 24, 22 |
Bundled dependencies were also bumped: c-ares, Undici, OpenSSL (24.x/22.x), SQLite (22.x), and the CA store, which drops the compromised eMudhra intermediate that browsers blocked between October 17 and 19.
Why It Matters
Brotli decoding is not an exotic code path you opted into. Node's built-in fetch() (Undici) transparently decompresses Content-Encoding: br responses, and Axios advertises Brotli in Accept-Encoding by default. Coverage of the bug also points out that Express 5's body-parser 2.x accepts Brotli-encoded request bodies with inflation on by default. That gives the bug two directions:
- Inbound — any service that decompresses client request bodies.
- Outbound — any backend that calls a third-party API, webhook target, or object store whose responses an attacker can influence. The attacker never has to reach your server directly.
Today's PoC stops at a crash on stock builds, which is already a cheap denial-of-service against API gateways, BFF layers and CI tooling. The distance from "controlled out-of-bounds write plus memory read" to "code execution" is the kind of gap that tends to close in days, not months. And because Node.js 20.x and older are end-of-life, a large tail of Lambda functions, container images and hosting-panel runtimes will not get an upstream fix at all.
The snapshot entropy bug (CVE-2026-106074) deserves its own line item: if you ship single-executable apps or user-land startup snapshots, every process started from that artifact may have generated the same "random" UUIDs and integers.
Who Is Affected
- Node.js 22.x before 22.23.4, 24.x before 24.22.1, 26.x before 26.12.1.
- Node.js 20.x and older: affected and end-of-life — no upstream patch. Some vendors (CloudLinux
alt-nodejs12throughalt-nodejs20) are backporting;node --versionwill not change on those builds, so verify by package release. - Single-executable applications (SEA) and startup snapshots built with a vulnerable runtime — they carry the old decoder until rebuilt.
- Container images pinned to vulnerable
node:tags, Electron or other products that embed Node.js, and serverless runtimes until the provider rolls the patch. - Updating the OS
brotli/libbrotlipackage does not fix Node.js; Node bundles its own copy indeps/brotli.
How to Protect Yourself
1. Inventory the runtimes that actually serve traffic
The version in your shell is not the version in your workers. Check running processes and images:
# running node processes and the binary they came from
ps -eo pid,args | grep -E '[n]ode( |$)'
for p in $(pgrep -x node); do echo "$p $(readlink /proc/$p/exe) $(/proc/$p/exe --version 2>/dev/null)"; done
# container images in use
docker ps --format '{{.Image}}' | sort -u | while read i; do
echo "$i -> $(docker run --rm --entrypoint node "$i" --version 2>/dev/null)"
done
# Kubernetes: images that look like node runtimes
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{range .spec.containers[*]}{.image}{"\n"}{end}{end}' | grep -i node | sort -u
2. Upgrade to a fixed release
Fixed builds: v22.23.4, v24.22.1, v26.12.1.
# nvm
nvm install 24.22.1 && nvm alias default 24.22.1
# Dockerfiles: bump the base tag and rebuild
grep -rnE '^FROM .*node:' --include=Dockerfile* .
# e.g. FROM node:24.22.1-bookworm-slim
# CloudLinux alt-nodejs
rpm -qa 'alt-nodejs*'
yum update 'alt-nodejs*'
Restart long-running processes afterwards — PM2, systemd units and hosting-panel Node selectors keep the old binary in memory until they restart.
3. Rebuild SEAs, snapshots and anything that embeds Node
A patched host runtime does nothing for an artifact that already contains the old one. Rebuild single-executable apps and --build-snapshot blobs with the fixed version, and redeploy. This also clears the frozen-entropy issue from CVE-2026-106074.
4. Find where you decode Brotli
There is no configuration switch that disables the vulnerable path, and maxOutputLength is not documented as a mitigation. Map your exposure so you know which services to patch first:
# direct use in your code
grep -rnE 'brotliDecompress|createBrotliDecompress|BrotliDecompress' --include='*.js' --include='*.ts' --include='*.mjs' . | grep -v node_modules
# inbound body parsing (Express 5 / body-parser 2.x)
npm ls express body-parser 2>/dev/null
# outbound HTTP clients that auto-decompress
npm ls undici axios node-fetch got 2>/dev/null
Until a service is patched, reducing risk means not decompressing Brotli from sources you do not control: strip or reject Content-Encoding: br on inbound requests at the reverse proxy, and avoid advertising br in outbound Accept-Encoding where you can set it. That narrows exposure; it does not close it.
5. Watch for crashes
The public PoC crashes stock builds, so unexplained Node worker restarts are your earliest signal:
journalctl -u 'your-node-service*' --since '2026-10-21' | grep -Ei 'segmentation fault|SIGSEGV|SIGABRT|core dumped'
pm2 logs --lines 500 | grep -Ei 'SIGSEGV|exited with code 139'
kubectl get pods -A --field-selector=status.phase=Running -o json | jq -r '.items[] | select(any(.status.containerStatuses[]?; .restartCount > 3)) | .metadata.namespace + "/" + .metadata.name'
6. Retire end-of-life lines
If you are still on Node.js 20.x or older, this is the release that should end that. Move to 22.x or 24.x LTS; vendor backports are a bridge, not a plan.
Source
- Node.js — Wednesday, October 21, 2026 Security Releases
- CloudLinux — Node.js October 2026 Security Releases: alt-nodejs Updates
- SecurityOnline — Node.js Security Release Fixes Remote Code Execution Bug
- byteiota — Node.js Brotli RCE CVE-2026-111497: Patch Your Backend Now
- The Hacker News — Node.js Brotli Decoder Bug Could Allow Remote Code Execution