Next.js Middleware Bypass CVE-2026-64642: Is Your App Vulnerable?

On July 20, 2026, Vercel shipped nine CVEs worth of Next.js patches. Eight of them are the usual mix of denial of service and cache confusion. One, CVE-2026-64642, does something worse: on a specific and entirely ordinary configuration, a crafted request reaches your routes without your middleware running at all.

If that middleware is where your if (!session) redirect('/login') lives, then for the duration of that request you do not have authentication. CVSS 8.3, CWE-285, improper authorization. Reported by the researcher KarimPwnz through Vercel's open source bug bounty.

TL;DR

Three conditions have to be true together: Next.js 16.0.0 through 16.2.10, a build using Turbopack, and exactly one entry in config.i18n.locales. If all three match your app, crafted requests skip middleware and any auth check inside it. Upgrade to 16.2.11. Then move the real authorization check into the route handler or server component that reads the data, because this is the second framework in eight days to ship a bug that silently turns route-level guards off.

Are You Affected? Three Checks

All three have to be true. Any one of them being false takes you out of scope for this CVE.

1

Check your Next.js version

npm ls next

Affected range is >= 16.0.0 < 16.2.11. If you see 16.0.x, 16.1.x, or 16.2.0 through 16.2.10, keep going. Next.js 15.x is not in range for this one.

2

Count your locales

grep -A6 "i18n" next.config.js next.config.mjs next.config.ts 2>/dev/null

You are looking for a locales array with exactly one entry. Something like locales: ['en']. A single-locale i18n config is a very common thing to have: people set it up intending to add languages later, or a starter template shipped with it. Two or more locales, or no i18n block at all, and this does not fire.

3

Check whether you build with Turbopack

grep -n "turbopack\|--turbo" package.json next.config.*

Webpack builds are not in scope. Turbopack became the default build path in Next 16, so if you have not gone out of your way to opt out, assume you are on it.

Three yeses means upgrade today, not this sprint. The advisory is public, the affected configuration is one someone can fingerprint from outside your app, and the exploit needs no authentication. There is no partial mitigation that keeps you on the vulnerable version safely.

The fix:

Patch the version
npm install next@16.2.11   # Active LTS
npm install next@15.5.21   # if you are on the 15.5 maintenance line

What Vercel Has and Has Not Said

The advisory states the effect precisely and the mechanism not at all: "Crafted requests targeting Next.js applications using App Router built with Turbopack and a single entry in config.i18n.locales can bypass middleware/proxy based authentication."

That is deliberate. Advisories published alongside a patch normally withhold the exact request shape so people have a window to upgrade before someone reverse-engineers it from the diff. Do not read the missing detail as the bug being theoretical. A reproducible bypass was accepted, triaged, and paid out through a bug bounty.

Do not try to work out the payload and test it against someone else's app. Test your own, against a staging deploy, before and after the upgrade. The useful test is the boring one: request a protected route with no session and see what comes back.

The Part That Outlives This CVE

Eight days after Vercel's release, Nuxt published an advisory of its own where route rules with a capital letter in the key stopped matching, so the middleware guarding those routes never ran.

Different frameworks. Different root causes. Identical failure shape: the routing layer decided your request did not need the guard, and nothing downstream disagreed.

That's the thing worth taking from this.

Middleware feels like a security boundary because it sits in front of everything and it's where the auth code goes. It isn't one. It's a routing feature that you have been using to carry a security decision, and it enforces that decision only for requests the router agrees are matched. When path matching breaks, and path matching is fiddly enough that it breaks regularly, your single checkpoint disappears without an error, without a log line, and without any change to your code.

One checkpoint is a single point of failure, and it's the one you never test. You test that logged-out users get redirected. You do not test what happens when the redirect layer itself doesn't run, because you have no way to simulate that until an advisory tells you it's possible.

Where the Second Check Goes

The advisory's own workaround is the permanent fix, not a stopgap: "enforce authorization in the page's server-side data path instead of relying solely on middleware."

Concretely, keep the middleware. It gives logged-out users a clean redirect instead of a blank error, and that's a real thing worth having. Then add the check that actually protects the data, in the code that reads the data:

app/dashboard/page.tsx
import { redirect } from 'next/navigation'
import { getSession } from '@/lib/session'
import { getInvoicesForUser } from '@/lib/db'

export default async function DashboardPage() {
  // This runs no matter what the router did with middleware.
  const session = await getSession()
  if (!session) redirect('/login')

  // Scope the query to the caller. Never fetch by an id from the URL alone.
  const invoices = await getInvoicesForUser(session.userId)
  return <InvoiceList invoices={invoices} />
}

Two properties make this hold up where middleware didn't. It runs inside the thing being protected, so there is no routing decision between the check and the data. And it scopes the query to the caller, which means even a request that somehow arrives authenticated as someone else gets that person's rows and not yours.

Route handlers need the same treatment. app/api/**/route.ts files are their own entry points. If your only auth for /api/admin/users is a middleware matcher, that endpoint has exactly the same exposure as the page, and it returns JSON rather than HTML, which is friendlier to whoever finds it.

The pattern generalizes past Next.js. Whatever your framework calls its route guard, treat it as the convenience layer and put the enforcing check next to the data. That's the double checkpoint from our route protection guide, and it's the reason a routing bug should cost you a nicer redirect rather than your customer table.

How to Confirm You Actually Fixed It

Upgrading changes a number in package-lock.json. It doesn't tell you whether your protected routes are protected, and plenty of apps have a second, unrelated hole that this exercise will surface.

After you deploy the patch, hit your own protected routes from outside, with no cookies:

The unauthenticated smoke test
# Should be 401, 403, or a 30x to /login. A 200 with real content is a finding.
curl -s -o /dev/null -w "%{http_code} %{url_effective}\n" -L \
  https://yourapp.com/dashboard \
  https://yourapp.com/admin \
  https://yourapp.com/api/admin/users

Watch for a 200 that returns a login page shell while the real data arrives client-side afterwards. That reads as protected in a browser and is wide open to anything that reads the network response, which is the pattern behind the Lovable app that exposed 18,000 users.

A scanner does this systematically across every route it can discover rather than the three you thought to type. That's the part people miss when they check by hand: you test the routes you remember building.

Is my Next.js app vulnerable to CVE-2026-64642?

Only if all three conditions are true at once: you are on Next.js 16.0.0 through 16.2.10, you build with Turbopack, and your config has exactly one entry in i18n.locales. Miss any one of those and this specific CVE does not apply to you. Next.js 15.x is outside the affected range for this issue, though the same July release patched other CVEs that do affect it.

What version of Next.js fixes the middleware bypass?

16.2.11, released July 20, 2026. Run npm install next@16.2.11. The fix is also in the 16.3 canary and preview builds and shipped in 16.3.0 stable. If you are on the 15.5 maintenance line, 15.5.21 carries the rest of that release's fixes.

Why does having only one locale trigger the bug?

Vercel has not published the crafted-request shape, which is standard practice for a recent advisory. What the advisory does state is the effect: with App Router, a Turbopack build, and a single entry in config.i18n.locales, a crafted request reaches the route without middleware running, so any auth check in that middleware is skipped.

How do I check if my app is exposed right now?

Run npm ls next to get your exact version, grep your next.config for i18n.locales and count the entries, and check whether your build script passes --turbopack. If all three line up, upgrade. Then request a protected route with no session cookie and confirm you get a 401 or a redirect rather than the page.

Should I stop using Next.js middleware for authentication?

Not stop, but stop relying on it alone. Middleware is a routing feature, so any bug in path matching turns your only auth check off silently. Keep the middleware for the redirect experience and also check the session in the server component or route handler that reads the data. Two independent checkpoints means a routing bug costs you a redirect, not your data.

Is anything answering that shouldn't be?

Upgrading fixes the CVE. It doesn't tell you which of your routes were never guarded in the first place. A free scan requests every route it can find with no session and reports the ones that answer.

Vulnerability Guides

Next.js Middleware Bypass CVE-2026-64642: Is Your App Vulnerable?