対象:Next.js(や類似のJSフレームワーク)でアプリを作って公開している人。とくに「AIに手伝ってもらって作って、運用は手探り」という人向けです。実際の事故(→ 放置したCVSS 10.0の話)から抽出した、後れを取らないための4つの対策です。
当サイトの視点:大事なのは速さではなく、見落とさない仕組み
個人開発者がセキュリティでつまずく原因は、たいてい知識不足ではなく、運用を続けられないことです。CVE速報を誰より早く読むことに価値はありません(速さはベンダーやニュースに任せればいい)。効くのは 「自分に関係するCVEを、見落とさない仕組み」です。だからこの記事は、知識ではなく仕組みづくりを中心にしています。
1. 実稼働版で判定する
「危ないバージョンを使っているか」は、package.json の下限表記ではなく、実際に動いているバージョンで測ります。なぜなら、マニフェストの数字と実際に動く版はしばしば食い違うからです。
✗ package.json の下限で数える
"next": "^16.0.0" →「16.0.0が脆弱だから危険」と誤判定。「8個脆弱」と過大カウント。
✓ 実稼働版で数える
npm ls next で実際の解決版を確認 → 自動更新済みは安全、固定ピンだけ危険。本当は2個。
# 実際に解決されている版を確認
npm ls next react react-dom
# 稼働中コンテナの中で確認
docker exec <container> npm ls next^16.0.0 のようなキャレット表記は、再ビルドで自動的に上がる範囲がある一方、固定ピンの依存は取り残されます。判定にはここに出るバージョンを使います。
自分の環境で確認する方法
ここからは、自分のアプリが今どの版で動いていて、既知のCVEに当たるかを確かめる手順です。どれも自分の環境の中を見るだけの操作です。
手元の版を確認する
プロジェクトのフォルダで npx next info を実行します。next・react・react-dom の実際のバージョンと、最新版との差が表示されます。npx next -v でも Next.js の版だけを確認できます。
なぜその版になっているかを確認する
npm ls next(pnpm なら pnpm why next)で、どのパッケージ経由でどの版が入っているかを見ます。ロックファイル(package-lock.json や pnpm-lock.yaml)をリポジトリに含めていない場合、ビルドのたびに版が変わり得るので、まず含めるようにします。
本番で動いている版を確認する
手元を更新しても、本番が古いイメージのまま動いていることがあります。コンテナなら、稼働中のコンテナの中で next の package.json に書かれた version を読みます(下のコマンド例)。output: 'standalone' の構成でも、この方法で確認できます。
既知のCVEと照合する
npm audit --omit=dev で、本番に入る依存だけを既知の脆弱性と照合します。--audit-level=high を付けると、High以上が見つかったときに終了コードが0以外になるので、CIで止める条件にできます。osv-scanner でロックファイルを検査する方法も同じ目的に使えます。
公式の勧告で、自分の構成が対象かを読む
Next.js の勧告は、App Router か Pages Router か、セルフホストかどうかで対象が分かれることがあります。勧告に書かれた修正版の一覧と、手順1〜3で確かめた版を突き合わせます。
# 手元:実際の版と最新版との差
npx next info
# 本番コンテナの中で動いている版
docker exec <container> node -p "require('next/package.json').version"
# 本番に入る依存だけを既知の脆弱性と照合(High以上で失敗)
npm audit --omit=dev --audit-level=high動かし方で変わること
同じCVEでも、どう動かしているかで影響を受けるかが変わります。過去の2件を例に、動かし方ごとにまとめます。
| 動かし方 | ミドルウェアの認可迂回(CVE-2025-29927) | RSCのRCE(CVE-2025-55182) | 更新の担当 |
|---|---|---|---|
| Vercel・Netlify などのマネージド | 影響なし(ルーティングが別の仕組みで動くため) | App Router なら対象。遮断ルールはあっても更新は必要 | 自分(next の版は自分のロックファイルで決まる) |
| セルフホスト(next start/standalone、Docker含む) | 対象 | App Router なら対象 | 自分(イメージの再ビルドと再起動まで) |
| 静的エクスポート(output: 'export') | 影響なし(サーバーが動かないため) | リクエストを受けるサーバーがないため、基本的に届かない | 自分(ビルドに使う依存は更新対象) |
表から分かるとおり、マネージドのホスティングでも、Next.js の版を上げるのは利用者自身です。ホスティング会社の対策は、修正版に上げるまでの時間を稼ぐものと考えてください。
サポート期間も確認しておきます。公式のサポートポリシーでは、2026年10月時点で次のとおりです。
| 系列 | 状態(2026年10月時点) | セキュリティ修正 |
|---|---|---|
| 16.x | Active LTS(新機能・修正・セキュリティ修正) | 出る |
| 15.x | Maintenance LTS(初回リリースから2年) | 重大なものだけ出る |
| 14.x 以前 | サポート対象外 | 深刻な場合にまれに出るだけで、保証はない |
2. 依存を機械監視する
CVEを手作業で追い続けるのは難しく、その見落としが事故になります。ツールで自動監視します。
無料で始められる依存監視
# OSV スキャナでロックファイルを検査(CIに1ステップ)
osv-scanner scan -L pnpm-lock.yamlGitHub なら Dependabot を有効化(リポジトリの Settings → Advanced Security → Dependabot alerts)。自分の依存に該当するCVEだけが自動でPR通知されます。
監視では優先度が肝心です。当サイトの考えでは、優先順位は「実際に悪用されているか(KEV)」と「CVSSの高さ」を掛け合わせて決めます。CVSSの数字が高くても未使用なら影響は小さく、中スコアでも悪用中なら最優先です。この優先度の判断が、運用の中心になります。
3. 更新:回避策ではなく修正版に上げる
脆弱性が見つかったら、フレームワーク本体を修正版へ更新して、脆弱性そのものを修正します。
表面的な対処(不十分)
- リバースプロキシで攻撃に似たリクエストだけを遮断する
- 課金や症状を止めて「対応完了」と考える
- RCE の脆弱性自体は残ったまま
根本修正(正しい)
- フレームワーク本体を修正版へ更新して脆弱性を修正する
- 更新後、脆弱性の兆候が消えたかをログで確認
- 被害拡大を止める作業と根本的な修正を、別作業として両方やる
やりがちな失敗
「課金や症状を止めた」≠「対応完了」。被害拡大を止めることと、脆弱性そのものを修正することは別の作業です。両方やって初めて完了です。
実際の例:2025年12月の React Server Components の脆弱性
公開済みCVEへの対応で何が起きるかを、2025年12月に公表された React Server Components(RSC)の脆弱性で振り返ります。いずれも React・Next.js の公式発表と CISA の公開情報にもとづきます。
2025年12月3日
React が CVE-2025-55182(CVSS 10.0)を公表。認証なしでサーバー上のコード実行につながり得る脆弱性で、Next.js では App Router を使う 15.x・16.x などが対象(CVE-2025-66478)。Pages Router と Edge Runtime は対象外。回避策はなく、修正版(15.0.5/15.1.9/15.2.6/15.3.6/15.4.8/15.5.7/16.0.7 など)への更新が必要とされた。2025年12月5日
CISA が、実際に悪用が確認された脆弱性の一覧(KEV)に追加。2025年12月6日
Next.js が、12月4日13時(米国太平洋時間)の時点で修正前のまま公開していたアプリには、使っている秘密情報(APIキーなど)の入れ替えを強く勧めると追記。2025年12月11日
修正の検証の過程で、同じ仕組みに別の脆弱性が2件(サービス停止とソースコードの露出)見つかり、追加の修正版を公開。その後、サービス停止の修正が不完全だったとして CVE-2025-67779 が出され、先に更新した人にも再度の更新が求められた。
この例から、運用で押さえることが3つ分かります。
- 一度更新しても終わりではない。同じ箇所の追加の修正が数日おきに続くことがある
- ホスティング側の遮断ルールは補助で、版を上げることが唯一の完全な対処とされた
- 修正前に公開していた期間があるなら、更新に加えて秘密情報の入れ替えまで行う
当サイトの視点:「更新した」ではなく「本番の版が修正版になった」で完了にする
この件のように追加の修正が続くと、「先週上げたから大丈夫」という記憶が当てになりません。完了の判断は、作業した記憶ではなく、本番で動いている版が最新の勧告の修正版以上になっているかで行います。当サイトも、デプロイ後にコンテナが作り直されたことと、中で動く版を確かめてから完了としています。
よくある間違いと直し方
- package.json の数字だけで判断する:実際に入っている版は違うことがあります。
npx next infoやnpm ls nextで確かめます。 - ロックファイルを更新しただけで終わる:本番のイメージを作り直して再起動するまで、古い版が動き続けます。本番の中で版を確認します。
- 1回の更新で安心する:追加の勧告が続くことがあります。Dependabot などの通知を有効にしたまま、数日は勧告を追います。
- ホスティング会社の遮断ルールに任せる:遮断ルールですべての攻撃の形を防げるとは限りません。版を上げます。
- サポート対象外の系列に留まる:14.x 以前は修正が出る保証がありません。16.x へ移る計画を立てます。
- 開発用の依存の警告が多すぎて、本番に関わる警告を見落とす:
npm audit --omit=devで本番に入る依存を先に見ます。 - 修正前に公開していた期間を気にしない:その間に秘密情報が抜かれた可能性があります。APIキーやデータベースのパスワードを入れ替えます(→ .envとAPIキーの基本)。
4. 最小権限で被害の範囲を小さくする
万一悪用されても、被害が広がらない設計にします。
非特権ユーザーで動かす
USER を root にしない。悪用されても、そのユーザーの権限の範囲までしか被害が及ばない。DB・Redisは内部ネットだけに
サービスごとに分離
これらは、漏れたときに「コンテナ内のenv窃取で止まる」か「ホスト乗っ取りまで行く」かの分かれ目になります。
当サイト自身も同じ対策を実践している
当サイト自身も、ここで書いた通りに自分の依存をCVE監視の対象にしています。発端になった事故(公開済みCVSS 10.0の見落とし)を、二度と人が見落とさないよう、ツールによる自動監視を運用に組み込んでいます。私たちが「優先度(KEV+CVSS)で見る」と書くのは、自分たちがそう運用しているからです。
次に読む
- 事故:公開済みRCEを放置して不正課金された話
- 用語:CVE / CVSS / RCE
- 歴史:Log4Shell — 依存経由のRCE
- FW別:Next.jsのセキュリティ対策(境界・環境変数・依存CVEの総論)
- 優先度:CVSS・EPSS・KEVでCVEの優先度を決める
- 監視:osv-scannerの導入と使い方
- 傾向:Next.jsとReactは脆弱性が多いのか(CVEの実データで見る、危ないのはどこか)
出典
- Next.js「Security Advisory: CVE-2025-66478」(2025年12月3日、12月6日追記): nextjs.org
- Next.js「Security Update: December 11, 2025」(CVE-2025-55183/55184/67779): nextjs.org
- NVD「CVE-2025-55182」: nvd.nist.gov / CISA「Known Exploited Vulnerabilities Catalog」: cisa.gov
- Vercel「React2Shell Security Bulletin」: vercel.com
- Vercel「Postmortem on Next.js Middleware bypass」(CVE-2025-29927): vercel.com
- Next.js「Support Policy」: nextjs.org /「next CLI」: nextjs.org /「Static Exports」: nextjs.org
- npm Docs「npm audit」: docs.npmjs.com / OSV-Scanner「Usage」: google.github.io / GitHub Docs「Configuring Dependabot alerts」: docs.github.com