フロントエンドのビルドツールViteに、開発サーバー上で任意のコードを実行される脆弱性GHSA-p4f5-76q4-ffq7が2026年11月10日に公表されました。深刻度はCVSS 4.0で9.1のCriticalで、影響はVite 4.0から8.3.6までの広い範囲に及びます。この記事では、原因と悪用の前提条件、系列ごとの修正版とnpmで実際に入る版、手元の版と公開設定を調べるコマンド、すぐ更新できない環境で開発サーバーを閉じる設定を順に整理します。本記事の記述の基準は、11月11日時点で公開されている情報です。
まとめ:開発サーバーを外部公開していたViteは修正版へ、5系以前は6.4.6以上へ
影響を受けるのは、--hostやserver.hostで開発サーバーをネットワークへ公開しているプロジェクトです。localhostだけで待ち受ける既定の設定なら、この脆弱性は成立しません。とはいえ設定は人によって違うため、版番号の更新を先に済ませるのが確実です。
更新先は8系なら8.3.8、7系なら7.3.8、6系なら6.4.6です。4系と5系には修正版が出ていないので、6.4.6以上へのメジャー更新が必要になります。この脆弱性にはCVEが付いておらず、11月11日時点ではGitHubの全体のアドバイザリデータベースにも載っていません。Dependabotやnpm auditの警告を待たず、版番号で判断してください。社内の開発環境の公開範囲をまとめて点検したい場合は、脆弱性診断・セキュリティ診断で受け付けています。
GHSA-p4f5-76q4-ffq7で開発サーバー上のコード実行に至る仕組みと前提条件
Viteのアドバイザリが分類する弱点はCWE-116、出力時のエンコードやエスケープの不備です。報告者は4名で、修正はViteのメンテナが公開しました。
2つの仮想モジュールにURL由来のIDが無エスケープで入る原因
Viteの依存解決プラグインは、__vite-browser-external:<suffix>と__vite-optional-peer-dep:<suffix>という仮想モジュールを内部で生成します。ブラウザで使えないNode.jsの組み込みモジュールや、入っていない任意のピア依存を参照したときに差し込む代わりのモジュールです。
問題は、要求URLから取り出した<suffix>の部分が、生成するコードへエスケープなしで埋め込まれていた点です。攻撃者はURLを細工するだけで、そのモジュールに任意のコードを書き込めました。
server.fsの外のファイル読み出しとeval経由のサーバー上での実行
アドバイザリは影響を2段階で説明しています。1段目は、注入したコードからserver.fsの制限外のファイルをインポートさせ、その内容を取り出すことです。.envや秘密鍵のように、本来なら403で拒否されるファイルが対象になります。
2段目はサーバー側での実行です。Viteはnew Workerとimport.meta.globの処理で値を取り出すためにevalを使っており、この経路を通すと注入したコードが開発サーバーのNode.jsプロセスで評価されます。requireなどの変数は使えないよう制限されていましたが、アドバイザリはこれを「セキュリティ境界ではない」と明言し、回避方法があるとしています。開発者の端末やCIで動くプロセスの権限で、任意の処理を実行されると考えてください。
–hostかserver.hostで開発サーバーを公開している場合だけが対象
アドバイザリは、影響を受けるのは--hostオプションかserver.host設定で開発サーバーを明示的にネットワークへ公開しているアプリに限ると書いています。Viteの公式文書ではserver.hostの既定値は'localhost'で、trueや0.0.0.0を指定するとLANや公開アドレスを含む全アドレスで待ち受けます。
CVSSのベクトルはAV:N/AC:L/AT:P/PR:N/UI:Nで、認証も利用者の操作も要りません。AT:P(攻撃の前提条件あり)が、この「公開している場合だけ」に当たります。スマートフォンの実機確認のためにvite --hostで起動し、カフェや共用のネットワークで作業していた端末は、同じネットワークの誰からでも届く状態でした。
Vite 4.0から8.3.6までの影響版と系列ごとの修正版・npmで入る版
影響版と修正版は、アドバイザリの記載とnpmレジストリの実際の公開状況を突き合わせて確認しました。両者にずれがあるので、表の右端の列で判断してください。
系列ごとの影響版・アドバイザリ上の修正版・npmで入れる版の対応表
| パッケージ | 影響版 | アドバイザリの修正版 | 11月11日時点で入れる版 |
|---|---|---|---|
| vite 8.3系 | 8.3.0〜8.3.6 | 8.3.7 | 8.3.8(最新) |
| vite 8.2系 | 8.2.0〜8.2.4 | 8.2.5 | 8.2.6 |
| vite 8.0〜8.1系 | 8.0.0〜8.1.6 | 8.1.7 | 8.1.7 |
| vite 7系 | 7.0.0〜7.3.7 | 7.3.8 | 7.3.8 |
| vite 4〜6系 | 4.0.0〜6.4.5 | 6.4.6 | 6.4.6 |
| vite-plus | 1.5.0以下 | 1.5.1 | 1.5.1 |
修正版はいずれも11月9日にnpmへ公開され、アドバイザリの公開は翌10日でした。8.3.8は11月11日に出た通常のバグ修正版で、修正内容は8.3.7を含みます。Vite+(vite-plus)を使っている場合の更新手順は、Vite+の1.5系とRCE脆弱性への対処で扱っています。
アドバイザリ記載の8.2.5とRolldown 1.2.17のnpm未公開と8.2.6
アドバイザリは、8系の修正がViteの中ではなく、8系が使うRolldown側にあると書いています。8.3.7と8.2.5はRolldown 1.2.17、8.1.7はRolldown 1.1.7の修正に依存するという説明です。実際、8.3.7の変更履歴にある修正は「Rolldownをv1.2.18へ更新」の1項目だけでした。
ところがnpmレジストリには、vite 8.2.5もrolldown 1.2.17も存在しません。Rolldown 1.2.18のリリースノートには、1.2.17はRustのcrates.ioだけに公開し、その変更を1.2.18でnpmへ反映したと書かれています。npmで実際に公開されたのは、rolldown ~1.2.18に依存するvite 8.2.6です。8.2系に留まるなら8.2.6を指定してください。
4系・5系には修正版が出ておらず6.4.6以上へ上げるメジャー更新の必要
影響範囲は4.0.0からですが、修正版の最も古い系列は6.4.6です。npmで確認すると、4系の最終版は2025年4月30日の4.5.14、5系の最終版は2025年10月20日の5.4.21で、どちらも今回の修正を含みません。
4系・5系のプロジェクトは、6.4.6へのメジャー更新が避けられません。5系から6系への変更点はVite 6の移行ガイドにまとまっています。移行の工数が取れない間は、後述の設定で開発サーバーをlocalhostに閉じ、外から届かない状態を保ってください。
手元のプロジェクトで影響を受けるViteの版と開発サーバーの公開設定を調べる手順
調べるのは、実際に入っているViteとRolldownの版、そして開発サーバーを公開する設定があるかの2点です。どちらも読み取りだけで、作業中のサーバーは止めません。
npm lsでViteとRolldownの実際の版を依存ツリーごと確認
package.jsonの記載ではなく、ロックファイルから実際に入った版を見ます。npm lsの公式文書のとおり、パッケージ名を並べると、間接依存も含めてどこから入ったかが表示されます。
# プロジェクトのルートで実行(Vitestや各種プラグイン経由の間接依存も表示される)
npm ls vite rolldown vite-plus --all
# pnpm の場合
pnpm why vite
pnpm why rolldown
結果にvite 8.3.6以下と7.3.7以下、6.4.5以下が1つでも出たら更新の対象です。Vitestや@vitejs/plugin-reactなどが別の版のViteを抱えていることもあるため、最上位の1行だけで判断しないでください。8系の場合は、rolldownが1.2.18以上か1.1.7以上かも合わせて見ます。
vite.config.tsとpackage.jsonのhost設定のgrep確認手順
次に、開発サーバーを公開する設定を探します。設定ファイルのhostと、起動スクリプトの--hostの2か所に現れます。
# 設定ファイルの server.host(true や 0.0.0.0 になっていないか)
grep -nE "host\s*:" vite.config.*
# 起動スクリプトの --host
grep -n "\-\-host" package.json
# モノレポなら node_modules を除いて全体を検索
grep -rnE "\-\-host|host\s*:\s*(true|['\"]0\.0\.0\.0)" --include=package.json --include="vite.config.*" --exclude-dir=node_modules .
Dockerの開発用コンテナでは、コンテナ外から接続するために--hostを付けるのが通例です。その場合は、docker runやcompose.yamlのポート公開の書き方まで確認が要ります。詳しくは暫定策の章で扱います。
系列別にViteを修正版へ上げてロックファイルとCIで固定するまでの手順
更新は、直接の依存と間接依存の両方をそろえてはじめて完了です。直接の依存だけを上げると、プラグインが抱える古いViteが残ることがあります。
8系・7系・6系それぞれの修正版を指定するnpm installのコマンド
系列は変えず、同じ系列の修正版へ上げるのが最小の変更です。
# 8.3系(8.3.8 は 8.3.7 の修正を含む)
npm install -D [email protected]
# 8.2系に留まる場合(npm には 8.2.5 が無いので 8.2.6)
npm install -D [email protected]
# 7系
npm install -D [email protected]
# 4〜6系(4系・5系は 6系への移行が前提)
npm install -D [email protected]
# 確認:脆弱な版が残っていないか
npm ls vite rolldown --all
最後のnpm lsで古い版が残っていなければ、ロックファイルをコミットします。CIでnpm ciを使っていれば、ロックファイルの版がそのまま再現されます。
overridesでプラグインが抱える間接依存のViteを修正版にそろえる設定
プラグインの依存範囲が古いViteに固定されていて、上の操作では上がらない場合があります。そのときは、package.jsonの公式文書にあるoverridesで、依存ツリー全体のViteを1つの版に固定します。
{
"devDependencies": {
"vite": "8.3.8"
},
"overrides": {
"vite": "$vite"
}
}
$viteは「直接の依存に書いた版と同じにする」という指定です。書き換えたらnpm installを実行し、npm ls vite --allで全部が8.3.8になったことを確かめます。プラグインが想定していないメジャー版を強制すると動作が変わるので、上げるのは同じメジャー版の中に留めてください。
すぐ更新できない環境でserver.hostを閉じる設定とDockerのポート公開
アドバイザリには更新以外の回避策が書かれていません。ただ、前提条件が「開発サーバーをネットワークへ公開していること」なので、公開をやめれば攻撃の経路は塞がります。更新までのつなぎとして入れてください。
server.hostを既定のlocalhostに戻すvite.config.ts設定例
server.hostを明示的にlocalhostへ戻し、起動スクリプトから--hostを外します。
// vite.config.ts
import { defineConfig } from 'vite'
export default defineConfig({
server: {
host: 'localhost', // true や '0.0.0.0' にしない
// allowedHosts: true は設定しない
},
})
同じ文書はserver.allowedHostsをtrueにすると、DNSリバインディングで任意のWebサイトから開発サーバーへ要求を送れるようになると警告しています。トンネル用のサービスで外部のホスト名を通すためにtrueにしている設定は、許可するホスト名を列挙する形へ戻してください。スマートフォンでの実機確認が必要なときは、その作業の間だけ--hostを付け、自宅や社内の信頼できるネットワークに限ります。
開発用コンテナの公開ポートを127.0.0.1に限定するdocker runの指定
コンテナの中のViteは、ホストから接続させるために--hostで全アドレスを待ち受けます。危ないのはホスト側の公開範囲です。Dockerの公式文書のとおり、-p 5173:5173はホストの全アドレスで公開されるため、同じネットワークの他の端末から届きます。
# ホストの 127.0.0.1 だけに公開する
docker run --rm -p 127.0.0.1:5173:5173 -v "$PWD":/app -w /app node:22 npx vite --host
# compose.yaml の場合
# ports:
# - "127.0.0.1:5173:5173"
こうしておけば、コンテナ内で--hostを付けていても、開発サーバーに届くのはそのマシン自身からの接続だけです。共用の開発サーバーやクラウドの仮想マシンでViteを動かし、ポートを開けて複数人で見ている運用は、この方法では閉じられません。更新を最優先にしてください。
2025年以降のVite脆弱性の傾向から決める開発サーバー公開の採用条件
今回の件は単発ではありません。Viteのセキュリティ一覧には、2025年4月から2026年11月までに10件を超えるアドバイザリが並び、その多くが開発サーバーのファイル配信制限server.fsの迂回です。
2026年に公表されたserver.fs迂回系アドバイザリと深刻度の一覧
| 公表日 | 識別子 | 内容 | 深刻度 |
|---|---|---|---|
| 2026-04-06 | CVE-2026-39363 | WebSocket経由の任意ファイル読み取り | High |
| 2026-04-06 | CVE-2026-39364 | クエリ付き要求でserver.fs.denyを迂回 | Moderate |
| 2026-06-01 | CVE-2026-53571 | Windowsの別パス表記で迂回 | Moderate |
| 2026-10-06 | CVE-2026-112946 | server.fs.allowの外のファイルを配信 | Moderate |
| 2026-10-21 | CVE-2026-118662 | 6系でクエリ付き要求により迂回 | Moderate |
| 2026-11-10 | GHSA-p4f5-76q4-ffq7 | 仮想モジュール経由のコード実行 | Critical |
これまでの多くはファイルを読まれる被害でしたが、今回はサーバー上での実行まで進みました。どの件も、開発サーバーに外から届くことが悪用の入口です。開発サーバーの欠陥は今後も見つかると見て、版の更新とは別に、公開しない運用を標準にしておくほうが手戻りは少なくなります。同じ型の欠陥はStorybookにもあり、Storybookの開発サーバー脆弱性で対象版と確認コマンドをまとめています。
開発サーバーをステージング代わりに外部公開する運用は採用しない判断
判断を言い切ります。viteの開発サーバーを、顧客確認用やステージングの代わりとしてインターネットへ公開する運用は採用しません。開発サーバーは開発者の手元で動かす前提で作られており、ファイル配信の制限は過去1年余りで何度も破られています。確認用の環境にはvite buildの成果物を静的ホスティングやWebサーバーで配信してください。
一方、社内LANでの実機確認のために一時的に--hostを付ける使い方まで禁止する必要はありません。修正版に上げたうえで、作業が終わったら外す運用で足ります。ここで見送ってよい対策もあります。WAFで仮想モジュール名を含むURLだけを止める対策は、開発サーバーの前にWAFが無い構成がほとんどなので、労力に見合いません。
CVE未採番のためDependabotやnpm auditに出ない期間の監視方法
今回の件は、11月11日時点でCVEが採番されていません。GitHubの全体のアドバイザリデータベースとOSVでも、このIDのページは404を返しました。リポジトリ単位のアドバイザリが全体のデータベースへ取り込まれるまでの間は、それを情報源にするDependabotやnpm audit、OSVを使うスキャナに警告が出ない可能性があります。
依存ツールの通知だけに頼る体制では、この空白期間を拾えません。Viteのセキュリティ一覧をGitHubの「Watch」でセキュリティアラートとして購読しておけば、公開と同時に通知が届きます。Dependabotの設定と通知の仕組みはDependabotの設定とRenovateとの違いで、脆弱性データベースごとの収録の差はSCAとNVD・OSV・GitHub Advisoryの差で解説しています。
よくある質問
Viteの脆弱性GHSA-p4f5-76q4-ffq7について、開発の現場で迷いやすい点に答えます。
本番環境に配信しているビルド成果物にも影響はありますか?
アドバイザリが対象としているのは開発サーバーです。vite buildで出力した静的ファイルをWebサーバーやCDNで配信している本番環境は、この脆弱性の前提条件に当たりません。ただし、開発者の端末やCIで脆弱な版の開発サーバーを公開していた場合は、そのマシンの.envや認証情報が読まれた可能性があります。本番の秘密情報を開発環境に置いていたなら、入れ替えを検討してください。
vite previewのサーバーも対象になりますか?
アドバイザリの本文は開発サーバーについて書かれており、vite previewへの影響には触れていません。11月11日時点では対象外とも対象とも書かれていない状態です。vite previewは手元でビルド結果を確かめるための簡易サーバーとされているので、こちらも外部へ公開せず、修正版へ上げておけば判断を待つ必要はありません。
Vite 5系のまま修正だけを取り込む方法はありますか?
11月11日時点で、5系と4系に今回の修正版は出ていません。5系の最終版は2025年10月20日公開の5.4.21です。修正を取り込むには6.4.6以上へのメジャー更新が必要になります。移行の工数が取れない間は、server.hostをlocalhostに戻し、Dockerの公開ポートを127.0.0.1に限定して外から届かない状態を保ってください。
Vite 8.3.6でrolldownだけを1.2.18に上げれば足りますか?
アドバイザリは8系の修正がRolldown側にあると説明していますが、推奨しているのはViteの修正版への更新です。8.3.6が依存するrolldownの範囲は~1.2.16なので、ロックファイルの更新で1.2.18が入ることはあり得ます。それでもVite自体の組み合わせとして検証されているのは8.3.7以降なので、Viteを8.3.8へ上げる方法を選んでください。
悪用されたかどうかをログで確かめられますか?
アドバイザリに、侵害を判定する方法は書かれていません。Viteの開発サーバーは既定でアクセスログを残さないため、記録から確かめるのは難しいのが実情です。脆弱な版の開発サーバーを信頼できないネットワークへ公開していた期間があるなら、その端末の.envにあるAPIキーやクラウドの認証情報を、発行元で無効化して入れ替える対応を優先してください。
関連記事
- Vite + Reactの環境構築手順|Viteとは・Vite 8.3の変更点とTypeScript 7対応:Viteの仕組みと8系でRolldownへ移った背景を解説しています。
- Vite+とは?vpコマンドの使い方と1.5系の中身・RCE脆弱性への対処と既存Vite案件の移行手順:vite-plusを使っている場合の同じ脆弱性への対処です。
- Storybookの脆弱性CVE-2026-114125とは:開発サーバーの対象版・確認コマンド・修正手順:開発サーバーを狙う別の脆弱性と確認手順を扱います。
- SCAとは?ソフトウェア構成分析の仕組みとSAST・SBOMとの違い・導入判断を解説:依存パッケージの脆弱性を継続して見つける仕組みです。
- API不正アクセス対策の実装手順:JPCERT注意喚起に沿うレート制限・認可・トークン失効とアプリ解析・SSRF対策:漏れた認証情報を失効させる設計の基本をまとめています。