All posts
Forward Development

Next.js 16.3.3 patches two critical unauthenticated RCE flaws

Next.js 16.3.3 fixes two critical advisories — Windows-hosted server RCE and Image Optimization AVIF RCE. Here's who is exposed and how to mitigate.

  • Next.js
  • Operations

You run next start behind a reverse proxy on a Windows VM, or you run it in a container with next/image pointed at a handful of remote hosts. Both are ordinary setups. Both are in scope for the two critical advisories fixed in Next.js 16.3.3, and both are reachable without a login. That is the part worth reacting to: unauthenticated means an attacker needs nothing but your public URL.

The release notes for v16.3.3 list two security fixes, both rated critical:

  • Unauthenticated Remote Code Execution on windows-hosted serversGHSA-p293-qw3h-jr36
  • Unauthenticated Remote Code Execution in Image Optimization API when AVIF files are usedGHSA-2xp9-vwfh-vxw4

That is the entirety of what the release announces. No CVE numbers were published in the notes, so we are not going to invent any — the GHSA identifiers above are the ones to search your vulnerability tracker for.

Confirm what you are actually running before anything else

The version in your package.json is a range. The version on your server is a fact. Get the fact.

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

# or, from the lockfile-resolved tree
npm ls next

If you deploy from a Docker image, run it against the image, not your laptop:

docker run --rm --entrypoint node your-image:tag \
  -e "console.log(require('next/package.json').version)"

A surprising number of "we're on 16" answers turn out to be a stale image tag, a node_modules baked six weeks ago, or a latest tag that stopped moving when the registry credentials expired. Check the artifact you actually serve.

Who is exposed, and who is not

These two advisories have different blast radii, and conflating them wastes a maintenance window.

The Windows-hosted server RCE applies to the Next.js server process running on Windows. If your production hosts are Linux containers or Linux VMs, this specific advisory is not your production exposure — but your Windows developer laptops running next dev on a bindable interface, and any Windows-based staging or intranet box, still are. Internal does not mean unreachable.

The Image Optimization AVIF RCE applies to the Image Optimization API — the /_next/image endpoint that backs next/image. If your app renders next/image with a running Next.js server doing the optimizing, that endpoint is live and public. If you have images.unoptimized: true, or you use a custom loader that hands optimization to Cloudinary, imgix, or a CDN, or your app is a fully static export with no Next.js server in the request path, the optimizer is not yours to exploit.

One clarification that matters: remotePatterns governs which upstream hosts the optimizer will fetch from. A permissive remotePatterns — anything with a wildcard hostname — widens what an attacker can feed the optimizer. It is not the vulnerability, but it is the surface area dial.

Managed platform hosting narrows this further; platform operators generally patch the optimizer edge on their side. Self-hosted deployments — next start on your own EC2, ECS, Fly, Railway, bare metal, or Kubernetes — own the whole thing. Self-hosted is the population that has to move.

Which upgrade applies to 15.x versus 16.x

For the 16.x line, the fix is 16.3.3. Upgrade to it:

npm install next@16.3.3
# or pin exactly and rebuild your image

For the 15.x line, the release notes list v15.5.24 among the other recent releases in the repository. If you are on 15.x and not ready for a major upgrade, that is the release in your line to move to — and you should read the 15.5.24 notes and both GHSA advisories directly to confirm the backport covers both issues for your exact version before you call it done. The v16.3.3 notes do not enumerate what 15.5.24 contains, and we are not going to assert coverage the source does not state.

Do not upgrade to a canary. The notes list v16.4.0-canary.6, .7, and .8 as recent releases in the repo. Canaries are where fixes land first and where regressions land first. 16.3.3 is the current stable release carrying these fixes — ship that.

What to configure if you cannot ship an upgrade today

Sometimes the release train is a change-frozen week or a Magento-adjacent monolith where the storefront deploy is coupled to something slower. Interim mitigations, in rough order of preference:

Drop AVIF from the formats list. The advisory is specific to AVIF handling in the optimizer:

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

WebP covers effectively the same browser matrix for real traffic; you lose some compression efficiency on hero imagery and nothing else. This is the same lever that showed up in the canary line — narrowing what the optimizer will negotiate.

Tighten remotePatterns to exact hosts. No wildcard hostnames, no wildcard protocols:

images: {
  remotePatterns: [
    { protocol: 'https', hostname: 'cdn.example.com', pathname: '/media/**' },
  ],
}

Or take the optimizer out of the path entirely. images: { unoptimized: true }, or point loader at a CDN that does the resizing. You give up on-the-fly optimization; you also give up the endpoint.

Treat every one of these as a stopgap with a calendar date on it, not a fix. A config change narrows the input; the patched code is what removes the bug. And if your Windows hosts are the exposure, none of the image config helps at all — that path needs the version bump or it needs to stop being on Windows.

Make the next one of these boring

The teams that handle advisories badly are not the ones with bad engineers. They are the ones who cannot answer "what version is in production right now" in under five minutes. That is a tooling problem, and it is fixable: pin exact versions rather than ranges, emit the resolved framework version into a health endpoint or build label, wire Dependabot or Renovate with security updates set to auto-open, and subscribe the repo's security advisories to a channel a human reads.

We build enterprise Next.js applications with that plumbing in from the start, because the alternative is discovering your deployment inventory during an incident. The same discipline applies to a headless storefront where Next.js fronts a Medusa or Vendure backend — the frontend is a server with a public attack surface, not a static asset bundle, and it needs the same patch cadence you already give the commerce layer.

Do this today

  1. Enumerate every deployed Next.js app and record its running version from the artifact, not the repo.
  2. Move 16.x apps to 16.3.3 now. For 15.x apps, evaluate 15.5.24 against both GHSA advisories and move.
  3. For anything you cannot upgrade in this window, set images.formats to exclude AVIF and tighten remotePatterns to exact hosts — then book the upgrade.
  4. Audit Windows-hosted Next.js processes specifically, including staging and internal tools. They are the ones that get forgotten.
  5. Check your access logs for unusual /_next/image traffic — heavy volume, odd url parameters, unfamiliar upstream hosts.

If you are staring at a fleet of deployments and no reliable inventory of what is running where, that is the actual problem to solve, and it is a short engagement rather than a big one. Get in touch and we will work through it.

Need this done on a real stack?

Magento 2, Adobe Commerce, migrations to Medusa.js or Vendure, enterprise Next.js, WordPress, and AI automation.

Contact us