Is Your Node.js Version Vulnerable to the Brotli RCE? Check in 2 Minutes

CVE-2026-111497 is an actively exploited Brotli decoder bug in Node.js. Check your version in two minutes, see which frameworks and HTTP clients reach the decoder, patch by install method, and apply mitigations if you can't upgrade today.

Ashley Innocent

Ashley Innocent

5 November 2026

Is Your Node.js Version Vulnerable to the Brotli RCE? Check in 2 Minutes

Apidog for Enterprise

On-Premises Deploy

SSO & RBAC

SOC 2 Compliant

Explore Apidog Enterprise

Run this now. If your version sits below the floor in the table, the Node.js Brotli RCE (CVE-2026-111497) applies to you, and attackers are already using it.

node -v
Release line Vulnerable Fixed from Latest (Nov 5, 2026)
26.x Below 26.12.1 26.12.1 26.13.0
24.x Below 24.22.1 24.22.1 24.22.2
22.x Below 22.23.4 22.23.4 22.23.4
25.x, 20.x, older End-of-Life: unpatched and unassessed No fix exists Move to 24 or 26

For a second signal, ask the binary directly:

node -p "require('node:zlib').constants.BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH"

The fix added this constant. We ran it on nine official macOS builds from the three supported lines: every fixed build printed -17, and every older build printed undefined. Trust node -v first, because a distro that backports the patch may not add the constant.

Skip process.versions.brotli. It printed 1.2.0 on both 24.21.0 and 24.22.1, and 1.1.0 on both 22.23.3 and 22.23.4. Node.js cherry-picked the fix without changing the reported version, so this field can’t tell you whether you’re patched.

TL;DR

Question Answer
What is it? Out-of-bounds write in the Brotli decoder bundled with Node.js, also called Node2Shell or HTTP2Shell
Impact Crash, memory disclosure, or remote code execution
Severity HIGH per Node.js; 9.8 CRITICAL (CVSS 3.1) per NVD
Exploited? Yes. CISA KEV listed it on October 27, 2026
Login needed? No, per NVD’s vector and Akamai’s analysis
Who’s reachable? Apps that decode Brotli they don’t control: Express 5 bodies, fetch() responses, direct node:zlib calls
Fix Upgrade the runtime, rebuild images, restart processes
Workaround? The advisory lists none. Interim measures below reduce exposure but don’t cover everything
Timeline of CVE-2026-111497: Node.js fixes on October 21, CVE published October 22, exploit traffic reported October 26, CISA KEV listing October 27, KEV due date November 10, next Node.js security release November 11

ELLIO reported exploit traffic in its sensors by October 26, five days after the fix. The payload it captured targeted Node.js 24.22.0 on x86-64. That payload’s final stage failed in ELLIO’s tests, but ELLIO also confirmed code execution itself on stock 24.22.0 builds. CISA gave US federal agencies until November 10 to act, and it marks ransomware use as “Unknown”. Akamai’s telemetry showed 61% of networks running affected versions on October 26.

Node2Shell explained: what the Brotli bug does

Node2Shell is an out-of-bounds write in the Brotli decoder that ships inside the Node.js runtime. A malformed compressed stream makes the decoder write past the end of an eight-byte internal buffer, which corrupts process memory. The result can be a crash, leaked memory, or attacker-controlled code running on your server.

The root cause is a misclassified error. An invalid block switch came back as “I need more input” instead of “this data is broken”, so the streaming decoder kept appending bytes to that small buffer.

The bug lives in Google’s Brotli library, versions 1.0.3 through 1.2.0, so it isn’t only a Node.js problem. Node.js fixed its copy by cherry-picking upstream commit 0ed4268a into the 24.22.1 release and its siblings. OpenAI Codex Security researchers Khai Tran and Sylvie Mayer reported it.

Your dependency scanner won’t catch this, because the decoder ships in the runtime, not a package. npm install reported 0 vulnerabilities for our Express 5 test project while running on an unpatched Node.js 24.15.0.

Who is reachable

A vulnerable runtime is half the condition. The other half is a path that feeds untrusted Brotli data to the decoder. We tested each path on Node.js 24.22.1 by sending a harmless invalid body (the text not-valid-brotli) with Content-Encoding: br, and by serving valid Brotli to each client.

Path Version tested Runs the decoder? What we saw
Express 5 express.json() 5.3.0 (body-parser 2.4.0) Yes, by default 400, “Decompression failed”
Express 4 express.json() 4.22.3 (body-parser 1.20.9) No 415, unsupported encoding
Koa @koa/bodyparser 6.1.0 Yes, by default 500, BrotliDecoder error in the log
Fastify with @fastify/compress 9.3.0 Yes, once registered 400, FST_CP_ERR_INVALID_CONTENT
Plain Fastify 5.12.8 No 400, invalid JSON
Bare node:http server or http.get 24.22.1 No Raw bytes pass through
Built-in fetch() 24.22.1 Yes, always Decoded the response
axios, got, node-fetch 1.21.0, 16.2.0, 3.3.2 Yes, by default Decoded the response
zlib.brotliDecompress*, createBrotliDecompress Any Yes This is the decoder API
Diagram of paths into the Brotli decoder in node:zlib: Express 5 parsers, Koa body parsers and Fastify with @fastify/compress on the inbound side, fetch, axios and got on the outbound side, while Express 4, plain Fastify and bare node:http do not reach it

Two results deserve a second look. fetch() decoded Brotli even when the request sent Accept-Encoding: identity, because it follows the response header, not what you asked for. Any server your app calls can reach the decoder, so a webhook tester, link previewer or URL importer is exposed. And a 400 alone proves nothing: Express 5 and plain Fastify both return one, but only Express 5 ran the decoder. Read the error message.

Find your paths with three commands:

# Direct decoder use
grep -rnE "brotliDecompress|createBrotliDecompress" src/

# Parsers that decode request bodies
npm ls express body-parser @koa/bodyparser @fastify/compress

# Base images and pinned versions
grep -rnE "^FROM .*node" --include='Dockerfile*' .

One new fetch() call changes these answers, so “not reachable” still means patch.

How to patch CVE-2026-111497

Go to the latest build on your line, not the floor. These sources all carried fixed builds on November 5:

Install method Do this
nvm nvm install 24 && nvm alias default 24
Homebrew brew upgrade node (or node@24, node@22)
Docker FROM node:24.22.2-slim, then docker build --pull
Linux distro packages Follow your distro’s advisory, since it may backport the fix under an older version number
CI Update .nvmrc, engines and node-version, then rebuild
Serverless Log process.version from a deployed function; don’t assume the platform updated it

Then close the two gaps that catch people out:

Finish by running the checks at the top of this post inside the deployed container, then on CI runners and developer machines. To see the newest security build per line:

curl -s https://nodejs.org/dist/index.json | jq -r '[.[] | select(.security == true and (.version | test("^v(22|24|26)\\.")))] | group_by(.version | split(".")[0]) | .[] | max_by(.date) | "\(.version)  \(.date)"'

Still on 20 or 25? No build exists for you. Read the Node.js 20 End-of-Life plan and move.

Node.js Brotli mitigations if you can’t patch today

These buy time. None replaces the upgrade.

  1. Reject br at the edge. Block Content-Encoding: br at your proxy or load balancer, matching case-insensitively and inside lists like gzip, br.
  2. Reject it in the app. Put this before your body parsers. It returned 415 in our Express 5 test:
app.use((req, res, next) => {
  const encoding = req.headers['content-encoding'] || '';
  if (/\bbr\b/i.test(encoding)) return res.status(415).end();
  next();
});
  1. Turn off inflation. express.json({ inflate: false }) returned 415 for the same request. It rejects gzip bodies too, so check your clients first.
  2. Control outbound responses. axios accepts decompress: false, which left the bytes undecoded in our test. fetch() has no standard off switch, so restrict which hosts it can reach with an allowlist and egress rules.
  3. Limit the blast radius. Segment Node.js services, and restrict who can read core dumps, since ELLIO notes crashes can expose in-memory data there.

Watch for what ELLIO saw first: bursts of Brotli-encoded request bodies mapping which hosts decode them. Unexpected Content-Encoding: br traffic on a JSON API, or a spike in worker crashes, is worth an investigation.

Prove your API survived the upgrade: let your agent run it

A runtime jump can change TLS, DNS and HTTP behavior, and October’s release touched all three. Don’t diff that by hand. Let your coding agent run Apidog CLI before and after, then report what moved.

npm install -g apidog-cli@latest
apidog login --with-token <YOUR_TOKEN>
npx -y skills add https://apidog.com   # pick your agent when prompted

Give your agent one prompt:

Run Apidog test suite <id> in project <id> against staging and save the
results to reports/before. After I upgrade Node.js, add a test case for
POST /orders that sends the plain text "not-valid-brotli" with
Content-Encoding: br, asserts a 4xx status, then checks GET /health
returns 200. Rerun the suite to reports/after and list every request
whose result changed.

The agent runs these commands:

apidog run --test-suite <id> --project <id> -e <envId> -r cli,junit --out-dir reports/before
apidog cli-schema get test-case-create
apidog cli-schema validate test-case-create --file case.json
apidog test-case create --project <id> --file case.json
apidog run --test-case <caseId> --project <id> -e <envId> -r cli,json
apidog run --test-suite <id> --project <id> -e <envId> -r cli,junit --out-dir reports/after

That extra case is a health check, not an exploit: the body is plain text, and it failed with the same padding error on vulnerable and fixed builds in our test. It catches a real gap, though. Our Koa test answered 500 because the decode error went unhandled, and a public API should answer 4xx. Run it against staging only.

The run command reference lists every flag, and the CI/CD guide puts the same JUnit run in your pipeline. Apidog’s Free plan covers up to 4 users.

Why November 11 matters next

The Node.js project has pre-announced another release for 26.x, 24.x and 22.x on or shortly after November 11, 2026, again with HIGH as the top severity. No CVEs are public yet. Our November release guide covers how to prepare.

Patch Brotli now rather than folding it into that window. The bug has public details and live traffic today, and the upgrade you run this week rehearses the next one: same inventory, same image rebuilds, same test suite. PHP2Shell and React2Shell moved the same way.

FAQ

Is CVE-2026-111497 being exploited? Yes. CISA added it to the Known Exploited Vulnerabilities catalog on October 27, 2026, under Google Brotli, and ELLIO recorded exploit traffic by October 26.

Is it high or critical? Both labels are real. Node.js rates it HIGH. NVD scores it 9.8 CRITICAL on CVSS 3.1, and the Google-issued CVSS 4.0 score is 9.2. Plan around the fact that it’s exploited.

I’m on Express 4. Am I safe? Your request bodies don’t reach the decoder, but fetch(), axios and direct node:zlib calls still do. The same release also fixed nine other CVEs, so upgrade anyway.

Is Node.js 20 affected? The project doesn’t assess End-of-Life lines, and they get no fix. Treat 20.x and 25.x as unpatched and unassessed, then migrate.

Does this affect anything besides Node.js? Yes. The GitHub advisory covers the PyPI brotli and brotlicffi packages, and vendors report fixes for Bun 1.4.4 and .NET. Update each decoder separately, because a Node.js upgrade only covers its own copy.

Explore more

OpenAI's AI Found 948 Ways to Get Root on Linux. Is Your API Server Patched?

OpenAI's AI Found 948 Ways to Get Root on Linux. Is Your API Server Patched?

OpenAI's pipeline produced 948 unique Linux root exploits for $1,279 each. Here's what that means for API servers, how to check your kernel and patch state in 2 minutes, and how to limit what a foothold can reach.

5 November 2026

Still on Node.js 20? The November 11 Security Release Won't Patch You

Still on Node.js 20? The November 11 Security Release Won't Patch You

Node.js 20 reached End-of-Life on April 30, 2026, and the November 11 security release skips it. See what it has missed, whether to move to 24 or 26, what breaks, and what to do if you can't migrate this week.

5 November 2026

How to Let AI Agents Use API Keys Without Seeing Them

How to Let AI Agents Use API Keys Without Seeing Them

Let AI agents use API keys without seeing them: keep key names in context and values outside, with env vars, secret references, an injecting proxy and short-lived tokens.

4 November 2026

Practice API Design-first in Apidog

Discover an easier way to build and use APIs

Is Your Node.js Version Vulnerable to the Brotli RCE? Check in 2 Minutes