Source: https://alexjardinedigital.com/writing/keeping-nextjs-patched-2026
Author: Alex Jardine
Published: 2026-10-22

# The patch you applied might not be the one you’re running

Next.js has shipped nine security releases this year, and between October 14 and 21 Next.js, React, Node.js and PHP all shipped security fixes. Here are the ways a patch can look applied when it isn’t, and the checklist I now use on every site I maintain.

Alex Jardine Oct 22, 2026 10 min read

*Updated October 23, 2026: Amazon has since softened its PHP2Shell wording, and Netlify, Node.js, Vercel and PHP have added detail, so those sections are updated. I also corrected two dates and the count of upstream criticals, and filled in the full 2026 release list.*

On October 14, Next.js and React shipped fixes for two critical remote code execution flaws. On October 21, Node.js and PHP followed with security releases of their own, and attackers were already probing for the PHP bugs. I maintain several production sites on Next.js, including this one, so I spent part of that week patching.

The version bump was quick. Making sure the fix had actually landed took longer, because there are several ordinary ways for a patch to look applied when it isn’t. Here’s what I ran into and the checklist I use now.

Next.js security advisories in 2026 5 critical 15 high 21 moderate 3 low

## Nine security releases in ten months

By my count from the [Next.js advisories page](<https://github.com/vercel/next.js/security/advisories>), the project has published 44 security advisories this year: 5 critical, 15 high, 21 moderate and 3 low. They arrived in nine security releases, and every one has version numbers you can check on npm:

Next.js security releases, January to October 2026 Includes a critical

Read the releases as a list

- **January 26:**  three advisories, fixed in 16.1.5 and 15.5.10.
- **March 16:**  five moderate advisories, fixed in 16.1.7, and on the 15 line in 15.5.13 and 15.5.14 (March 19).
- **April 8:**  one high advisory, fixed in 16.2.3 and 15.5.15.
- **May 6 and 7:**  13 advisories across two releases a day apart, ending at 16.2.6 and 15.5.18. Vercel’s [changelog](<https://vercel.com/changelog/next-js-may-2026-security-release>)  listed every 13.x and 14.x version as affected, with no patch for either.
- **July 21:**  nine advisories, fixed in 16.2.11 and 15.5.21.
- **August 25:**  two critical remote code execution flaws, one in AVIF image handling and one on Windows-hosted servers, fixed in 16.3.3 and 15.5.24.
- **September 22:**  a critical flaw in ` ImageResponse `, the ` next/og ` image generator, fixed in 16.3.6.
- **September 30:**  seven advisories, fixed in 16.3.8 and 15.5.27.
- **October 14:**  two criticals and a high, fixed in 16.4.1 and 15.5.28.

All five of this year’s criticals allow remote code execution. As of October 22, none of the October Next.js or React advisories had been reported as exploited. I wouldn’t count on that lasting. When React2Shell landed last December, Wiz found that [39% of cloud environments](<https://www.wiz.io/blog/critical-vulnerability-in-react-cve-2025-55182>)  contained vulnerable Next.js or React versions, and exploitation followed quickly.

Rapid7 tracked 43 newly exploited high and critical vulnerabilities in the third quarter of 2026 and found exploitation began [three days after disclosure on average](<https://www.rapid7.com/blog/post/tr-q3-2026-threat-update-attackers-exploiting-vulnerabilities-within-3-days/>), with 71% of it inside the first week. Datadog’s State of DevSecOps report puts the median dependency [278 days out of date](<https://www.datadoghq.com/about/latest-news/press-releases/datadog-state-of-devsecops-report-2026/>). That’s why I don’t leave a security release for the next sprint.

## A security patch is now a minor upgrade

Since August, each critical fix has shipped on the newest minor of each line and nowhere else. If you were on 16.2 in August, there was no 16.2 patch. To stay patched on the 16 line, you went from 16.2.11 to 16.3.3, then 16.3.6, then 16.3.8, then 16.4.1. This site made that last jump, from 16.3.8, purely for the security fix.

A minor upgrade is usually painless, but it can still break things. It can pull new transitive versions into the lockfile, and those can fail lint or tests for reasons unrelated to the fix. Since you’ll be doing this roughly once a month, it’s worth having tests that catch real breakage and a deploy you can roll back quickly.

The line you’re on matters too. Next.js’s [support policy](<https://nextjs.org/support-policy>)  keeps each major in Maintenance LTS for two years after its release. Next.js 15 was released on October 21, 2024, so by that rule its maintenance window closed on October 21, 2026. The support page hadn’t been updated when I wrote this and still listed 15 as Maintenance LTS, so treat that as my reading of the policy, not an announcement. Either way, I’d plan as if 15.5.28 could be the last 15.x patch. The policy only promises fixes for unsupported versions “in rare circumstances,” and 13 and 14 got nothing this year.

Four traps

## Trap one: your lockfile isn’t your package.json

The October image flaw, [CVE-2026-96889](<https://github.com/vercel/next.js/security/advisories/GHSA-2464-fhr4-w9xw>), isn’t in Next.js’s own code. It’s in librsvg, which Next.js reaches through ` sharp `, the image library behind ` next/image `. The advisory’s workaround is to make sure the ` sharp ` Next.js uses is 0.35.5 or later, and it notes that fresh installs get a fixed version automatically. A project with an existing lockfile may not.

It wasn’t new in October, either. The librsvg CVE was published on September 23, and sharp shipped the fix in 0.35.5 on September 27, with [its own advisory](<https://github.com/advisories/GHSA-wq5f-xc86-pv6w>)  three days later. That was two to three weeks before Next.js published on October 14. The ratings differ too: Next.js calls it critical, sharp rates it high.

Next.js lists ` sharp ` as an optional dependency with a version range, and the ranges differ by line. On the 16 line, 16.4.1 asks for ` ^0.35.5 `, so the upgrade pulls it forward. (16.3.8 asked for ` ^0.35.4 `, which allowed the vulnerable release.) On the 15 line, 15.5.28 still accepts ` ^0.34.3 || ^0.35.5 `, so a lockfile that already resolved an older ` sharp ` can keep it after you bump Next.js. An override in your own ` package.json ` takes precedence over either range.

I hit both of these. My studio’s site had an override pinning ` sharp ` to 0.35.4. On a client site, the upgraded Next.js still accepted an older ` sharp `. Both looked patched in ` package.json `, but both were still installing a vulnerable ` sharp `.

```
# What is actually installed, and why
npm ls sharp next react react-dom
npm explain sharp
pnpm why sharp
yarn why sharp

# Overrides that can hold an old version in place
grep -nE '"(overrides|resolutions)"' package.json
grep -n -A5 '"pnpm"' package.json
```

Check what the lockfile resolves, not what package.json asks for.

Then check what’s deployed. On a page served by Next.js, ` window.next.version ` in the browser console reports the version the client bundle was built with. It isn’t proof of what every server function is running, but it catches a common failure: a merged upgrade that never deployed.

The same problem shows up one level higher. I keep this site’s source in one repository and deploy from a lean mirror. The security upgrade went into the mirror first, and a day later the source still said 16.3.8. If I’d synced from it, I would have quietly rolled the live site back, so the source needed the same upgrade.

## Trap two: the bug isn’t in Next.js

Four of this year’s five critical Next.js advisories came from code underneath it. Three came through image handling: August’s AVIF flaw through libheif, September’s through Satori, and October’s SVG flaw through librsvg. The fourth, October’s ` use cache ` flaw, came from React Server Components. The AVIF and SVG flaws both arrive via ` sharp `. If your app uses ` next/image ` with the built-in optimizer, or ` next/og `, watch the image pipeline closely: it produced three of this year’s five criticals.

The advisories are specific about preconditions. The October image flaw applies “when Next.js runs on glibc-based Linux.” Alpine-based Docker images use musl, so they may fall outside that particular advisory. That’s my reading, not Vercel’s statement, and it does nothing for the other October issues. Where you host matters as well. Netlify says its Image CDN serves ` next/image ` on its platform, so [that path isn’t exercised there](<https://www.netlify.com/changelog/2026-10-14-nextjs-react-security-vulnerabilities/>). The same flaw is still reachable through ` next/og ` ` ImageResponse `, which runs in your own functions, and there Netlify puts the impact at a crashed function invocation rather than code execution. The [Next.js announcement](<https://nextjs.org/blog/nextjs-security-update-october-14-2026>)  makes no such statement about Vercel. It just tells you to patch your Next.js dependencies, so that’s what I’d do on any host.

The other two October issues depend on what your app uses:

- The ` use cache ` flaw affects 16.0.0 through 16.4.0 apps with a ` use cache ` function that returns multiple typed arrays. There’s no workaround. It comes from an upstream [React Server Components flaw](<https://github.com/facebook/react/security/advisories/GHSA-xqc2-xf4c-x3h3>), fixed in ` react-server-dom-* ` 19.0.9, 19.1.10, 19.2.9 and 19.3.1.
- The Server Actions denial of service affects App Router apps with at least one Server Action, back to 13.0.0. Pages Router apps, or apps without Server Actions, aren’t affected. There’s no workaround and no patch for 13 or 14.

Use the preconditions to decide which sites to patch first, then patch the rest. The next advisory will likely have different preconditions, and staying on the current minor keeps the fix one small upgrade away.

## Trap three: your runtime is someone else’s patch

Node.js shipped [22.23.4, 24.22.1 and 26.12.1](<https://nodejs.org/en/blog/vulnerability/october-2026-security-releases>)  on October 21, fixing ten vulnerabilities. Node rated four of them high and none critical: two TLS hostname bypasses, a DNS name-truncation bug, and an out-of-bounds write in the bundled Brotli decoder that “permits remote code execution.” That last one is the one I’d worry about. It’s an upstream Google Brotli bug, and Google, which assigned the CVE, scores it 9.2. Node 20 reached end of life in April and Node 25 in June, so neither gets these fixes.

Who applies that patch depends on how you run Node. On a managed platform, it’s usually the platform’s job, and its documentation should tell you when the new release reached your functions. [Vercel’s bulletin](<https://vercel.com/kb/bulletin/node-js-security-advisory>), for example, says it added firewall rules the same day and manages patch versions for Node 22 and 24, but projects still on Node 20 have to switch to 22 or 24 and redeploy. In a Docker image, it’s whatever base image you built from. A tag like ` node:24-alpine ` only picks up 24.22.1 when you rebuild and redeploy, and it only has it once the image maintainers have published it.

PHP showed how much that lag can matter. In the [Hacker News thread](<https://news.ycombinator.com/item?id=50182987>)  on the PHP release, developers described distribution packages and Docker images arriving hours after the fix, while one commenter’s managed host had patched within about an hour. The [PHP Foundation](<https://thephp.foundation/blog/2026/10/21/todays-php-security-release-and-how-were-strengthening-php-security/>)  says one image vendor broke the embargo more than six hours early. Amazon’s threat intelligence team [saw an exploit attempt](<https://aws.amazon.com/blogs/security/amazon-threat-intelligence-identifies-php2shell-exploitation-prior-to-public-disclosure-in-madpot/>)  four days before disclosure and broad exploitation attempts once the fixes shipped, though it said it was unclear whether any would have succeeded. CISA said the same day that it had [not observed exploitation](<https://www.cisa.gov/news-events/alerts/2026/10/21/critical-vulnerabilities-php-require-immediate-patching>). So the PHP bugs had been probed but not confirmed exploited, which is still reason enough to patch.

### If you also run PHP sites

Many agencies run Next.js for some clients and WordPress for others, so the PHP side is worth a few lines. The fixed releases are [8.5.12, 8.4.27, 8.3.36 and 8.2.35](<https://www.php.net/archive/2026.php>). Branches 7.4 to 8.1 have only minimal source backports from the PHP project, and anything older has no fix. PHP 8.2 itself reaches end of life on December 31, 2026, so if you’re on 8.2, plan the move to a newer branch now. The mistakes I saw developers describe were operational:

- Changing the CLI ` php.ini ` while PHP-FPM reads its own. Check with ` phpinfo() ` served by FPM, not ` php -i `.
- Applying the stopgap with ` ini_set() ` or `.user.ini `. PHP says to set ` session.upload_progress.enabled=0 ` in php.ini, an FPM pool or server configuration, and to restart every worker. On October 23, PHP [added](<https://www.php.net/archive/2026.php#2026-10-23-1>)  that the setting should stay at 0 until the next regular bugfix release, even after patching, because of a separate issue in the same feature (CVE-2026-115560). Apps that never change the session serialize handler at runtime can leave it on.
- Upgrading the package without restarting PHP-FPM, which keeps serving the old code.
- Treating a firewall rule as the fix. Cloudflare deployed rules early, but it also reported attackers [changing their payloads](<https://blog.cloudflare.com/php-vulnerabilities-waf-protection>)  and told customers to patch anyway.

For site owners, I wrote a plainer guide on Jardine Studio: [Is your website exposed to this month’s security flaws?](<https://jardinestudio.com/journal/is-your-website-exposed>)

## Trap four: scanners lag the advisories

Dependabot and other scanners are worth running, but they read advisory databases, and those databases lag. In early September, a developer [reported on Hacker News](<https://news.ycombinator.com/item?id=49534734>)  that the critical AVIF advisory from August 25 was live on the Next.js repository but returned a 404 from the GitHub advisory API and OSV, and that their scanners had missed it. OSV [lists that advisory](<https://osv.dev/vulnerability/GHSA-2xp9-vwfh-vxw4>)  as published on September 8, two weeks after the fix, and lists both October 14 criticals as published on October 22. That’s a small sample, not a measured rate, but it’s enough that I don’t rely on scanners alone for criticals.

So I watch the sources directly: the security advisories pages for ` vercel/next.js ` and ` facebook/react ` on GitHub, the Next.js blog, the Node.js security blog, and the PHP announcements. Next.js posted advance notice on October 8 for the October 14 release, and those six days were enough to plan the work before the fixes landed.

## The checklist I use

This is what I ran across 12 JavaScript projects in October. Four were live sites, and all four were patched and live the same day, each as its own change so it could be reviewed and rolled back on its own.

1. **Inventory.**  For every project, record the framework and version, where it runs, what provides the runtime, and who’s responsible for patching it.
2. **Resolve versions.**  Read the lockfile, not ` package.json `: ` next `, ` react `, ` react-dom `, ` react-server-dom-* ` if present, and ` sharp `. Look for overrides and resolutions.
3. **Match the advisory’s preconditions.**  App Router or Pages Router? Server Actions? ` use cache `? The image optimizer on glibc Linux? ` next/og `? A Windows host? Use the answers to decide which projects go first.
4. **Upgrade on a branch.**  Move to the patched minor, force fixed transitive versions where needed, and regenerate the lockfile.
5. **Verify.**  Type check, lint, test and run a production build. Serve it locally and load pages and images. Then confirm the resolved versions again.
6. **Ship and confirm.**  Deploy, check the live version, and update every other copy of the code: mirrors, templates and starter repositories.
7. **Record it.**  The date, the versions before and after, and anything that held an old version in place, so the next patch starts from a known state.

```
# Quick precondition checks for the October advisories
grep -rln '"use cache"' app src 2>/dev/null
grep -rln '"use server"' app src 2>/dev/null
grep -rn 'ImageResponse' app src 2>/dev/null
grep -n 'unoptimized' next.config.*
```

Step 3, run from the project root.

## If you look after sites for clients

On client sites, the hard part of patching is usually knowing whose job it is. In the PHP thread, the same story came up repeatedly: an agency or freelancer builds the site and moves on, the client assumes the host handles updates, and nobody watches the releases, so when a critical fix lands, nobody applies it.

If you have more than a handful of client sites, the inventory from step one is worth building first. One line per site: what it runs, which versions, where, and whose job the next patch is. When a release lands, you can see which sites are exposed without opening repositories one by one.

## Not sure your site is patched?

If you’re not sure whether your site is behind, or you’ve inherited one that nobody has been maintaining, I’ll check it for free. Send me the URL, or for a private project, the ` package.json ` and lockfile. I don’t need access to your repository. I’ll reply within one business day with what it runs, which current advisories apply, and what it would take to patch it, whether that’s a quick version bump or a bigger move off Next.js 13, 14 or 15.

If you want me to do the patching, or to keep an eye on releases for you every month, we can talk about that too. Email me at [alex@jardinestudio.com](<mailto:alex@jardinestudio.com>), or use the form below. If you’re an agency with client sites in the same position, have a look at [how I work with agencies](<https://alexjardinedigital.com/agencies>).
