security

Node.js October Security Release: The Brotli Flaw and How to Protect Your App

expressnextjsnodejssecurityserver-hardeningvulnerability
Gerald VillorenteOctober 24, 20267 min read
Node.js October Security Release: The Brotli Flaw and How to Protect Your App

On October 21, 2026, the Node.js project shipped emergency fixes for 10 security flaws across all three supported release lines (22.x, 24.x, 26.x). The headline is a bug in Node's built-in Brotli decompressor that can let an attacker run their own code on your server. If you run anything on Node — Express APIs, Next.js sites, React server rendering, background workers — this post explains what broke in plain language, how to check and fix your version today, and how to harden your app for the long run.

If you only remember one thing: upgrade Node to 22.23.4, 24.22.1, or 26.12.1 (whichever line you run) and redeploy. For the headline flaw there is no workaround — updating is the fix.

What is the vulnerability?

The most serious flaw is CVE-2026-111497: an out-of-bounds write in the Brotli decoder that Node.js bundles, rated High severity with remote code execution impact.

Unpack that in plain words:

  • Brotli is a compression format — a way to shrink web traffic so pages load faster. When your app receives Brotli-compressed data, Node decodes (unshrinks) it before your code sees the content.

  • Out-of-bounds write means the decoder can be tricked, by malformed compressed input, into writing past the end of its reserved memory space — scribbling over neighboring memory. Attackers shape that scribble until it becomes code execution: their instructions running inside your server process.

  • Where it triggers: anywhere your Node app decodes Brotli data an attacker influences — calling node:zlib decompression on request bodies yourself, or fetch()-ing a URL whose response arrives Brotli-compressed (Node's HTTP client decompresses automatically). If neither happens in your app, this particular flaw has no path in — but keep reading, because the same release fixes nine other issues.

The other nine span the usual suspects: DNS name handling, two TLS certificate hostname bypasses (a server proving its identity less strictly than it should), a keep-alive response mix-up, certificate validation for odd IP formats, predictable random values in startup snapshots, a ZipFile handling flaw, plus refreshed bundled dependencies (undici, OpenSSL, c-ares, SQLite). None has the headline's drama, but TLS and DNS bugs erode the exact guarantees your HTTPS traffic relies on — patch them all at once by upgrading.

One honest note: Node 20.x and earlier receive no fix (end of life), and short-lived odd lines like 25.x were never in support. If you run those, the upgrade is the patch.

How to check if you're affected

Two minutes:

  1. Check your runtime version:

node --version

You're exposed if the version is below the fixed one on your line: below 22.23.4 on 22.x, below 24.22.1 on 24.x, or below 26.12.1 on 26.x. Anything on 20.x or older — or an odd line like 25.x — needs a move to a supported line, not just a patch.

  1. Check what's actually deployed, not just your laptop. The version on your machine and the version inside your Docker image or server can differ. For Docker setups, look at the base image:

grep -h "^FROM" apps/*/Dockerfile* docker/*/Dockerfile* 2>/dev/null

If it names an older Node tag, your production is exposed even if your laptop is fine.

  1. Check whether you decode Brotli at all. Search your code for decompression of external data:

grep -rn "zlib\|brotli\|gunzip\|inflate\|createUnzip" apps packages --include="*.js" --include="*.ts" | grep -v node_modules

No hits, no body-decompression middleware, and no fetch() of URLs an attacker could influence? Then the headline flaw likely can't reach you — but the other nine still justify the upgrade.

How to secure your Node.js website

In order of urgency:

1. Upgrade Node everywhere, then redeploy

  • Local/dev machines: use your version manager (nvm install 26.12.1, or your package manager), then confirm with node --version.

  • Docker: bump the base image tag (e.g. node:26.12.1-alpine), rebuild with --build, and redeploy. A new tag without a rebuild changes nothing — verify the running container reports the new version:

docker compose exec api node --version
  • Managed hosts (Vercel, Railway, Render, etc.): most rolled the patched runtime out within a day — but runtimes often follow your configured version or rebuild triggers, so confirm in your dashboard and redeploy if the running version predates the fix.

  • After upgrading, restart everything. A patched binary that never starts is decoration.

2. Update your dependencies too

Node's fix covers Node. Your packages are your job:

npm audit

Read the output and act on it — especially anything critical on a network-facing path (frameworks, auth, upload handling, HTTP clients). During a recent build we watched npm itself warn that Multer 1.x carries patched vulnerabilities and urge an upgrade to 2.x: that warning is the system working as intended. Listen to it.

3. Stop decoding the internet's mail blindly

Make the Brotli flaw (and its future cousins) structurally unreachable:

  • Don't decompress what you don't need. If your API accepts JSON, you almost certainly never need to decode Brotli or gzip request bodies — so don't. Every decoder you never invoke is an invulnerable one.

  • Cap request sizes. Express's body parsers accept a limit — set one that fits your real payloads so a 2 GB "request" dies at the door instead of inside your process.

  • Treat fetched responses as hostile until proven otherwise. If your server fetch()es third-party URLs, validate status codes and content types before parsing, cap response sizes, and set timeouts. A server that fetches arbitrary, attacker-chosen URLs is doing the attacker's errands.

4. Harden the app and its container

  • Run as non-root. Official Node images default to root; create and switch to an unprivileged user (e.g. nodejs) so a takeover inherits far fewer powers.

  • Hide the version banner. Express answers with an X-Powered-By: Express header by default — a free version hint for scanners. Middleware like Helmet removes it and adds a set of sensible security headers in one line.

  • Keep secrets out of code and logs. Environment variables for keys and tokens, never committed files; make sure error responses and logs don't echo them back.

  • HTTPS everywhere, TLS kept fresh. Terminate TLS with current settings, redirect all HTTP to HTTPS, and let your CDN or host manage certificates so they never silently expire.

  • Backups and rollback plan. Image tags pinned, database backups tested, and a known-good deploy you can return to in minutes. Patching is calm when retreat is easy.

5. Cover the framework layer (Next.js / React / Express specifics)

  • Update the framework itself — Next.js, React, Express, and your auth/upload libraries — on the same day as Node. Framework CVEs are the more common way Node apps actually fall.

  • Validate every input at the boundary: server actions, route handlers, API endpoints, and form parsing. Type-check, length-check, and allow-list rather than block-list.

  • Uploads deserve suspicion: accept only needed file types, verify content (not extensions), cap sizes, store outside executable paths, and never execute or render uploads as code. Block SVG uploads if you serve them same-origin — embedded scripts execute.

  • Lock down rendering: escape or sanitize anything user-written before it reaches HTML (React escapes by default — stay inside its guardrails; reach for dangerouslySetInnerHTML never, or last).

How to avoid being a potential target

Attackers sweep the internet for the unpatched — not for you personally. Stay out of the sweep:

  1. Patch on a rhythm. Follow the official Node.js blog or release feed so security releases reach you in hours, not months. The sites hurt worst are always the ones that learn last.

  2. Run supported lines only. Even-numbered Node lines get long-term fixes; odd lines expire fast and old evens go end-of-life. Check the schedule before you standardize, and migrate before your line retires.

  3. Shrink dependencies. Every package is code you didn't write running with your privileges. Audit regularly, remove what you don't use, and prefer maintained packages. A smaller node_modules is a smaller target.

  4. Put a shield in front. A CDN/WAF (Cloudflare and peers) absorbs bot probing and known exploit patterns before they touch your origin — it doesn't replace patching, but it buys quiet.

  5. Watch and log. Centralize access and error logs, alert on spikes and 5xx bursts, and review dependency and runtime versions on a schedule — monthly beats never.

  6. Plan the bad day. Know in advance: how do you rotate every secret, restore from backup, and communicate downtime? Write the one-page incident plan before you need it.

Key sources

Related reading

PHP2Shell: The Critical PHP Flaw Every Website Owner Must Fix Now
security

PHP2Shell: The Critical PHP Flaw Every Website Owner Must Fix Now

October 23, 2026
beginnersphpsecurityserver-hardening
Hardening a Production Web App: A Practical Security Audit

Hardening a Production Web App: A Practical Security Audit

September 13, 2026
devopsdockernextjsnodejs

Comments

Comments disabled — configure NEXT_PUBLIC_GISCUS_* env vars.