CVE-2025-29927は、Next.jsのミドルウェアで行っている認可チェックを、外部からのリクエストだけで飛ばせてしまう脆弱性です。2025年3月21日に公開され、CVSS v3.1のスコアは9.1(Critical)でした。影響するのは、ミドルウェアでログイン確認や権限判定をしていて、しかもnext startなどで自前のサーバーに載せているアプリです。Vercel上のアプリは対象外でした。この記事では、影響する版と修正版、セルフホストだけが対象になる理由、パッチを当てられないときの回避策、ログでの検知方法を、GitHubのセキュリティアドバイザリとVercelの事後報告にもとづいて整理します。PoC(概念実証コード)を探している方には、PoCを動かさなくても影響の有無を判定できる手順を示します。
まとめ:CVE-2025-29927の影響と対応の結論
- 何が起きるか:ミドルウェアが丸ごと実行されずに、リクエストが保護したいページやAPIへ届く。認証Cookieの確認をミドルウェアだけに置いていると、未ログインでも管理画面が開く。
- 影響する版:Next.js 11.1.4以降の11.x、12.3.5未満の12.x、13.5.9未満の13.x、14.2.25未満の14.x、15.2.3未満の15.x。修正版は15.2.3・14.2.25・13.5.9・12.3.5で、11.x向けの修正版は出ていない。
- 影響するデプロイ:
next startとoutput: 'standalone'のセルフホスト。Vercel・Netlify・Cloudflare Workers・静的エクスポートは対象外。 - 今やること:サポート対象系列の最新版へ更新する。2026年10月2日時点では16.3.8(Active LTS)か15.5.27(Maintenance LTS、2026年10月21日で期限切れ)。15.2.3は、2025年12月公表のRCE(React2Shell)と2026年8月公表の未認証RCE 2件の影響範囲にも入っている。
- 上げられないとき:リバースプロキシで外部からの
x-middleware-subrequestヘッダーを落とす。これが公式の回避策。 - 設計の見直し:Next.js公式は、ミドルウェア(16系ではProxy)を認可の唯一の防御線にしないよう明記している。データを返す側でもセッションを検証する。
CVE-2025-29927の基本情報:CVSS 9.1の認可バイパス
GitHub Security Advisory(GHSA-f82v-jwr5-mffw)の記載をまとめると次のとおりです。
| 項目 | 内容 |
|---|---|
| アドバイザリID | GHSA-f82v-jwr5-mffw |
| 公開日 | 2025年3月21日 |
| CVSS v3.1 | 9.1(Critical) |
| ベクトル | 詳細は表の直後に記載 |
| CWE | CWE-285・CWE-863 |
| 発見者 | zhero・inzo_ |
| CISA KEV | 未収録(2026年10月1日版で確認) |
CVSSベクトルはAV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:Nです。CWEの分類はCWE-285(不適切な認可)とCWE-863(誤った認可)で、発見者はAllam Rachid(zhero)とAllam Yasser(inzo_)です。
ベクトルの読み方がそのまま被害像になります。ネットワーク越し(AV:N)に、認証なし(PR:N)・利用者の操作なし(UI:N)で成立し、機密性と完全性への影響が高い(C:H/I:H)。CVSS上の可用性はA:Nですが、発見者の解説は、構成によってはキャッシュ汚染でサービス妨害(DoS)につながる例も挙げています。「リモートコード実行につながる」という説明も見かけますが、アドバイザリの分類は認可の不備で、この脆弱性単体で任意のコードが実行されるわけではありません。CVSSやCWEの読み方そのものはCVE(共通脆弱性識別子)の仕組みとCVSS・CWEの違いで解説しています。
影響を受けるNext.jsの版と修正版:系列別の影響範囲と更新先
アドバイザリが挙げる影響範囲と修正版です。あわせて、同じ調査の過程で見つかった後続のCVE-2025-30218の修正版も並べます。
| 系列 | 影響する版 | CVE-2025-29927の修正版 | CVE-2025-30218の修正版 |
|---|---|---|---|
| 15.x | 15.0.0〜15.2.2 | 15.2.3 | 15.2.4 |
| 14.x | 14.0.0〜14.2.24 | 14.2.25 | 14.2.26 |
| 13.x | 13.0.0〜13.5.8 | 13.5.9 | 13.5.10 |
| 12.x | 12.0.0〜12.3.4 | 12.3.5 | 12.3.6 |
| 11.x | 11.1.4以降 | なし(12.3.5以降へ移行) | なし |
CVE-2025-30218(GHSA-223j-4rm8-mrmf・深刻度low)は、修正で導入された内部ヘッダーx-middleware-subrequest-idが、ミドルウェアから外部ホストへ送るリクエストに漏れうる問題です。GMO Flatt SecurityのRyotaK氏ら2組の報告と並行してVercelが確認しました。15.2.3まで上げた環境は、少なくとも15.2.4へ進める必要があります。
自分のプロジェクトに入っているNext.jsの版を確認するコマンド
package.jsonの"next": "^15.1.0"のような記述は範囲指定なので、実際に入っている版はロックファイルかインストール済みのパッケージで確かめます。
# 実際にインストールされている版(依存ツリー上の next をすべて表示)
npm ls next
# Next.js CLIが表示する版
npx next --version
# モノレポや複数アプリの場合はロックファイルを直接確認
grep -A2 'node_modules/next"' package-lock.json
社内に複数のNext.jsアプリがある場合は、1本ずつ確認するよりOSV-Scannerのような依存関係スキャナでロックファイルをまとめて照合する方が漏れません。GHSA-f82v-jwr5-mffwはOSVのデータベースにも入っています。
影響を受けるデプロイ形態:セルフホストだけが対象になった理由
版が影響範囲に入っていても、どこで動かしているかで結論が変わります。Vercelの事後報告は、デプロイ形態ごとに次のように判定しています。
| デプロイ形態 | 影響 | 理由(事後報告の記載) |
|---|---|---|
| next start(Node.jsサーバー) | あり | セルフホストで影響を確認 |
| output: ‘standalone’ | あり | 同上 |
| Vercel | なし | ルーティングが別システムで動く |
| Netlifyほか(下記参照) | なし | アダプター側でルーティングが分離 |
| 静的出力(output: ‘export’) | なし | サーバー実行環境が無くミドルウェアが動かない |
表のstandaloneはDocker等で動かす構成、NetlifyほかはNetlify・Cloudflare Workersを指します。静的出力は、設定値をoutput: 'export'とする静的エクスポートのことです。
Vercelが対象外だったのは、事後報告の言葉を借りると「偶然」です。VercelではNext.jsのルーティング処理がアプリ本体とは切り離された別システムで動いており、問題のヘッダーを解釈する経路を通りませんでした。逆に言えば、AWSのECSやEC2、Google Cloud Run、社内のKubernetesなどでDockerイメージを動かしている構成は、ほぼすべてがnext startかstandaloneのどちらかに当たります。「クラウドに載せているから大丈夫」とは判断できません。VercelやNetlifyを含むホスティング全体の攻撃面はVercelハッキングの手口と対策で扱っています。
脆弱性の仕組み:外部からの内部用ヘッダーの受け入れと認可処理の省略
Next.jsは、ミドルウェアの中から自分自身へリクエストを送ったときに処理が無限に繰り返されないよう、内部用のx-middleware-subrequestヘッダーでミドルウェアの実行回数を数えていました。このヘッダーが一定の条件を満たすと、ミドルウェアを実行せずにリクエストを先へ通す作りです。問題は、このヘッダーが本来フレームワーク内部でしか付かないにもかかわらず、外部のクライアントが付けて送っても同じように解釈されたことでした。
その結果、ミドルウェアで「セッションCookieが無ければ/loginへリダイレクト」としているアプリでは、ミドルウェアそのものが飛ばされ、保護したいページの描画やRoute Handlerの処理まで到達します。ミドルウェアでセキュリティヘッダー(Content-Security-Policy等)を付けている場合は、そのヘッダーも付かなくなります。
修正内容:プロセスごとのランダムIDによる内部リクエストの識別
修正コミット(52a078da)は、サーバー起動時にcrypto.getRandomValuesで8バイトの乱数IDを作ってプロセス内に保持し、内部リクエストにだけx-middleware-subrequest-idとしてそのIDを付けます。受け取ったリクエストのIDが一致しなければ、x-middleware-subrequestを削除してから処理する仕組みです。外部の攻撃者はプロセス内の乱数を知り得ないので、ヘッダーを偽装してもミドルウェアは通常どおり実行されます。この新しいIDヘッダーが外部へ漏れうると分かって出たのが、前章のCVE-2025-30218です。
PoCを動かす前の判定:認可バイパスの影響を受けるアプリの3つの条件
公開直後から、GitHub上に検証用のPoCや、脆弱性スキャナ向けの検知テンプレートが多数公開されました。ただ、自社のアプリが危ないかどうかを知るだけなら、PoCを動かす必要はありません。次の3つは、認可バイパスによる情報漏えいや不正操作を優先確認する条件です。ただし、これに当てはまらなくても、CSPの欠落やキャッシュ構成に依存するサービス妨害などの影響を確認する必要があります。
- 版:前章の表の影響範囲に入っている(
npm ls nextで確認) - デプロイ:
next startかoutput: 'standalone'で動かしている - ミドルウェアの役割:
middleware.tsやmiddleware.js(12.2より前では_middleware.tsや_middleware.js)で認証・認可・アクセス制限をしていて、ページやAPIの側では同じ確認をしていない
1と2に当てはまる場合、認可以外の用途でも影響を確認してください。ロケール別の書き換えが省略されてエラー応答がキャッシュされる構成では、サービス妨害につながる可能性があります。3に当てはまるなら、PoCの結果を待たずに更新するべきです。PoCで動作を確かめたい場合も、対象は自社が管理権限を持つ検証環境に限ります。第三者のサイトへ送れば、たとえ確認目的でも不正アクセス禁止法に触れるおそれがあります。
内部用ヘッダーの悪用試行を検知するためのログ記録と調査対象の判定
このヘッダーは正規のブラウザからは付きません。そのため、アプリの手前にあるリバースプロキシのアクセスログに記録しておけば、試行を見つけやすくなります。nginxならログ形式に次の変数を足します。
# nginx.conf(httpブロック)
log_format with_mw '$remote_addr [$time_local] "$request" $status '
'mw_sub="$http_x_middleware_subrequest"';
access_log /var/log/nginx/access_mw.log with_mw;
このログ形式では、ヘッダーが無い場合もmw_sub="-"と記録されます。空文字や「-」以外の値を調査候補とし、送信元や正規のサーバー間通信と照合してください。ヘッダーの存在だけでは攻撃とは断定できません。修正版へ上げたあとも、どれだけ狙われていたかを振り返る材料になります。ただし、ログに残るのはプロキシを通った通信だけです。プロキシを経由せずアプリのポートに直接届く経路が無いかも、あわせて確認してください。
パッチを当てられない場合の回避策:外部からの内部ヘッダーを落とす
アドバイザリの回避策は1つだけです。x-middleware-subrequestを含む外部からのリクエストを、Next.jsアプリに届く前に止めます。nginxでは、プロキシ先へ渡すヘッダーを空文字にすると、そのヘッダー自体が送られなくなります。
location / {
proxy_pass http://127.0.0.1:3000;
# 外部から付けられた内部用ヘッダーをNext.jsへ渡さない
proxy_set_header x-middleware-subrequest "";
}
Apache HTTP ServerならRequestHeader unset x-middleware-subrequestで同じことができます。いずれも、アプリへ直接届く経路が残っていれば意味がありません。
CDNやWAFで、このヘッダーを持つリクエストを遮断する方法もあります。Cloudflareは2025年3月22日にマネージドWAFルール(ルールID 34583778093748cc83ff7b38f472013e)を出しました。ただし、サードパーティの認証サービスと組み合わせたミドルウェアを使うサイトで正規のリクエストが失敗したため、同日中にオプトイン方式へ変更しています。現在はProプラン以上で手動で有効にし、FreeプランではカスタムWAFルール(len(http.request.headers["x-middleware-subrequest"]) > 0)で同じ条件を書きます。Logアクションを利用できるのはEnterpriseプランです。利用できる場合はLogで影響を確認してからBlockへ切り替え、利用できないプランでは検証環境やオリジン側のログで正規通信への影響を確認してから有効にしてください。
この回避策は、11.xのように修正版が出ていない系列にとっては唯一の手段です。ただし、回避策で止まるのはCVE-2025-29927だけです。サポート外の系列への修正提供は保証されません。Next.jsは深刻度に応じて例外的に修正する場合があるとしていますが、それを前提に運用を続けるべきではありません。回避策は更新までのつなぎと割り切り、次章の版の問題を先に片付けるべきです。
15.2.3で止めてはいけない理由:その後のNext.jsの脆弱性とサポート状況
CVE-2025-29927への対応として15.2.3や14.2.25へ上げたあとも、更新を止めてはいけません。2025年12月3日に公開されたアドバイザリGHSA-9qr9-h5gf-34mp(React Server Componentsの通信処理に起因するリモートコード実行・Critical)は、15.2系では15.2.6未満を影響範囲にしています。つまり15.2.3はCVE-2025-29927の修正版でも、App Routerを使う構成ではこのRCEの影響対象です。対応手順はReact2Shell(CVE-2025-55182)の対応手順にまとめています。
2026年に入ってからも、15.2.3を直撃する重大な脆弱性が続いています。Next.js公式の2026年8月25日の告知は、未認証のリモートコード実行2件を公表しました。1件はAVIF画像を変換するImage Optimization APIの問題で10.0.0〜15.5.23が、もう1件はWindows上で動くサーバーで成立するCVE-2026-75604で13.4.0〜15.5.23が対象です。修正は15.5.24と16.3.3で、15.2系や14系には出ていません。
サポートの面でも、修正版の版番号だけを見る対応は通用しなくなっています。Next.jsのサポートポリシー(2026年10月2日時点)は次のとおりです。
| 系列 | 状態 | 2026年9月時点の最新 |
|---|---|---|
| 16.x | Active LTS | 16.3.8(2026-09-30) |
| 15.x | Maintenance LTS(10-21まで) | 15.5.27(2026-09-30) |
| 14.x | サポート外 | 14.2.35(2025-12-11) |
| 13.x以前 | サポート外 | – |
Maintenance LTSはメジャー版の初回リリースから2年間なので、2024年10月21日に出た15.xは2026年10月21日で期限を迎えます。14.x以前にいるなら、CVE-2025-29927の修正版に上げるだけでは不十分で、16.xへの移行計画が必要です。最新版と更新手順はNext.js 16の最新バージョンとアップデート手順で確認できます。
2026年9月30日には定例のセキュリティリリースとして16.3.8と15.5.27が公開されました。公式の告知によると、修正したのは7件(High 1件・Medium 5件・Low 1件)で、画像の配信効率を高める処理のSSRFや、セルフホストのPages RouterでのSSG・ISRキャッシュ汚染などが含まれます。9月23日の事前告知では9件の予定でしたが、Critical 1件とHigh 1件は上流の依存の都合で延期され、2026年10月2日時点で修正版はありません。更新後も、次のリリースをnpm view next dist-tagsやNext.jsのブログで追ってください。
社内に14系以前や15.2系のNext.jsアプリが複数残っていて、どれから手を付けるか判断できない場合は、外部の診断で現状を洗い出すのが早道です。一創の脆弱性診断・セキュリティ診断では、ミドルウェアに依存した認可の抜け道を含め、Webアプリケーションの認証・認可を診断しています。
ミドルウェアだけに認可を置かない設計:Next.js公式の推奨
CVE-2025-29927で被害が大きくなるのは、認可をミドルウェア1か所に集めていたアプリです。Next.jsの認証ガイドは現在、この点を明確に書いています。
While Proxy can be useful for initial checks, it should not be your only line of defense in protecting your data.
Proxyは、16系でのミドルウェアの新しい名前です。middlewareというファイル規約は非推奨になり、proxy.tsとproxy関数へ改称されました。ガイドはProxyでの判定を「楽観的チェック」と位置づけ、Cookieを読んでリダイレクトするだけの前段処理にとどめるよう勧めています。本当の認可は、データを取得するServer Component、Server Action、Route Handlerの中で行う構成です。ガイドはデータ取得と認可処理をData Access Layer(DAL)に集約する構成を示しています。以下はそのセッション確認部分の抜粋で、App Router環境と、署名・有効期限を検証する別実装のdecrypt関数を前提とします。対象データや操作への権限判定は別途必要です。
// app/lib/dal.ts
import 'server-only'
import { cache } from 'react'
import { cookies } from 'next/headers'
import { redirect } from 'next/navigation'
import { decrypt } from '@/app/lib/session'
export const verifySession = cache(async () => {
const cookie = (await cookies()).get('session')?.value
const session = await decrypt(cookie)
if (!session?.userId) {
redirect('/login')
}
return { isAuth: true, userId: session.userId }
})
データを返す関数の先頭でawait verifySession()を実行し、検証の完了を待ってからデータを取得すれば、ミドルウェアが飛ばされても、未ログインの利用者にはデータが渡りません。ミドルウェアに加え、ページやAPIでもセッションを検証し、対象データの所有者や操作権限まで確認する構成なら、CVE-2025-29927による認可バイパスからデータや操作を保護できます。ただし、CSPの付与やキャッシュ制御など、ミドルウェアのほかの処理が省略される影響は別途確認が必要です。Auth.jsを使っている場合も、保護対象の処理でawait auth()の戻り値を確認し、セッションが無ければ処理を中断したうえで、必要な権限も検証する構成が同じ役割を果たします(Auth.jsとNextAuthの違いとv5の導入手順を参照)。
公表までの経緯:報告から公開まで22日の対応と修正版の提供時系列
Vercelの事後報告(postmortem)によると、経緯は次のとおりです(時刻はGMT)。
| 日時 | 出来事 |
|---|---|
| 2025-02-27 06:03 | GitHub非公開報告を受領(当初12.x対象) |
| 2025-03-01 02:00 | 最近の版も影響を受けるとの追加報告 |
| 2025-03-14 17:18 | Next.jsチームへ調査を依頼 |
| 2025-03-17 22:44 | 14.2.25を公開 |
| 2025-03-18 00:23 | 15.2.3を公開 |
| 2025-03-21 10:17 | CVEを公開 |
| 2025-03-22 21:21 | 13.5.9を公開(バックポート) |
| 2025-03-23 06:44 | 12.3.5を公開(バックポート) |
当初の報告が古い12.xについてのものだったため優先度が下がり、複数の報告が重なってトリアージが遅れた、とVercel自身が書いています。再発防止策として、ホスティング事業者向けの連絡網の新設、報告窓口のGitHub非公開報告への一本化、LTSポリシーの公開、内部ヘッダーを文書化したデプロイアダプターAPIの整備を挙げました。前章のサポートポリシーはこのとき公開されたものです。
よくある質問
CVE-2025-29927のPoCは公開されていますか?
公開されています。2025年3月の公開直後から、GitHubに検証用のコードや脆弱性スキャナ向けの検知テンプレートが多数上がりました。自社アプリでは、本文の3条件で認可バイパスの危険性を確認し、CSPやキャッシュへの影響も点検してください。更新の判断にPoCの実行は必須ではありません。動作を確かめる場合も、自社が管理権限を持つ検証環境に限ってください。
CVE-2025-29927でリモートからコードを実行されますか?
この脆弱性単体では実行されません。アドバイザリの分類はCWE-285(不適切な認可)です。起きるのは、ミドルウェアの処理を飛ばして保護されたページやAPIに届くことで、ミドルウェアで付けているCSPが外れたり、キャッシュの構成によってはエラー応答が保存されてサービス妨害になったりする例も報告されています。その先のAPIに別の弱点があれば、被害はさらに広がります。
Vercelにデプロイしているアプリも対応が必要ですか?
CVE-2025-29927については不要です。VercelはNext.jsのルーティングを別システムで処理しているため影響を受けず、アドバイザリにも自動で保護されると明記されています。ただし、版を古いまま放置してよい理由にはなりません。その後に見つかった脆弱性の修正は、Vercel上でも版を上げなければ取り込めません。
Next.jsの脆弱性はどう追いかければよいですか?
GitHubのvercel/next.jsリポジトリのSecurity Advisoriesが一次情報です。リポジトリをWatchしてセキュリティアラートを有効にするか、Dependabotを設定すれば、影響する版を使っている場合に通知が届きます。複数のアプリをまとめて見るなら、OSV-Scannerなどでロックファイルを定期的に照合するのが確実です。
CVEとは何の略ですか?
Common Vulnerabilities and Exposuresの略で、公開された脆弱性に一意の番号を振る仕組みです。CVE-2025-29927は「2025年に採番された29927番」を意味し、採番はGitHubがCNA(採番機関)として行いました。深刻度の数値であるCVSSや、弱点の種類を表すCWEとは別の体系です。