Next.js 16.4.1 and October's Node.js release: a patch checklist for production apps

Two critical RCEs in Next.js and four high-severity Node.js CVEs in one week. What changed, who is affected and how to automate the check in CI.

Igor Calabraro

· 7 min read

In this post

Within a single week, the two pieces at the heart of almost every modern JavaScript stack shipped security fixes: Next.js on October 14 and Node.js on October 21. My take is simple: upgrading is not the hard part. The hard part is knowing, without relying on memory, whether every production app sits above the safe floor. This post sums up what was fixed and walks through a checklist, plus a script that turns it into a CI step.

#What Next.js fixed on October 14

The Next.js team shipped an out-of-band update with two fixes that had been held back from the September release because of upstream dependency delays. The patched versions are 16.4.1 (Active LTS) and 15.5.28 (Maintenance LTS).

AdvisorySeverityWho is affectedWorkaround
GHSA-673q-mjm6-r5xrCritical (RCE)App Router with Cache Components, when a use cache function returns multiple typed arraysNone: upgrade only
CVE-2026-96889 / GHSA-2464-fhr4-w9xwCritical (RCE)Image Optimization processing SVG on glibc-based Linuxsharp 0.35.5 or later
GHSA-p3m5-59mp-jv5rHigh (DoS)App Router with at least one Server ActionNone: upgrade only

Three details deserve attention:

  • The use cache RCE does not require you to have the vulnerable pattern. The official advice is to upgrade even if your code never returns typed arrays from a cached function. According to The Hacker News, it affects 16.0.0 through 16.4.0.
  • The image RCE comes from librsvg, bundled inside sharp. Next.js does not optimize SVG by default; that only happens with dangerouslyAllowSVG enabled or with next/og rendering SVG on the Node.js runtime. On the 15 line, 15.5.28 still accepts sharp 0.34.x, and upgrading over an existing install can leave the old version in place.
  • The DoS targets Server Actions. Crafted requests burn CPU and block the process for subsequent requests. Apps using only the Pages Router, or with no Server Actions at all, are not affected.

#What Node.js fixed on October 21

The Node.js security release covered 10 CVEs (4 high, 3 medium and 3 low), with fixes in v22.23.4, v24.22.1 and v26.12.1. The high-severity ones are the kind that slip through code review:

  • CVE-2026-111497: an out-of-bounds write in the Brotli decoder of node:zlib on malformed input, which can lead to a crash, memory disclosure or code execution. Relevant if you decompress third-party payloads.
  • CVE-2026-105482: dns.resolve*() and dns.reverse() silently truncate hostnames containing a NUL byte. That opens a path around domain allowlists, a common SSRF defense.
  • CVE-2026-106069 and CVE-2026-105483: alternative IP spellings (leading zeros or fullwidth digits) make certificate checks validate against an address other than the one actually connected.

Among the medium ones, one stands out if you use startup snapshots or SEA executables: crypto.randomUUID() and randomInt() may repeat values across processes (CVE-2026-106074). The release also updates c-ares, OpenSSL, SQLite and Undici.

#The checklist

This is the order I recommend for any Next.js app in production:

  1. Find out what is actually running, not what package.json says. The lockfile and the deploy image are the source of truth.
  2. Upgrade Next.js to 16.4.1 or 15.5.28. Anyone on unpatched lines (14 or older) needs to plan a major migration.
  3. Check sharp and make sure it is 0.35.5 or later, especially on the 15 line.
  4. Upgrade Node.js where the app runs: Docker image, engines in package.json, .nvmrc and the version configured on your deploy platform.
  5. Review your exposed surface: dangerouslyAllowSVG, next/og usage and public Server Actions such as checkout or contact forms.
  6. Rebuild and redeploy. A patch installed without a new build protects nothing.

The manual verification commands:

# the version actually installed (works for npm, pnpm and yarn)
npm ls next sharp
pnpm why sharp

# upgrade
pnpm add next@16.4.1   # or next@15.5.28 on the 15 line

# Node version where the app runs
node --version

#Turning the checklist into a CI step

A manual checklist works once. To avoid depending on memory next time a round of patches lands, I prefer a dependency-free script that fails the pipeline whenever Node or Next is below the floor. Just update the FLOORS table with each new advisory.

// scripts/check-security-floor.mjs
import { readFileSync } from "node:fs";
import { createRequire } from "node:module";

const require = createRequire(import.meta.url);

// Minimum patched version per major line (October 2026 patches)
const FLOORS = {
  node: { 22: "22.23.4", 24: "24.22.1", 26: "26.12.1" },
  next: { 15: "15.5.28", 16: "16.4.1" },
};

function parse(version) {
  return version.replace(/^v/, "").split("-")[0].split(".").map(Number);
}

function isAtLeast(current, floor) {
  const a = parse(current);
  const b = parse(floor);
  for (let i = 0; i < 3; i++) {
    if (a[i] !== b[i]) return a[i] > b[i];
  }
  return true;
}

function check(name, version) {
  const [major] = parse(version);
  const floor = FLOORS[name][major];
  if (!floor) return `${name} ${version}: line ${major} has no patch, migrate to a newer major`;
  if (!isAtLeast(version, floor)) return `${name} ${version}: upgrade to ${floor}+`;
  return null;
}

const nextPkg = JSON.parse(readFileSync(require.resolve("next/package.json"), "utf8"));

const problems = [
  check("node", process.versions.node),
  check("next", nextPkg.version),
].filter(Boolean);

if (problems.length > 0) {
  console.error(problems.join("\n"));
  process.exit(1);
}
console.log("Node and Next are above the security floor.");

Run it with node scripts/check-security-floor.mjs as a step before the build. In a project on next@15.5.4, for example, the output is next 15.5.4: upgrade to 15.5.28+ and the process exits with code 1, which is enough to block the deploy on any CI. sharp is left out on purpose: since it is usually a transitive dependency of Next, checking it with npm ls sharp or pnpm why sharp is more reliable than trying to resolve it from the project root.

#Why this matters to whoever hires

Several projects in my portfolio run on Next.js, such as the custom CRM and the anti-cheat platform with video evidence. In systems like these, an unauthenticated RCE is not a theoretical problem: it means access to the server holding customer and operational data. For anyone hiring, the right question is not "does your app run the latest version?" but "how do you find out you need to upgrade, and how long does it take to reach production?".

#Conclusion

  • Upgrade to Next.js 16.4.1 or 15.5.28 and Node.js 22.23.4, 24.22.1 or 26.12.1, then rebuild and redeploy. There is no workaround for the use cache RCE or the Server Actions DoS.
  • Do not rely on npm audit alone: two of the three Next.js advisories were missing from its feed right after the patch.
  • Automate the version floor in CI. A script of a few dozen lines turns "I think I already upgraded" into a pipeline that fails when you did not.

#Sources

Want this level of care in your project?

Free 30-minute diagnosis: I look at your stack and tell you what needs attention.

Get my diagnosis

Keep reading

All posts

Rather have me handle this in your project?

The same care as the posts, applied to your product. Free 30-minute diagnosis, no strings attached.