AI-FIRST CYBERSECURITY · Always Wise. Always Ahead. +91-95851-60363 info@semperwise.com DOVER, DE, USA

Vulnerability advisory · Node.js

Node.js CVE-2026-111497: the Brotli bug your code never calls.

On 21 October 2026 the Node.js project shipped security releases for every supported line, fixing ten vulnerabilities. The one that matters most sits in the Brotli decompressor bundled inside Node — and the commonest way to reach it is through code you did not write, because the built-in fetch(), Express 5 and the popular HTTP clients all decompress Brotli automatically.

SemperWise Vulnerability Research 13 min read Vulnerability Intelligence
GET /v1/orders/{id} POST /v1/orders GET /v1/users/{id} POST /v1/admin/roles Data store tenant A tenant B tenant C tenant D Object-level authorisation not enforced on 2 routes
10CVEs fixed in one release
9.2CVSS v4.0, as scored by Google
3 lines22.x, 24.x and 26.x patched
No fixFor Node.js 20 and older

What happened on 21 October

The Node.js project released v22.23.4 (LTS “Jod”), v24.22.1 (LTS “Krypton”) and v26.12.1 (Current). Between them they fix ten Node.js CVEs — four rated High, three Medium and three Low by the project — and update five bundled components: c-ares, OpenSSL (on 22.x and 24.x), SQLite (on 22.x), undici, and the root-certificate store.

That last change is the Node.js response to the compromise of eight eMudhra intermediate certificate authorities, which we cover separately in the eMudhra CA compromise. It landed the same day as critical releases from PHP and GitLab, and an Unbound DNS fix — an unusually heavy day of patching for anyone who runs web infrastructure.

CVE-2026-111497 in plain terms

Brotli is a compression format, used heavily on the web as Content-Encoding: br. Node.js ships Google’s C implementation of the Brotli decoder inside the runtime and exposes it through node:zlib.

The Node.js advisory describes the defect precisely: “An invalid block switch was reported as a temporary need for more input instead of a permanent format error, so the streaming decoder kept appending input bytes to an eight-byte internal buffer.” Every byte written past the end of that buffer corrupts the decoder’s neighbouring memory. In the project’s words, an attacker who can supply Brotli data that an application decompresses “can corrupt process memory, which can lead to a crash, disclosure of process memory, or remote code execution.”

This is an upstream bug, not a Node.js-only one. Google, which assigned the CVE, lists Brotli 1.0.3 through 1.2.0 as affected and released fixed versions 1.0.10, 1.1.1 and 1.2.1 on 21 October. The same CVE therefore covers the Python brotli and brotlicffi packages (fixed in 1.2.1 and 1.2.1.0), Envoy deployments with the Brotli decompressor configured, and the libbrotli packages shipped by Linux distributions.

One detail deserves attention. The upstream fix — commit 0ed4268a, “Detect and report invalid stream earlier.” — was authored on 27 February 2026 and sat in Brotli’s public repository for almost eight months before any tagged release contained it. The patch that shows where the bug is has been readable by anyone for most of the year.

How severe? Four official readings of one bug

WhoRatingWhat it reflects
Node.js project High No CVSS number is published in the advisory.
Google (the CVE assigner) CVSS v4.0 9.2 — Critical AV:N/AC:L/AT:P/PR:N/UI:N — network-reachable and unauthenticated, but the target must actually decompress attacker input.
Red Hat CVSS 3.1 8.1 — Important Rates attack complexity as High; Amazon Linux publishes the same score.
CISA (SSVC, 23 Oct) Exploitation: none · Automatable: no · Technical impact: total A decision aid rather than a score — “total” means full control if it works.
Scores published by the parties responsible, as of 23 October 2026. Figures quoted elsewhere that match none of these should be treated with caution.

Why you can be exposed without ever calling zlib

The advisory’s condition — an application that decompresses attacker-supplied Brotli with node:zlib — sounds narrow. It is not, because most of that decompression happens inside libraries, automatically, keyed on a header the other side controls.

Code pathDecodes Brotli automatically?Who can send the malicious data
Built-in fetch() (bundled undici) Yes — any response carrying Content-Encoding: br; over HTTPS it also advertises br by default Any server your application fetches from: webhooks, link previews, URL importers, partner APIs, anything an SSRF can point at
Express 5 / body-parser 2.x Yes — request bodies with Content-Encoding: br, unless inflate: false is set Anyone who can send a request to your API
axios (Node.js adapter) Yes by default, unless decompress: false Servers your application calls
got Yes by default (decompress: true) Servers your application calls
Bare http / https modules No — Node.js core does not decode Content-Encoding itself Only reachable if your own code passes the body to zlib
Established from each project’s source code. body-parser added Brotli support in 2.0.0, so Express 4 apps on body-parser 1.x do not decode Brotli request bodies by default.

Note the asymmetry in the first row. undici decides how to decode from the response’s Content-Encoding header, not from what your request asked for. Sending accept-encoding: gzip narrows what an honest server returns; a malicious one can send Brotli anyway.

The other nine CVEs in the release

CVE-2026-111497 is the headline, but three of the remaining issues are rated High and two of them undermine TLS certificate checking — the control most applications assume is doing its job.

CVESeverityLinesWhat it is
CVE-2026-105482 High 26, 24, 22 dns.resolve*() and dns.reverse() truncate names at a NUL byte, so attacker.example\0.trusted.example passes an allowlist check and then resolves attacker.example. An incomplete fix of CVE-2026-48930.
CVE-2026-105483 High 26, 24 TLS hostname check bypass when an IPv4 address is written in fullwidth digits; a regression after the fix for CVE-2026-48618.
CVE-2026-106069 High 26, 24, 22 A leading-zero IPv4 literal such as 0127.0.0.1 is checked as octal (87.0.0.1) but connected to as decimal on some platforms, so the certificate is validated against the wrong IP.
CVE-2026-105481 Medium 26, 24, 22 A keep-alive HTTP client can accept a response that arrived before its request was sent. An incomplete fix of CVE-2026-48931.
CVE-2026-106072 Medium 26, 24, 22 Non-canonical IPv4 spellings (0x7f.0.0.1, 2130706433, 127.1) let a certificate with only a DNS SAN authenticate an IP endpoint.
CVE-2026-106074 Medium 26, 24, 22 randomUUID() and randomInt() entropy caches get baked into startup snapshots and single-executable apps, so values repeat across launches.
CVE-2026-106070 Low 26 zlib.ZipFile returns attacker bytes after a failed ZIP header check — a scanner/extractor disagreement.
CVE-2026-106071 Low 26 Wildcard --allow-fs-* permission rules over-grant, so /etc/passwd.* also allows /etc/passwd.
CVE-2026-106073 Low 26, 24, 22 fs.realpathSync() skips the permission model’s read check. An incomplete fix of CVE-2026-21715.
Severity as rated by the Node.js project. Four of the nine are labelled incomplete fixes or regressions of earlier CVEs.

The bundled-dependency updates carry their own security content: c-ares 1.34.9 is a security release with eleven advisories (one High), OpenSSL 3.5.9 fixes the High-severity CVE-2026-84782 in DTLS, and the undici updates fix several High-severity issues, including CVE-2026-109383 — function options such as checkServerIdentity being silently dropped when an Agent cloned its options.

Affected and fixed versions

Release lineStatusUpgrade to
26.x Current — becomes LTS on 28 October 2026 26.12.1 or later
24.x “Krypton” Long-term support 24.22.1 or later
22.x “Jod” Maintenance LTS, supported to 30 April 2027 22.23.4 or later
20.x and older End-of-life (20.x ended 30 April 2026) No fix — move to 22.x or 24.x
Source: Node.js release notes and release schedule. The project states that “End-of-Life versions are always affected when a security release occurs.”

How to find every vulnerable Node.js runtime

Upgrading is the easy part. The work is finding every copy, because Node.js rarely lives in one place: operating-system packages, version managers on developer and build machines, container base images, CI runners, serverless runtimes and desktop apps built on Electron each carry their own.

On each host
# The node on PATH — patched means v22.23.4+, v24.22.1+ or v26.12.1+
node --version

# Every node binary on the machine, not just the first one on PATH
which -a node nodejs
sudo find / -xdev \( -name node -o -name nodejs \) -type f -perm -u+x 2>/dev/null \
  | while read -r b; do printf '%s\t' "$b"; "$b" --version 2>/dev/null || echo '?'; done

# Version managers on developer and build machines
ls ~/.nvm/versions/node/ 2>/dev/null
volta list all 2>/dev/null; fnm list 2>/dev/null; asdf list nodejs 2>/dev/null

# Operating-system packages (Debian's nodejs uses the system Brotli library)
dpkg -l nodejs libbrotli1 2>/dev/null | awk '/^ii/{print $2, $3}'
rpm -q nodejs brotli 2>/dev/null

# Python services carry the same CVE through the brotli package
pip show brotli brotlicffi 2>/dev/null | grep -E '^(Name|Version)'
Containers and dependencies
# Node.js inside each running container
docker ps --format '{{.ID}} {{.Image}}' | while read -r id img; do
  printf '%s %s ' "$id" "$img"; docker exec "$id" node --version 2>/dev/null || echo 'no node'
done

# Images in a Kubernetes cluster that look like Node.js workloads
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}{"\t"}{.spec.containers[*].image}{"\n"}{end}' | grep -i node

# Which of your services decode Brotli request bodies automatically
npm ls express body-parser axios got 2>/dev/null

The process.versions trap

It is tempting to check the bundled library version with process.versions.brotli. Do not rely on it. The Node.js fix was a cherry-picked commit, and the version header was not changed — so patched 24.22.1 still reports Brotli 1.2.0, exactly like vulnerable 24.22.0. On Debian, the value reflects the system library and stays the same after the security update too. Decide on process.version, and on Debian on the libbrotli1 package version.

Debian, Ubuntu, Red Hat and container images

  • Debian builds nodejs against the system Brotli library, so the fix ships in the brotli source package: 1.1.0-2+deb13u1 for trixie (DSA-6582-1) and 1.0.9-2+deb12u1 for bookworm (DLA-4855-1, Debian LTS), both published 23 October. Restart long-running Node processes afterwards — a running process keeps the old library mapped.
  • Ubuntu lists brotli and nodejs as needs-triage at medium priority, with no Ubuntu Security Notice yet as of 23 October.
  • Red Hat rates the CVE Important; fixes for the RHEL brotli packages and the nodejs:24 and nodejs:26 modules were still pending on 23 October.
  • Official Docker images — the node:22, node:24/lts and node:26/current tags were rebuilt on 21 October. A container picks up the fix only when you rebuild your image and redeploy it; restarting a container does nothing.

If you cannot patch today

The Node.js project documents no workaround. The measures below reduce exposure while an upgrade is scheduled; none of them replaces it.

  • On Express 5, set inflate: false on body parsers for routes that never need compressed request bodies. The parser then rejects any non-identity Content-Encoding with a 415.
  • Reject or strip Content-Encoding: br on inbound requests at your reverse proxy or WAF.
  • Restrict which hosts your services fetch from. Red Hat’s guidance is to “limit exposure of services that decompress Brotli from untrusted peers”.
  • Treat an explicit accept-encoding header on outbound calls as partial protection only, for the reason given above.

Exploitation status, as of 23 October 2026

CVE-2026-111497 is not in CISA’s Known Exploited Vulnerabilities catalogue, and CISA’s assessment records exploitation as “none”. Red Hat states that “there is no public, reliable remote code execution proof-of-concept”.

On 22 October the security firm Imperva reported that it had achieved code execution in a lab, using the official Node.js 24.22.0 linux-arm64 image, through both fetch() responses and Express 5 request bodies. By Imperva’s own account the technique was unreliable and took multiple attempts, and it did not publish its code. Several GitHub repositories claim proofs of concept; according to press reports, the early ones crashed the process rather than running code.

That picture rarely lasts. The upstream fix has been public since February, the bug class is well understood, and the attack surface is any service that decompresses data it did not produce. Plan as though a reliable exploit will appear.

How SemperWise helps

Every runtime, not just the one on PATH

The optional Sentinel agent reports the installed software on each machine it watches, and SemperWise One grades every Node.js package against the fixed releases. A host on 22.x, 24.x or 26.x below the fix is raised as a finding that names CVE-2026-111497; one on an end-of-life line is raised as unsupported. Node.js inside container images and version-manager folders is reached from the build side, below.

Backports are not false alarms

A credentialed patch audit reads the distribution’s own advisories. A Debian host fixed through DSA-6582-1 is reported as fixed, even though its `nodejs` package version never changed — the case version-only scanners get wrong in both directions.

Your dependencies, in your repositories

Secure code review matches your lockfiles against current vulnerability intelligence, so the services that auto-decode Brotli — Express 5, body-parser 2.x, axios, got, Python’s brotli — are identified by name rather than by guesswork.

Closed when it is actually fixed

Findings are re-checked against every new inventory. One closes when the version moves past the fix, and reopens if an old image is redeployed — which is how most “patched” runtimes come back.

Known-exploited goes to the top

Every finding carries its CISA KEV status and EPSS exploit probability. If CVE-2026-111497 is added to the catalogue, it escalates automatically instead of waiting for someone to read the news.

Questions people ask about this

Is my application vulnerable if it never calls zlib?
It can be. The built-in fetch() decompresses Brotli responses automatically, Express 5 decompresses Brotli request bodies, and axios and got decompress responses by default. If your service uses any of these on Node.js 22.x, 24.x or 26.x below 22.23.4, 24.22.1 or 26.12.1, treat it as exposed. A service that only uses the bare http module and never passes data to zlib does not reach the vulnerable decoder.
Does process.versions.brotli tell me whether I am patched?
No. The fix was a cherry-picked commit that did not change the bundled library’s version string, so patched 24.22.1 and vulnerable 24.22.0 both report Brotli 1.2.0. Check process.version instead, and on Debian check the libbrotli1 package version, because Debian’s Node.js uses the system Brotli library.
We still run Node.js 20. What should we do?
Node.js 20 reached end-of-life on 30 April 2026 and receives no fix for this or any later vulnerability. Upgrade to 22.23.4 or 24.22.1. If an upgrade is genuinely blocked, the Node.js end-of-life page names HeroDevs, NodeSource and TuxCare as providers of commercial security fixes for retired lines — a bridge, not a destination.
Is CVE-2026-111497 being exploited?
As of 23 October 2026 it is not in CISA’s Known Exploited Vulnerabilities catalogue, and no official source reports exploitation in the wild. Imperva has reported unreliable lab code execution on arm64 without publishing its code. Because the upstream fix has been public since February 2026, a reliable exploit should be expected rather than hoped against.
Do Electron desktop apps need updating?
Electron embeds its own copy of Node.js, which node --version cannot see. As of 23 October no Electron release note mentions CVE-2026-111497, so whether Electron is affected is unconfirmed; Electron did ship the eMudhra certificate mitigation on 20 October. Watch each vendor’s release notes and update desktop apps as fixes appear.

SemperWise Vulnerability Research

Advisories & Patch Intelligence

Reads vendor advisories, CVE records, distribution trackers and government alerts the day they publish, and turns them into the version tables, detection steps and fix guidance our assessment teams work from. Every version number and quote is checked against its original source.

Next step

Talk to us about your next assessment.

A 30-minute call, then a scope document with what is in, what is out and what it costs. No obligation, and no charge for the conversation.