← All posts
· 4 min read ·
SecurityNext.jsCVEWeb SecurityAuthentication

CVE-2025-29927: The Next.js Middleware Auth Bypass That Should Worry You

A critical vulnerability in Next.js allowed attackers to bypass middleware-based authentication entirely using a single request header. Here's what happened, who was affected, and how to fix it.

Abstract representation of a broken authentication gate

In late March 2025, Vercel disclosed CVE-2025-29927 - a critical authentication bypass in Next.js middleware affecting versions 11.1.4 through 15.2.2. A year on, applications running unpatched versions are still being actively scanned. If you use Next.js middleware to gate any route, you need to understand this one.

What the Vulnerability Does

Next.js middleware runs before a request reaches your page or API route. The common pattern is to check a session cookie or JWT in middleware and redirect unauthenticated users to /login. This is clean, centralised auth enforcement - or so it appeared.

The vulnerability: an attacker can set the x-middleware-subrequest header to a crafted value that causes Next.js to skip middleware execution entirely. The request passes straight to the underlying route handler as if no middleware existed.

GET /admin/dashboard HTTP/1.1
Host: example.com
x-middleware-subrequest: middleware

That single header bypasses your entire middleware chain. No session required. No token required.

Why Middleware-Level Auth Is Risky

The deeper issue this CVE exposed is architectural: middleware is a convenience layer, not a security boundary. The Next.js runtime has always documented that middleware runs on the edge, before authentication can be fully verified against a database or trusted token issuer. Treating it as your primary auth gate was never officially recommended - but the pattern was everywhere.

The correct model is defence in depth:

  1. Middleware: fast, edge-level redirect for unauthenticated users (UX, not security)
  2. Route handler / server component: authoritative auth check against session store or JWT
  3. Database/API layer: permission checks before data access

CVE-2025-29927 collapses tier 1. Applications that only had tier 1 were fully exposed.

Affected Versions

BranchAffected rangeFixed version
15.x15.0.0 – 15.2.215.2.3
14.x14.0.0 – 14.2.2514.2.26
13.x13.0.0 – 13.5.813.5.9
12.x12.0.0 – 12.3.412.3.5
11.x11.1.4 – 11.1.xNo patch - upgrade required

If you’re on version 11 and cannot upgrade, the only mitigation is to strip the x-middleware-subrequest header at your reverse proxy or CDN before it reaches the Next.js server.

Immediate Mitigation: Strip the Header at the Edge

Nginx:

location / {
    proxy_set_header x-middleware-subrequest "";
    proxy_pass http://nextjs_upstream;
}

CloudFront Function (cloudfront-js-2.0):

function handler(event) {
    var req = event.request;
    delete req.headers["x-middleware-subrequest"];
    return req;
}

Vercel: Vercel-hosted applications were patched automatically at the platform level before public disclosure. Self-hosted deployments are your responsibility.

Fixing It Properly: Auth in the Route Handler

Strip the header as a short-term control, but the correct fix is moving your authoritative auth check out of middleware.

Before (vulnerable pattern):

// middleware.ts  -  this is now bypassable
export function middleware(request: NextRequest) {
    const session = request.cookies.get("session");
    if (!session) {
        return NextResponse.redirect(new URL("/login", request.url));
    }
}

export const config = {
    matcher: ["/admin/:path*"],
};

After (defence in depth):

// middleware.ts  -  redirect for UX, not auth
export function middleware(request: NextRequest) {
    const session = request.cookies.get("session");
    if (!session) {
        return NextResponse.redirect(new URL("/login", request.url));
    }
}

// app/admin/layout.tsx  -  authoritative check
import { getServerSession } from "next-auth";
import { redirect } from "next/navigation";

export default async function AdminLayout({ children }) {
    const session = await getServerSession();
    if (!session) {
        redirect("/login");
    }
    return <>{children}</>;
}

The server component check cannot be bypassed by a header - it runs in a Node.js process with full access to your session store.

Checking Your Exposure

Scan your middleware files for auth-only patterns:

# Find middleware files
find . -name "middleware.ts" -o -name "middleware.js" | grep -v node_modules

# Check if they do any auth redirect with no route-level fallback
grep -n "redirect\|return NextResponse" src/middleware.ts

Then check each protected route/layout for a server-side auth check. If there isn’t one, that route was exposed.

What to Do Now

  1. Upgrade Next.js to the patched version for your branch - this is the only real fix.
  2. Strip x-middleware-subrequest at your proxy as a defence-in-depth measure regardless of version.
  3. Audit middleware-only auth gates and add server component or API route checks.
  4. Check your Dependabot / Renovate config - next should be in your auto-merge patch rules.

This vulnerability had a CVSS score of 9.1. If you are running Next.js in production and haven’t patched, do it before anything else today.

← All posts