The Great Next.js Middleware Heist of 2025: How a Single HTTP Header Can Bypass Your Auth
“It’s not about complex exploits or fancy zero-days. Sometimes it’s just about knowing which door was left unlocked.”
TL;DR (Because I Know You’re Going to Skip Anyway)
- A critical vulnerability (CVE-2025–29927) in Next.js lets attackers completely bypass your middleware auth with a single HTTP header
- Affected versions: 11.1.4 through 13.5.6, 14.x before 14.2.25, and 15.x before 15.2.3
- Next.js apps on Vercel are automatically safe (thanks Vercel! 🙏)
- Everyone else: upgrade to 14.2.25/15.2.3+ ASAP or block the evil header
The Epic Facepalm Moment
Picture this: You’ve spent weeks meticulously crafting your Next.js app’s authentication system. Your middleware is a fortress — checking session tokens, validating permissions, redirecting unauthorized users. You sleep soundly at night knowing your /admin
dashboard is secure.
Meanwhile, an attacker is sitting in their pajamas, adding a single HTTP header to their request and waltz right past all your security like they own the place:
GET /admin
Host: your-awesome-app.com
X-Middleware-Subrequest: middleware
That’s it. That’s the entire hack. One header and your fortress crumbles.
How Is This Even Possible?!
The vulnerability hinges on a seemingly innocent internal mechanism in Next.js. The framework uses the x-middleware-subrequest
header to prevent infinite middleware loops. When Next.js sees this special header, it basically says, "Oh, you've already been through middleware? Cool, I'll just let you through!"
The problem? Next.js never checks if the request actually came from middleware or if some sneaky user just added the header themselves.
It’s like having a super-secure door with retinal scanners, but then putting up a sign that says, “If you say the secret phrase ‘I’ve already been checked,’ the guard will let you right in.”
Code Time: What’s Actually Happening
In the heart of Next.js, there’s some code that looks roughly like this:
// Simplified version of what's happening inside Next.js
const subreq = request.headers["x-middleware-subrequest"];
const subrequests = typeof subreq === "string" ? subreq.split(":") : [];
if (subrequests.includes(middlewareInfo.name)) {
// "Oh, you've been through middleware already? Come right in!"
return NextResponse.next();
}
For different Next.js versions, the magic value varies slightly:
- For versions before 12.2:
x-middleware-subrequest: pages/_middleware
- For versions 12.2 and later:
x-middleware-subrequest: middleware
- For projects with a /src structure:
x-middleware-subrequest: src/middleware
- For newer versions with recursion depth:
x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware
Fix It Now: Your Action Plan
Option 1: The “I Have My Life Together” Solution
Update your Next.js version:
- For Next.js 15.x: update to version 15.2.3 or later
- For Next.js 14.x: update to version 14.2.25 or later
# For npm
npm install next@15.2.3 react@latest react-dom@latest
# For yarn
yarn add next@15.2.3 react@latest react-dom@latest# For pnpm
pnpm add next@15.2.3 react@latest react-dom@latest
Option 2: The “I Can’t Update Right Now” Solution
Block the evil header at different levels:
Using Nginx:
# In your nginx.conf
proxy_set_header x-middleware-subrequest "";
Using Apache:
# In your .htaccess or Apache config
RequestHeader unset x-middleware-subrequest
Using Express (with custom server):
// In your custom server.js
app.use((req, res, next) => {
delete req.headers['x-middleware-subrequest'];
next();
});
Using AWS Load Balancer:
Set up a rule to strip or block requests with the x-middleware-subrequest
header.
The “Am I Actually Vulnerable?” Test
- Do you use Next.js middleware for auth, redirects, or security headers?
- Is your Next.js version between 11.1.4 and 15.2.2?
- Are you self-hosting (not on Vercel)?
If you answered yes to all three, congratulations! You’re vulnerable. Fix it now.
Final Thoughts
This vulnerability is a reminder that even the most sophisticated security systems can be undermined by seemingly small oversights. It’s not about the ninety-nine doors you locked; it’s about the one you left open.
So update those dependencies, block those headers, and maybe pour yourself a strong coffee (or something stronger) while contemplating the fragility of web security.
Stay safe out there, fellow developers!
Disclaimer: I’m just a developer trying to help other developers. Always refer to official security advisories and documentation for the most accurate information.