Skip to content
Godek
Let's talk

Next.js 16.4.1 and the Node.js Brotli RCE: upgrade today

Next.js 16.4.1 and 15.5.28 close two critical RCEs; Node 22.23.4, 24.22.1 and 26.12.1 fix a Brotli RCE. What to check, in fifteen minutes.

· 7 min read

Jarosław MejerFreelance developer
A cross-section of stacked floor plates with a small ladder on the top one and a single red crack through one of the lowest plates
Two patches in one month, and the hole is always one layer below the one you checked.

Two runtime-level security updates in one month: Next.js on 14 October, Node.js on 21 October. Both fix remote code execution. Both are a one-line upgrade. If your app is on Next.js 16.4.0 or older, or on any Node.js below the versions in the table, the next fifteen minutes are the cheapest security work you will do this year.

This is also the first of a series. Every few weeks I will post a short note like this one: what got patched in the stack I ship, the exact safe versions, what to check. Same shape every time, so you can skim it.

What shipped in October 2026

WhatPatched versionWorst issueSource
Next.js 16 (Active LTS)16.4.1 (16.4.2 is a bug-fix patch from 15 October, also fine)Critical, unauthenticated RCENext.js, 14 Oct
Next.js 15 (Maintenance LTS)15.5.28Critical, unauthenticated RCEsame
Node.js 2222.23.4High, Brotli decoder RCENode.js, 21 Oct
Node.js 2424.22.1High, Brotli decoder RCEsame
Node.js 2626.12.1High, Brotli decoder RCEsame

The Next.js release is out-of-band and closes three issues, all in upstream dependencies. The nasty one: in App Router apps with Cache Components, a use cache function returning multiple typed arrays can be turned into unauthenticated remote code execution (GHSA-673q-mjm6-r5xr, with a matching React advisory). The team's words: "There is no known workaround for affected applications. You should upgrade immediately even if your application does not have similar functions." The second is RCE through the Image Optimization API fed a crafted SVG on glibc Linux (CVE-2026-96889); the fix is sharp 0.35.5 or later, which the patched Next.js pulls in for you. The third is a High-severity denial of service against any App Router app with a Server Action.

The Node.js release fixes ten CVEs across the three supported lines. The headline is CVE-2026-111497: malformed Brotli input makes the decoder in node:zlib write out of bounds, rated as crash, memory disclosure or remote code execution. Next to it: two TLS hostname-verification bypasses, a DNS truncation bug, and new OpenSSL, undici, c-ares and CA certificates. Your code does not need to do anything exotic. Brotli decoding is what happens when a response arrives with Content-Encoding: br.

Upstream is your problem too

Not one of the three Next.js bugs was in Next.js. They came in through React and sharp. The Node bugs sit one level further down, in the runtime your framework never sees. So "we are on the latest Next.js" says nothing about the Node tag in your Dockerfile. You patch layers, not a product.

A stack of five flat layers seen from the side, labelled only by shape, with a small red crack running through the second layer from the bottom
Your app, the framework, its dependencies, the runtime, the image. October's holes were in the two layers nobody looks at.

Hosting changes the arithmetic per bug, not per platform. Vercel rolls out Node.js patch versions itself, and some advisories do not apply there: September's SSG cache poisoning carried the line "Applications deployed on Vercel are not affected." The October ones carried no such line. Read each advisory to the end. Self-hosted on Railway, Fly or a client's Kubernetes, you are the hosting provider, and the fix lands when you rebuild the image.

The fifteen-minute check

Run this in every repo you are responsible for, including the ones untouched since spring:

Terminal
npx next --version    # want 16.4.1+ or 15.5.28+
node -v               # want 22.23.4+, 24.22.1+ or 26.12.1+
npm ls sharp          # want 0.35.5+ if next/image is in play
grep -n FROM Dockerfile   # the Node tag you actually ship

Then the two places a version hides outside the repo: the platform's runtime setting (on Vercel: Project Settings, Build and Deployment, Node.js Version, overridden by engines.node in package.json) and the base image tag. A floating tag like node:22-bookworm-slim picks up 22.23.4 only when something triggers a rebuild, so trigger one.

Node 24 moved to Maintenance on 20 October and Node 26 becomes Active LTS on 28 October, so a new Dockerfile this autumn lands on 24 now, 26 once your dependencies agree.

Why "next sprint" stopped being an option

Vulnerability discovery is being automated, and the numbers are not subtle. Mozilla shipped Firefox 150 with fixes for 271 security bugs found by an early Claude Mythos Preview; the previous model generation had surfaced 22 in Firefox 148. Daniel Stenberg, curl's maintainer since 1998, wrote in April that security reports now arrive one every 20 hours on average: "The time when we suffer from large amounts of AI slop is gone. Now we instead suffer under a massive load of good reports." The Next.js team gave the same reason for moving to a monthly security release in July: "The volume of vulnerability research across the industry is rising fast, driven by LLM-assisted discovery." Five Next.js security releases followed in four months, two of them out-of-band.

Defenders finally have a chance to win, decisively.

— Bobby Holley, CTO of Mozilla, April 2026

He is right, on one condition: the fix has to be installed. The other side is automating too. Mandiant's M-Trends 2026 puts the mean time from disclosure to exploitation at an estimated minus seven days. When React2Shell dropped on 3 December 2025, Amazon saw active exploitation attempts within hours, with the dry footnote that platform protections "aren't substitutes for patching."

The pre-AI baseline for a skipped patch is Equifax. The US GAO report has the timeline: US-CERT publicised the Apache Struts flaw on 8 March 2017, attackers scanned Equifax for it on 10 March, got in on 13 May and stayed about 76 days. 145.5 million people. The patch existed the whole time; the internal notice went to an out-of-date mailing list and a scan a week later missed the server. Not a zero-day. A stale email list. That is the whole damn lesson, and those attackers worked on a nine-week schedule. Today's are scripts on a nine-hour one.

What I'd actually do

  • Subscribe to the Next.js security feed and the Node.js vulnerability feed. Next.js announces about a week ahead with the expected severity, so you can book the hour before the patch exists.
  • Put a monthly "patch hour" in the calendar, the week after the Next.js release. Framework, runtime, base image, lockfile. An hour, not a sprint; the point is that it never grows into one.
  • Pin the Node major in engines.node and the Dockerfile, and let Renovate or Dependabot open the bump. A bot's PR you merge in a minute beats a reminder you ignore for a month.
  • Try npx next@canary upgrade --agent with its default security policy. Experimental, but it picks the safe release for your major, prepares the migration notes and hands the task to Claude Code or Codex. Next.js 16.4 also added experimental.agentUpgrade, which nags during next dev and next build when your version has an advisory. Leave it on. It fits the gated agent workflow I already run: the agent does the bump, the build gate and I do the approving.
  • If you commission apps rather than build them, ask your developer two questions this week: which Node line are we on, and who runs the patch hour. Silence on either is your answer.

Next instalment when the next patch lands, which, on the last four months' form, is a few weeks away. If a project of yours has not been touched since the last one, that is a thing I can look at.