セキュリティブログ

また別の(ちょっと前の)Next.jsのミドルウェアバイパスの脆弱性 CVE-2024-51479

また別の(ちょっと前の)Next.jsのミドルウェアバイパスの脆弱性 CVE-2024-51479

更新日:2025.03.27

English Version

アプリケーションセキュリティ課(現:高度診断課)の山崎です。

先日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 のパスには管理者のみがアクセスできるようにするコードが存在しました。

https://github.com/nextauthjs/next-auth-example/blob/e8b0310f9c2f428c74e574b5b7375db8164b2f3a/middleware.ts

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 クエリは本来 enjp といった言語設定が保管される場所で、おそらくはNext.jsの内部のルーティング処理で利用するものだとは思うのですが、外部からこのクエリが指定可能になっていました。

__nextLocale=admin クエリが設定されている状態でアクセスすると、Next.jsはロケールを一度解決してルーティング先のパスとして /admin を探索します。

そして/admin ページをレンダリングする前にミドルウェアを実行します。

Next.jsではミドルウェアの実行前にURLを正規化するのですが、この正規化で再びロケールの解決が行われます。

https://github.com/vercel/next.js/blob/48323c9dfefc08eaf84d4ee077d345fe38a2dda8/packages/next/src/server/next-server.ts#L2119

    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.pathnamematcher 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 脆弱性が公表される
シェア
X FaceBook
セキュリティ診断のことなら
お気軽にご相談ください
セキュリティ診断で発見された脆弱性と、具体的な内容・再現方法・リスク・対策方法を報告したレポートのサンプルをご覧いただけます。

関連記事

経験豊富なエンジニアが
セキュリティの不安を解消します

Webサービスやアプリにおけるセキュリティ上の問題点を解消し、
収益の最大化を実現する相談役としてぜひお気軽にご連絡ください。

疑問点やお見積もり依頼はこちらから

お見積もり・お問い合わせ

セキュリティ診断サービスについてのご紹介

資料ダウンロード