
Another (A Bit Earlier) Next.js Middleware Bypass Vulnerability: CVE-2024-51479
I'm Yamazaki, a Security Engineer at GMO Cybersecurity by Ierae, Inc.
Recently, a vulnerability that bypasses Next.js middleware has been disclosed as CVE-2025-29927, and it has been the topic of much discussion.
Next.js and the corrupt middleware: the authorizing artifact
This vulnerability allows middleware to be skipped by manipulating the value of the x-middleware-subrequest
HTTP header, which surprised many people.
At the end of last year, apart from this vulnerability, another authentication bypass vulnerability in Next.js middleware, CVE-2024-51479, was disclosed.
This is the vulnerability I reported two years ago, where middleware protecting certain paths can be bypassed.
Its impact is similar to that of CVE-2025-29927, and I would like to highlight that there was another problematic parameter in Next.js besides x-middleware-subrequest
.
Middleware Protecting Specific Paths
It is not uncommon to use middleware in Next.js to protect specific paths. In fact, in the sample code from Auth.js (NextAuth.js), a widely used Next.js authentication library, there is code that restricts access to the /admin
path to administrators only.
Also, Next.js middleware provides a configuration called config.matcher
that applies middleware only to certain paths, so there are many implementations protecting specific paths with this setting.
https://nextjs.org/docs/app/building-your-application/routing/middleware#example
Since only one middleware is allowed in current versions of Next.js, the official documentation suggests using conditional logic within the middleware function to differentiate based on path.
https://nextjs.org/docs/messages/nested-middleware
Middleware Bypass via __nextLocale - CVE-2024-51479
While CVE-2025-29927 involves bypassing the middleware by exploiting the x-middleware-subrequest
header, Next.js internally contains many other proprietary headers and queries.
The vulnerability CVE-2024-51479, disclosed last December, allows bypassing by appending a URL query called __nextLocale
.
For example, consider middleware designed to block access to /admin
(using Next.js version 14.2.14):
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
// Block access to /admin and /admin/*
return NextResponse.redirect('<http://example.com>')
}
export const config = {
matcher: [ '/admin', '/admin/:path*' ],
}
However, if you access the URL /?__nextLocale=admin
, the middleware is bypassed, and the /admin
page is returned to the client.
Request Path Tampering
Let’s look at another example.
This example middleware (in Next.js version 13.3.4), which does not use config.matcher
, blocks access to /admin
by checking request.nextUrl.pathname
:
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
console.log('Middleware:', request.nextUrl.pathname)
// Block access to /admin
if (request.nextUrl.pathname === '/admin') {
return NextResponse.redirect('http://example.com')
}
return NextResponse.next()
}
However, this middleware can also be bypassed if the URL contains the query /?__nextLocale=admin
.
According to the server log, inside the middleware request.nextUrl.pathname
becomes /admin/admin
, and so it is not recognized as an access to /admin
.
What is Happening
Using Next.js version 13.3.4 as an example, let me explain what occurs when __nextLocale
is specified.
(Note: Behavior may vary depending on the Next.js version and environment.)
The __nextLocale
query originally stores language settings like en
or jp
and is probably intended for use within Next.js internal routing. However, it was possible to specify this query from the HTTP request.
When accessing with the query __nextLocale=admin
, Next.js first resolves the locale and searches for the /admin
path as the target route.
Then, before rendering the /admin
page, the middleware is executed.
Before executing the middleware, Next.js normalizes the URL, and during this normalization, the locale is resolved again.
if (this.nextConfig.skipMiddlewareUrlNormalize) {
url = getRequestMeta(params.request, '__NEXT_INIT_URL')!
} else {
// For middleware to "fetch" we must always provide an absolute URL
const query = urlQueryToSearchParams(params.parsed.query).toString()
const locale = params.parsed.query.__nextLocale
url = `${getRequestMeta(params.request, '_protocol')}://${
this.hostname
}:${this.port}${locale ? `/${locale}` : ''}${params.parsed.pathname}${
query ? `?${query}` : ''
}`
}
Due to this normalization, the middleware sees the URL as /admin/admin
instead of /admin
.
Since /admin/admin
is not protected, an attacker can bypass the middleware checks and access the /admin
page.
Behavior Varies by Version
Moreover, the behavior changes depending on the Next.js version and the environment.
For example, when accessing /?__nextLocale=admin
to an app implemented with the App Router and Next.js version 14.2.14, the request.nextUrl.pathname
used by the middleware becomes /admin/
.
On the other hand, if you call /admin?__nextLocale=foobar
, the middleware will get the path /foobar/admin
, and the client will get the /admin
page.
Conclusion
Although CVE-2024-51479 may affect fewer applications than CVE-2025-29927, which can completely bypass middleware, many implementations still rely on URL paths (request.nextUrl.pathname
) or matcher
configurations for authentication, authorization and security protection.
Since Next.js versions up to v14.2.14 and v13.5.7 are affected by the bypass issue using the __nextLocale
query, it is recommended to upgrade.
Moreover, while the initial CVE stated that “it was possible for this authorization to be bypassed for pages directly under the application's root directory”, in practice, all pages are affected without such restrictions.
Timeline
- 2023/04/10: Reported vulnerability via huntr.dev
- 2023/05/08: Reported vulnerability directly to the Vercel team and triaged
- 2024/10/02: After discussed with the Vercel team, I also reported this issue to the NextAuth.js team
- 2024/10/04: A patch was applied
- 2024/12/17: Vulnerability disclosed