
また別の(ちょっと前の)Next.jsのミドルウェアバイパスの脆弱性 CVE-2024-51479
アプリケーションセキュリティ課(現:高度診断課)の山崎です。
先日Next.jsのミドルウェアがバイパスできてしまう脆弱性CVE-2025-29927が公表され、話題となっています。
Next.js and the corrupt middleware: the authorizing artifact
これは x-middleware-subrequest
というHTTPヘッダに細工した値を入れるとミドルウェアがスキップされてしまうという脆弱性で、こんな穴があるのかと驚いた方も多いと思います。
昨年末、この脆弱性とはまた別に、CVE-2024-51479というNext.jsのミドルウェアにおける認証バイパスが公表されました。
これは私が2年前に報告した特定のパスを保護するミドルウェアをバイパスできるという脆弱性なのですが、影響等がCVE-2025-29927と類似する点も多く、 x-middleware-subrequest
以外にもNext.jsで問題のあるパラメータがあったことを紹介しようと思います。
特定のパスを保護するミドルウェア
Next.jsで特定のパスを保護するためにミドルウェアを用いることは珍しいことではありません。Next.jsの認証ライブラリとして広く利用されているAuth.js(NextAuth.js)のサンプルコードにも /admin
のパスには管理者のみがアクセスできるようにするコードが存在しました。
Next.jsのミドルウェアには特定のパスにのみミドルウェアを適用する config.matcher
という設定項目があるので、これによって特定のパスを保護しているコードも数多くあるでしょう。
https://nextjs.org/docs/app/building-your-application/routing/middleware#example
また、今のNext.jsではミドルウェアを1つしか持てないため、パスによってロジックを分ける手法が公式ドキュメントに記載されています。
https://nextjs.org/docs/messages/nested-middleware
__nextLocale によるミドルウェアバイパス - CVE-2024-51479
CVE-2025-29927は x-middleware-subrequest
ヘッダを悪用することでミドルウェアを回避することができるという問題でしたが、Next.js内部には他にもこのような独自のヘッダやクエリが多数存在します。
昨年の12月に公表された脆弱性CVE-2024-51479は __nextLocale
というURLクエリを付与することでこういったを回避できるというものです。
例えば次のように /admin
へのアクセスをブロックするミドルウェアがあったとします。(Next.jsのバージョンは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*' ],
}
しかし、/?__nextLocale=admin
というURLにアクセスすると、ミドルウェアが実行されず、クライアントには /admin
のページが返却されてしまいます。
ミドルウェアで扱われるパスが変化する
もう1つ例を見てみましょう。
これはNext.jsのバージョン13.3.4で config.matcher
を使わずに、 request.nextUrl.pathname
で /admin
へのアクセスをブロックするミドルウェアです。
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()
}
しかし、このミドルウェアも /?__nextLocale=admin
というクエリでアクセスするとブロックを回避できてしまいます。
サーバのログを見てみると、ミドルウェアでは request.nextUrl.pathname
が /admin/admin
となっているため、 /admin
へのアクセスとみなされない、という事象が起きています。
なにが起こっているのか
バージョン13.3.4のNext.jsを例に、この __nextLocale
を指定したときに何が起こるかを説明します。
(※Next.jsのバージョンや環境によって挙動が変わります。)
__nextLocale
クエリは本来 en
や jp
といった言語設定が保管される場所で、おそらくはNext.jsの内部のルーティング処理で利用するものだとは思うのですが、外部からこのクエリが指定可能になっていました。
__nextLocale=admin
クエリが設定されている状態でアクセスすると、Next.jsはロケールを一度解決してルーティング先のパスとして /admin
を探索します。
そして/admin
ページをレンダリングする前にミドルウェアを実行します。
Next.jsではミドルウェアの実行前にURLを正規化するのですが、この正規化で再びロケールの解決が行われます。
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}` : ''
}`
}
この正規化によりミドルウェアでは /admin
ではなく /admin/admin
というURLにユーザがアクセスしてきたように見えてしまいます。
/admin/admin
は保護対象ではないので、攻撃者はそのままミドルウェアによる検証を回避して /admin
ページへアクセスできてしまいます。
バージョンによって挙動は異なる
また、これはNext.jsのバージョンや環境によって細かく挙動が変わります。
例えばNext.jsのバージョン14.2.14でApp Routerで実装したアプリに対し、 /?__nextLocale=admin
というURLでアクセスすると、ミドルウェアの扱うrequest.nextUrl.pathname
は /admin/
になります。
代わりに、 /admin?__nextLocale=foobar
というURLでアクセスすると、ミドルウェアには /foobar/admin
というパスが渡され、クライアントには /admin
のページが返却されます。
終わりに
ミドルウェアを直接無効化できるCVE-2025-29927と比べれば、CVE-2024-51479の影響するアプリは多くないかもしれませんが、URLパス request.nextUrl.pathname
や matcher
configによって認証認可やセキュリティ保護を行う実装は少なくありません。
バージョンv14.2.14以前、またバージョンv13.5.7以前のNext.jsにはこのような __nextLocale
クエリによるバイパスの問題があるため、アップデートいただくことを推奨します。
また、Next.jsチームが初期に公表したCVEでは、「ルートディレクトリ直下のページの認証にのみ影響がある」という説明になっていましたが、実際にはそのような制限なく、サブディレクトリ以下のページにも影響があります。
タイムライン
- 2023/04/10 脆弱性をhuntr.dev経由で報告
- 2023/05/08 Vercelチームに直接報告し、トリアージされる
- 2024/10/02 Next.js本体のトリアージに時間がかかっているため、Vercelチームと相談し、NextAuth.jsチームにも状況を報告する
- 2024/10/04 修正パッチが当てられる
- 2024/12/17 脆弱性が公表される