⁉️

Next.jsミドルウェアの致命的脆弱性:CVE-2025-29927の詳細分析

に公開

はじめに

2025年3月21日、平凡な一日と思われたその日に、CVE に関連する深刻なセキュリティ脆弱性が報告されました。これは、Vercel 社が開発する人気フロントエンドフレームワークNext.js に存在する脆弱性です。

脆弱性の報告直後、技術コミュニティ内に大きな衝撃が走りました。Next.js は現在、最も普及しているフロントエンドフレームワークのひとつであり、NPM では週に1,300万回以上ダウンロードされています。なお、メンテナンスされているすべての Next.js バージョンにこの脆弱性が存在するため、Next.js を採用しているほぼすべてのプロジェクトが影響を受ける可能性があります。

この脆弱性がこれほど注目された理由は、その危険度がほぼ最大レベルであり、CVSS スコアが 9.1 という極めて高い評価を受けたためです。

Next.js ミドルウェアの認証バイパス
Authorization Bypass in Next.js Middleware

六つの主要な評価指標のうち、可用性(Availability Impact)以外はすべて最悪の評価を受けています。厳密に言えば、可用性の評価も完全に正確とは言えないと思います。というのも、この脆弱性を利用した DDoS 攻撃が容易に実行でき、システムを簡単にダウンさせることが可能だからです。

しかし、この記事ではそのような深刻な被害状況よりも、この脆弱性の技術的詳細に焦点を当てます。技術コミュニティで大きく注目された理由は、あまりにも初歩的なバグであった点にあると言えるでしょう。こうした基本的なエラーは、大学生の課題でも厳しく指摘されるレベルのものです。

それでは、この脆弱性の技術的詳細を深く掘り下げていきます。

脆弱性の技術的詳細

ミドルウェアの役割と実装

まず、バックエンドシステムにおけるミドルウェアの定義を確認しましょう。

ミドルウェアの定義図

インターネットに接続されたバックエンドシステムでは、フロントエンドからのリクエスト処理に際して、共通の前処理ステップが実施されます。たとえば、リクエストを受け取った直後にキャッシュを確認したり、特定の権限が必要なリクエストの場合は事前にユーザー認証を行ったりします。

これらの処理は共通のパターンで実行されるため、最初からゼロで実装するのではなく、既存のミドルウェアパッケージが利用されます。たとえば、JavaScript の Express や Koa、Python の Flask や Django、PHP の Laravel など、成熟したバックエンドフレームワークには豊富なミドルウェアエコシステムが整っています。

後発の Next.js も同様のミドルウェア機能を有していますが、純粋なオープンソースフレームワークとは一線を画す特徴があります。Vercel 社が Next.js をオープンソース化した背景には、自社のクラウドサービス、特にサーバー+CDN パッケージの市場シェア獲得戦略が存在します。

そのため、Next.js のアーキテクチャには特徴的な設計思想が取り入れられています。Next.js でバックエンドシステムを開発し、Vercel のクラウドへデプロイすると、ミドルウェアに関するコードが自動的に抽出され、Vercel Edge Network(Vercel 提供の CDN)へ送信されます。

ミドルウェアとビジネスロジックの分離図とリクエスト処理図

ユーザーがバックエンドへリクエストを送信すると、まず CDN を経由します。CDN はその場でミドルウェアのロジックをすべて実行し、残りの処理をサーバーへ転送します。この仕組みにより、多くの Next.js 開発者は Vercel クラウドサービスの高いパフォーマンスを評価しています。

特に、ミドルウェアのみでレスポンスを返せるリクエストの場合、ほぼ瞬時に応答が返される点が大きな魅力です。

認証の例

図の例のように、ユーザーがプロフィールページを閲覧しようとすると、リクエストはまず CDN 側で認証チェックを受けます。認証されていない場合、その場でログインページへリダイレクトされ、サーバー側は一切関与しません。これが Vercel の競争上の優位性であり、Next.js をオープンソース化した根本的な狙いでもあります。

しかし、このアーキテクチャには潜在的な問題も孕んでいます。もしミドルウェアの実行ロジックが CDN デプロイメントのシナリオを十分に考慮していなければ、無限ループに陥るリスクがあるのです。

無限ループの例

図の例では、ミドルウェアがリダイレクトを実施した後、直後に新たなリクエストが CDN に戻り、再びミドルウェアが実行され、認証に失敗すれば再度リダイレクトが行われる―という無限ループがタイムアウトに至るまで繰り返される状況が発生します。

問題の核心:初歩的なセキュリティミス

この問題に対処するため、Vercel の開発者たちは独自の対策を講じました。すなわち、ミドルウェアがリダイレクトを実行する直前に、次のリクエストへ特定のヘッダーを追加する方式です。このヘッダーによって、後続のリクエストがユーザー由来ではなく、CDN 内の内部処理で発生したものであることを示そうとしました。

認証およびリダイレクトを担当するミドルウェアは、このヘッダーを検出すると、処理をスキップしてリクエストをそのまま通過させる仕組みとなります。

特別なヘッダーのコード図
New Middleware API signature #30282

ところが、この実装には深刻なセキュリティ上の欠陥がありました。HTTP リクエストのヘッダーは誰でも自由に設定可能なため、該当ヘッダーを単に追加するだけで認証を含むすべてのミドルウェアがバイパスされてしまうのです。

たとえば、管理者ページへアクセスする際、管理者権限がなくとも、このヘッダーをリクエストに加えるだけで認証処理がスキップされ、アクセスが許可されてしまいます。さらに、DDoS 攻撃、XSS 攻撃、キャッシュ汚染などのリスクも容易に引き起こされる可能性があります。

本来、これらの攻撃はミドルウェアによって防がれるはずですが、特定ヘッダーの存在によりすべてのセキュリティチェックが迂回されてしまうのです。コンピュータサイエンスの知識を有する者なら、このような初歩的なミスは起こりえないと考えるでしょう。しかし、平均年収 3000 万円以上とされる Vercel のプログラマーがこの実装を採用し、なおかつ 3 年間も問題が指摘されなかった事実には驚かされます。

プルリクエストのマージ時間
New Middleware API signature #30282

2025年3月1日、ようやく二人の外部セキュリティ専門家がこの脆弱性を発見し、Vercel に報告しました。しかし、Vercel の対応はここで終わったわけではありません。

最初の修正試み

脆弱性報告後、最初のパッチのリリースまでに Vercel チームは 17 日を要し、その対策として別のヘッダーを追加する方式が採用されました。

追加のヘッダーのコード図
Update middleware request header #77201

追加されたヘッダーの値は、ミドルウェアが乱数を生成し、リダイレクト直前にその値をグローバルオブジェクトに保存することで設定されます。その後、後続のリクエストにおいて、ヘッダーの値が保存された乱数と一致するかを検証することで、外部ユーザーによる偽造を防ごうとする仕組みです。

しかし、このパッチはひとつの問題を解決したものの、同時に新たな問題点も露呈しました。

プルリクエストへのコメント
Update middleware request header #77201

まず、暗号学的に安全な乱数の生成には相応のコストがかかります。特に CDN のコールドスタート環境では、ノイズの収集やエントロピープールの形成などが必要となり、これにより Vercel が苦労して実現したパフォーマンス上の優位性が大幅に損なわれる可能性がありました。

さらに、リダイレクト後の新たなリクエストが必ずしも同一セッションに戻るとは限らず、CDN の分散設計上、同じマシンに到達する保証もありません。そのため、本来ミドルウェア由来のリクエストであっても、乱数が一致せず外部リクエストと判定されるケースが懸念されました。

最終的な修正方法

初期のバグが偶発的なものであったとしても、このパッチの問題は Vercel 開発者の判断に対して疑念を抱かせるものでした。それにもかかわらず、Vercel は批判を受けながらも、1 週間後に新たなパッチをリリースしました。

今回のパッチは、ヘッダーを用いたミドルウェアバイパスのロジックそのものを完全に削除するという、より徹底した対応となりました。つまり、無限ループの問題については、各アプリケーション開発者が個別に対処すべき事態となったのです。

https://github.com/vercel/next.js/pull/77474

この事例から学ぶべき教訓

この一連の事象を振り返ると、根本的な問題は、営利組織である Vercel が非営利プロジェクトを利用して自社の利益を追求する手法にあると言えるでしょう。このような構図は、10 年以上前にも既に見られていました。

当時、クラウドサービス企業である Joyent は、Node.js の創始者である Ryan Dahl を雇用することで、間接的に Node.js の支配権を握りました。自社のクラウドサービスの競争力を強化するため、多くの Node.js 機能の開発が抑制され、その結果、Node.js バージョン 1.0 のリリースが大幅に遅延したのです。

やがて、Node.js のコア開発者たちは限界に達し、Node.js をフォークして新たなプロジェクトを立ち上げました。Joyent もコミュニティの支持を失う危機感から、Linux ファウンデーションの下で Node.js ファウンデーションを設立し、支配権を手放すことで、Node.js は正常な発展軌道へ戻りました。

https://nodejs.org/en/blog/announcements/foundation-v4-announce

10 年後、Vercel はほぼ Joyent と同様の戦略を採用するとともに、過去の事例から学び、React のコア開発チーム のメンバーを自社に直接迎え入れる方針を採りました。

Vercel で働く React コアメンバーのリスト
Reactチーム紹介

これにより、外部からの批判があっても React の開発方針に対する一定の影響力を維持できるようになりました。その結果、近年注力されているサーバーサイドレンダリング(SSR)の強化が実現し、React とバックエンドを連携させることで Next.js へのユーザー流入を増加させ、最終的には自社クラウドサービスへの誘導に成功しています。

Vercel の戦略は極めて精巧であり、ある意味賞賛されるべきものですが、一方でプログラマーの視点からは、これが巧妙に仕組まれた「罠」とも言えます。Next.js を採用する際、ユーザー自身が知らず知らずのうちに Vercel の戦略の一部として組み込まれている側面が存在するのです。

まとめ

本事例は「ノーフリーランチ定理(No Free Lunch theorem)」を想起させます。オープンソースの恩恵を享受する一方、その背後に潜む商業的動機や影響力を十分に理解することが重要です。技術選択においては、単に機能性だけでなく、プロジェクトのガバナンスモデルや長期的な方向性も慎重に検討すべきでしょう。

参考

  1. https://vercel.com/blog/postmortem-on-next-js-middleware-bypass#2025-03-01
  2. https://github.com/vercel/next.js
  3. https://openai.com/
  4. https://zenn.dev/t3tra/articles/c293410c7daf63

Discussion