←All posts

Two Critical RCEs in Next.js: Patch Now, Then Look Hard at Your Image Pipeline

Next.js shipped 16.3.3 and 15.5.24 on August 25 to fix two critical unauthenticated remote code execution bugs — one in AVIF image optimization, one on Windows-hosted servers. The patch is the easy part; the lesson about /_next/image is the durable one.

Two Critical RCEs in Next.js: Patch Now, Then Look Hard at Your Image Pipeline

On August 25, 2026, Vercel published the August 2026 Next.js security release. Two critical-severity vulnerabilities, both unauthenticated remote code execution, both patched in v16.3.3 (Active LTS) and v15.5.24 (Maintenance LTS).

The release was pulled forward from its originally announced date after the team found a second critical issue in an upstream dependency. That detail matters more than it looks: the interesting bug in this batch is not really a Next.js bug at all.

If you self-host Next.js, stop reading and run the upgrade first.

npm install [email protected]   # for 16.3
npm install [email protected]  # for 15.5

What actually broke

1. AVIF optimization → RCE (GHSA-2xp9-vwfh-vxw4)

Next.js Image Optimization uses sharp, sharp links against libheif, and libheif had a memory-safety flaw (GHSA-g89c-p67h-r497). Feed the optimizer an attacker-controlled AVIF file and you get unauthenticated remote code execution on the server.

Read the attack path slowly, because it is the part worth internalizing. /_next/image is a public, unauthenticated endpoint that accepts a URL, fetches the bytes at that URL, and pushes them through a native image decoder. If an attacker can influence what URL that endpoint fetches — or can upload an avatar, a listing photo, a CSV-embedded logo — they get to hand raw bytes to a C++ decoder running in your server process. No login, no CSRF token, no session.

There is no clean patch available yet, because the fix lives upstream. So the patched Next.js releases take the blunt option: AVIF optimization is disabled. AVIF inputs are now served as-is, unresized and unoptimized, until a fixed libheif propagates.

2. Windows-hosted RCE (CVE-2026-75604)

The second issue, CVE-2026-75604 / GHSA-p293-qw3h-jr36, hits applications that use both the Pages Router and the App Router without Cache Components, when the Next.js server runs on a Windows filesystem. Linux and macOS are unaffected.

The advisory is explicit that there is no known workaround. If you have a Windows-hosted Next.js server in that configuration, upgrading is the only mitigation. That is an uncomfortable sentence to find in an advisory, and it should move this to the top of your queue rather than into a sprint backlog.

If you are hosted on Vercel, their changelog confirms no action is required — AVIF optimization was disabled across the managed service once the bug was identified, and the Next.js runtime there is Linux. Every other deployment target is yours to patch.

Verify you actually shipped the fix

npm install [email protected] updates your direct dependency. It does not guarantee that the version resolved in CI, in your Docker layer cache, or in a monorepo workspace with a pinned transitive copy is the one you think it is. Check the resolved tree, not the manifest:

npm ls next

In a monorepo, look for more than one answer:

npm ls next --all | grep -i 'next@'

Then confirm what is running in the built artifact, which is the only version that matters:

# inside the container or on the host running the app
node -p "require('next/package.json').version"

If you build images, rebuild them. A patched package.json sitting on top of a cached node_modules layer ships the vulnerable code.

Finally, make the audit routine rather than reactive:

npm audit --audit-level=high --omit=dev

The durable lesson: /_next/image is a compute endpoint

Both of these will be patched and forgotten in a week. The structural point will not be.

Next.js Image Optimization is easy to think of as a CDN feature. It is not. It is an unauthenticated HTTP endpoint that performs attacker-influenced I/O and then runs attacker-supplied bytes through native decoding libraries. That is a category of endpoint that deserves the same scrutiny as a file upload handler — and most teams give it none, because it arrived as a default.

Three things worth doing regardless of this advisory.

Constrain what the optimizer will fetch. remotePatterns is your allowlist. Keep it narrow and specific; a wildcard hostname turns your optimizer into an open proxy with a decoder attached.

// next.config.js
module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'assets.example.com',
        pathname: '/uploads/**',
      },
    ],
  },
};

Constrain the formats you decode. Every additional output format is another codec path. If you are on a patched release, AVIF output is already off; making that explicit documents the decision for whoever reads the config in six months.

module.exports = {
  images: {
    formats: ['image/webp'],
  },
};

Know whether you are running the optimizer at all. Plenty of Next.js sites do not. A static export with output: 'export' sets images.unoptimized and has no server-side image pipeline, so neither of these advisories reaches it. Knowing which category you are in — before an advisory lands — is what turns a fire drill into a five-minute check.

// A static-export site has no image optimization server surface.
module.exports = {
  output: 'export',
  images: { unoptimized: true },
};

The performance cost, and what to do about it

Disabling AVIF is a real regression, not a cosmetic one. AVIF typically encodes smaller than WebP at comparable quality, and for image-heavy pages the hero image is very often the LCP element. Losing AVIF means larger LCP payloads on exactly the pages that can least afford them.

Do not paper over this by hand-rolling an AVIF pipeline to get the savings back — you would be reintroducing the same decoder on the same untrusted input. Instead:

  • Re-measure rather than assume. Pull LCP from field data, not a lab run. If your hero images were already WebP or served through a third-party image CDN, the change may be close to invisible.
  • Recover the bytes elsewhere. Correct sizes attributes, tighter deviceSizes, and honest quality values usually reclaim more than the WebP/AVIF delta, and they cost nothing in risk.
  • Watch for the upstream fix. The Next.js advisory is explicit that AVIF is disabled until an upstream fix is propagated. Put a calendar reminder on it; this is the kind of temporary mitigation that quietly becomes permanent.

If your images are served by a managed image CDN rather than by your own Node process, this is also a reasonable moment to notice that the CDN is absorbing a class of risk on your behalf — and to check what their disclosure posture looks like.

Takeaways

  • Upgrade to 16.3.3 or 15.5.24 today if you self-host. Verify the resolved version in the running artifact, not just in package.json, and rebuild any cached container layers.
  • Windows-hosted servers using both routers without Cache Components have no workaround. Upgrade is the only fix.
  • Treat /_next/image as an unauthenticated compute endpoint. Allowlist remotePatterns tightly and limit formats to what you actually serve.
  • Expect a temporary LCP regression from AVIF being disabled. Measure it in field data, recover bytes through sizing rather than through a hand-rolled AVIF path, and track the upstream libheif fix so the mitigation does not become permanent.
  • The framework was not the weak link here — a transitive native dependency was. Your dependency audit should reach past the packages you chose deliberately.

Sources

←Back to all posts
Next step

Need help shipping software?

Tell us what you're trying to build. A discovery call, a one-page summary within 48 hours, a proposal within a week.

Response · 48h·NDA on request·US contracts only