# Next.js Secures Framework with Nine Critical Patch Updates

> Vercel addresses nine vulnerabilities in Next.js, fixing critical flaws that could lead to SSRF, authentication bypass, and DoS attacks.
> By Dave · 2026-07-23
> Source: https://otf-kit.dev/blog/nextjs-security-patches

## Why ship nine CVEs in one drop?

Vercel just published nine security advisories for Next.js and pushed a single coordinated patch — `15.5.21` for the 15.x line and `16.2.11` for 16.x. That's a quietly impressive amount of hygiene work for a framework this big. The issues include two SSRFs in request-routing features, a middleware/proxy bypass, a DoS path through Server Actions, two cache confusion bugs, and an Image Optimization crash that takes malicious SVG as input. All fixed in one release. The alternative — nine advisories discovering each other piecemeal over weeks — is the kind of thing that makes security teams pull their hair out. So: hats off to Vercel for the coordination and to researcher KarimPwnz for the reporting.

The reason this still matters to you, today, is that the [advisory batch](https://cybersecuritynews.com/next-js-patches-nine-security-flaws/) covers versions going back to `12.0.0`. If you're on any Next.js between `12.x` and `15.5.20`, or between `16.0.0` and `16.2.10`, you're exposed. The fix is one `npm install` away. The rest of this post is the upgrade ritual done right — and the two SSRF patterns worth understanding so you don't reintroduce them.

## What's actually in the batch

Eight of the nine advisories are spelled out in the disclosure; the ninth rounds out the coordinated release. Here's the lineup as filed:

| CVE | GHSA | Severity | Surface |
| --- | ---- | -------- | ------- |
| CVE-2026-64645 | GHSA-p9j2-gv94-2wf4 | High | SSRF via `rewrites()` / `redirects()` |
| CVE-2026-64649 | GHSA-89xv-2m56-2m9x | High | SSRF via Server Actions on custom Node servers |
| CVE-2026-64642 | GHSA-6gpp-xcg3-4w24 | High | Middleware + proxy bypass (Turbopack + legacy `middleware.ts` + single-locale i18n) |
| CVE-2026-64641 | GHSA-m99w-x7hq-7vfj | High | DoS via malicious Server Actions |
| CVE-2026-64646 | GHSA-4c39-4ccg-62r3 | Moderate | Unbounded Server Action payload in Edge runtime |
| CVE-2026-64644 | GHSA-q8wf-6r8g-63ch | Moderate | Image Optimization crash via malicious SVG |
| CVE-2026-64648 | GHSA-68g3-v927-f742 | Moderate | Cache confusion |
| CVE-2026-64647 | GHSA-4633-3j49-mh5q | Moderate | Cache confusion |



![severity split across the nine advisories — weighted toward high-impact issues](https://cdn.otf-kit.dev/blog/nextjs-security-patches/inline-1.png)



The four high-severity entries are what justify the rush: the two SSRFs coerce the Next.js server into hitting arbitrary hosts (including internal ones), the middleware bypass can skip authorization entirely on a specific config combo, and the DoS path is one malformed request away from memory pressure.

## How bad does each class actually get?

SSRF in this context doesn't mean "someone reads your `/etc/passwd`." It means your Next.js server, acting on your behalf, can be tricked into issuing a request to an arbitrary hostname — including internal-only services with no public address. In the rewrites case, the destination hostname is built from attacker-controlled request data, so a crafted path or query string steers the outbound request. In the Server Actions case on custom Node servers, the same trick works against the outbound request an action performs. Both end up in post-mortems under "data exfiltration from internal service."

The middleware bypass — CVE-2026-64642 — is narrower but nastier: it requires Turbopack, a legacy `middleware.ts`, *and* single-locale i18n configured together. If that triple applies to your app, an attacker can skip authorization entirely. The DoS via Server Actions takes a single malformed request and turns it into memory pressure. The Image Optimization SVG path lets an attacker crash an endpoint by uploading hostile markup — lesser impact in isolation, but a great staging ground for a noisy attack.

The two cache confusion bugs round out the batch as a reminder: caching is security, not just performance. Their real teeth show up when you share cached responses across users.

## How do you patch this today?

The work is straightforward. The discipline is doing it everywhere and not regressing.

```bash
# 15.x line
npm install next@15.5.21

# 16.x line
npm install next@16.2.11

# yarn
yarn add next@15.5.21
# or
yarn add next@16.2.11

# pnpm
pnpm update next@15.5.21
# or
pnpm update next@16.2.11
```

Then check what pulls in Next transitively and lock the floor. A `pnpm why next` or `yarn why next` will surface it; anywhere you still see `12.x` through `15.5.20` or `16.0.0` through `16.2.10`, that's still exposed. Vercel-hosted deployments get the new resolver automatically, but a self-hosted environment is on its own — a CI image rebuilt against the old floor is a quiet way to stay vulnerable after you thought you were safe.

## Where do SSRFs sneak in, and how do you keep them out?

You can defend against the *next* SSRF before you upgrade, by refusing to build destination hostnames from user input. The rewrites/redirects SSRF happens when a rule like this exists:

```js
// next.config.js — unsafe
async rewrites() {
  return [
    {
      source: '/proxy/:path*',
      destination: `
    },
  ]
}
```

The hostname in `destination` is reachable from a request header — the attacker controls the upstream you talk to. Replace it with a literal, allowlisted host:

```js
// next.config.js — safe
async rewrites() {
  return [
    {
      source: '/proxy/:path*',
      destination: ' // literal, no interpolation
    },
  ]
}
```

The Server Actions variant on custom Node servers is the same shape: any outbound `fetch` inside an action should target a hardcoded or strictly allowlisted URL — never one derived from `headers()`, the request body, or `searchParams`. Treat "destination = f(user input)" as a code-review smell across rewrites, redirects, Server Actions, and middleware proxies.

## Which framework settings shrink the next batch's blast radius?

Patching closes today's holes. The build settings below shrink the blast radius whenever the next batch ships — and Vercel has committed to a monthly security release cadence, so there will be more.

```js
// next.config.js — security posture
module.exports = {
  // 1. Refuse SVG unless you render them yourself
  images: {
    dangerouslyAllowSVG: false,
    contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
  },

  // 2. Headers Vercel can't infer from context
  async headers() {
    return [
      {
        source: '/(.*)',
        headers: [
          { key: 'X-Content-Type-Options', value: 'nosniff' },
          { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
          { key: 'Strict-Transport-Security',
            value: 'max-age=63072000; includeSubDomains; preload' },
          { key: 'Content-Security-Policy', value: "default-src 'self'" },
        ],
      },
    ]
  },

  // 3. Rewrites stay static — never built from headers/cookies/params
}
```

A few habits to layer on top:

- **Middleware** is your authorization layer. Review `middleware.ts` against CVE-2026-64642's bypass triple — Turbopack + legacy middleware + single-locale i18n — and confirm none of them apply together in production.
- **Server Actions** should validate payload size. CVE-2026-64646 is memory exhaustion in the Edge runtime; a hard cap on request body size is a cheap mitigation that survives the next regression.
- **Image Optimization** should reject SVGs by default (see `dangerouslyAllowSVG: false` above). The framework already gives you the toggle — turn it on unless you have a deliberate, sanitized SVG pipeline.

## What does this say about Next.js security going forward?

Vercel announced a monthly security release program alongside this batch. That changes your upgrade rhythm. "When the next CVE drops" stops being a question of *if* and becomes a calendar event. The pragmatic move is to wire a recurring dependency audit into CI:

```yaml
# .github/workflows/security.yml (sketch)
- name: Audit dependencies
  run: |
    pnpm audit --prod
    pnpm outdated next
```

Treat an outdated `next` past the published security floor as a failing check. Monthly advisories land best when monthly upgrade work is already budgeted — not crammed into the sprint after the disclosure.

## And what doesn't change when the framework does?

Every coordinated patch like this is a reminder that the framework layer underneath an app is the noisiest part — new versions, monthly advisories, deprecations, Turbopack switches. Worth its own audit ritual, yes. But the surface your users actually touch — the buttons, lists, forms, sheets — shouldn't churn with it. A `<Button>` that renders the same on iOS, Android, and the web, regardless of whether Next.js shipped an SSRF fix or a major version bump, is the durable layer. Ship the patches; keep the UI consistent.

If your contribution graph is a long queue of "bump Next.js, retest the navigation, retest the sheets, retest the forms" — that's the piece worth decoupling. The security work and the framework churn stay where they belong. The cross-platform UI doesn't have to follow.