2026年5月から6月にかけて、Viteベースの人気JavaScriptテストフレームワークVitestに、立て続けに3件の深刻な脆弱性が公表された。中心となるCVE-2026-47429はCVSS 9.8(Critical)で、Vitest UIサーバの不正なファイルアクセス検査を突いて任意ファイルの読み取りとリモートコード実行(RCE)に至る。Vitestは週5300万ダウンロードを超え、無数のCI/CDパイプラインで動いているため、影響範囲は極めて広い。本記事では、影響バージョンの確認・パッチ適用・SCA(Software Composition Analysis)による継続検知までを手順で解説する。

AIエージェント時代のセキュリティ全体像を整理したい方は、ピラー記事AIセキュリティとは?LLM時代の脅威モデル・代表的リスク・OSS対策ツールを体系解説する入門ガイドを先に読むと、本記事の位置づけがつかみやすい。

3行でわかるVitest RCE脆弱性
  • 影響範囲: vitest 4.1.0未満・3.2.5未満、@vitest/browser 4.1.8以下・3.2.4以下・5.0.0-beta.3以下。修正版は4.1.8 / 3.2.5 / 5.0.0-beta.4
  • 攻撃内容: UIサーバ・Browser Mode・CDPブリッジをネットワーク公開/Windows実行すると、設定ファイル改ざんやファイル読み取りからRCE(CVSS最大9.8)に到達。
  • 対応: npm ls / npm audit / GHSAアラートで使用有無を確認し、各系列の最新パッチへ更新。上げられない場合はサーバをlocalhost固定+allowWrite/allowExec無効化。

依存パッケージ経由の攻撃全体の見取り図は サプライチェーン攻撃とは|手口・防御ツール比較・npm 12の新機構まで実践解説 にまとめています。

Vitestの3件のCVEを一括で解消する修正版バージョンを示す図
最低ラインは4.1.8/3.2.5/5.0.0-beta.4。npm最新はさらに先

修正版はどれか――結論と、2026年8月時点の最新版

【2026-08-27 更新】修正版の下限が上がりました。 Browser Mode に critical がもう1件(CVE-2026-73653・CVSS 9.4・2026-07-21公表)加わり、本記事が当初示していた 4.1.8 / 3.2.5 / 5.0.0-beta.4 では塞ぎきれなくなっています。あわせて、旧「CVE採番待ち」としていたCDP経由RCEに CVE-2026-53633 が採番されました。以下の表は更新後の値です。

4件まとめて解消する目標バージョンは vitest / @vitest/browser ともに次の3系列です。

系列 修正版(最低ライン) 2026-08-27時点の npm 最新
4.x 4.1.10 以降(旧: 4.1.8) latest = 4.1.11
3.x 3.2.7 以降(旧: 3.2.5) V3 タグ = 3.2.7
5.0 ベータ 5.0.0-beta.6 以降(旧: 5.0.0-beta.4) beta = 5.0.0-beta.7

(npm レジストリの dist-tags を2026年8月27日に取得。4.1.10 / 3.2.7 / 5.0.0-beta.6 はいずれも 2026-07-06 公開

注意すべきは公開日のズレです。 修正版 4.1.10 / 3.2.7 / 5.0.0-beta.6 が npm に出たのは 2026-07-06、一方 CVE-2026-73653 のアドバイザリ公表は 2026-07-21 で、15日の開きがあります。つまり「アドバイザリを見てから動く」運用だと、修正が配布済みの状態で2週間以上、脆弱なバージョンを使い続けることになります。バージョン追随を npm audit だけに頼らず、パッチリリース自体を追う仕組み(Dependabot のバージョン更新)も併用する理由がここにあります。

**3.x 系を使っている場合は特に注意。** 旧下限の 3.2.5 と新下限の 3.2.7 の間にある **3.2.6 は脆弱**です(後述の実測で確認)。

【実測】どのバージョンが実際に検出されるか

手元で各バージョンを実際にインストールし、監査に掛けて確認しました(2026-08-27・macOS / Node 22.13.1)。

インストールした構成 critical 検出 検出されたCVE
[email protected] のみ 0件
[email protected] のみ 0件
[email protected] + @vitest/[email protected] 1件 CVE-2026-73653
[email protected] + @vitest/[email protected] 0件
[email protected] + @vitest/[email protected] 1件 CVE-2026-73653
[email protected] + @vitest/[email protected] 0件
vitestとvitest/browserの各バージョンで検出されたcritical件数の実測結果。vitest単体4.1.8は0件、@vitest/browser 4.1.8と3.2.6は1件(CVE-2026-73653)、4.1.10と3.2.7は0件であることを示す。
実測(2026-08-27)。旧「安全ライン」の 4.1.8 と、旧下限直後の 3.2.6 で critical が残る。

この表のいちばん重要な行は1行目です。 vitest 単体を入れただけでは @vitest/browser は入らず、Browser Mode の脆弱性は検出されません[email protected]dependencies を実際に開いても @vitest/browser は含まれていませんでした。

つまり 影響を受けるのは Browser Mode を明示的に導入しているプロジェクトだけです。vitest を普通のユニットテストランナーとして使っているだけなら、CVE-2026-73653 / CVE-2026-53633 の対象外になります。逆に言えば、package.json@vitest/browser があるかどうかが最初の判定基準です。

# Browser Mode を使っているかを1行で判定する
npm ls @vitest/browser 2>/dev/null || echo "Browser Mode 未導入(今回の追加2件は対象外)"

修正版の最低ラインを満たしていれば4件のCVEは解消されますが、すでにその先のパッチが出ています。特に理由がなければ、各系列の最新(4.1.11 / 3.2.7)へ寄せておくほうが、以降の修正も同時に取り込めます。ベータ系列は本番運用に載せる前提の版ではない点に注意してください。

# いま入っているバージョンを確認する(devDependencies なので --dev も見る)
npm ls vitest @vitest/browser 2>/dev/null

# 既知の脆弱性として検出されるか
npm audit --omit=dev=false 2>/dev/null | head -40

# 修正版へ上げる(系列を変えたくない場合は範囲を明示)
npm i -D vitest@^4.1.10 @vitest/browser@^4.1.10   # 4.x を使い続ける場合
npm i -D vitest@^3.2.7  @vitest/browser@^3.2.7    # 3.x を使い続ける場合

同じ「テスト・CI環境が攻撃面になる」型の事例としては nginx CVE-2026-42533解説|mapとregexのRCEを自分のサーバで確認する実行コマンド付き、稼働中の依存バージョンを継続的に把握する仕組みは SBOM入門|ソフトウェア部品表でサプライチェーン攻撃を防ぐSPDX・CycloneDX・Syft活用法 が参考になります。

「修正版に上げた」で終わらせない
本件の攻撃面はUIサーバやBrowser Modeをネットワークに公開しているかに強く依存します。バージョンを上げても、CIで api.host を外部に開いたままにしている構成は、別の脆弱性が出たときに同じ形で刺さります。上げると同時に公開設定を見直すのが本質的な対策です。

30秒で理解する

まず要点だけを押さえる。今回のVitest脆弱性は、単独のバグではなく4件のアドバイザリの束である(当初3件。2026-07-21にBrowser Modeの1件が追加された)。共通する本質は「Vitestが内部で立ち上げるサーバ(UIサーバ・Browser Mode API・WebSocket RPC)が、信頼できない相手に届く状態だと危険」という一点に尽きる。

対象と深刻度: CVE-2026-47428(CVSS 9.6)、CVE-2026-47429(CVSS 9.8)、CVE-2026-53633(CVSS 9.8・旧「CVE採番待ちのCDP経由RCE」GHSA-g8mr-85jm-7xhm)、CVE-2026-73653(CVSS 9.4・2026-07-21追加)の計4件。いずれもCriticalで、結果はリモートコード実行
影響範囲: vitest本体は4.1.0未満および3.2.5未満。@vitest/browserは4.1.9以下・3.2.6以下・5.0.0-beta.5以下。関連のvite-plusは0.1.23以下
Browser Modeを使っていないなら追加2件は対象外: vitest 単体では @vitest/browser は入らない(実測で確認)。npm ls @vitest/browser で1行判定できる
修正版: 4.x系は4.1.10以降、3.x系は3.2.7以降、5.0ベータ系は5.0.0-beta.6以降。これを満たせば4件すべて解消(旧記載の4.1.8 / 3.2.5 では CVE-2026-73653 が残る)
確認手順: (1)npm ls vitestで直接・推移的依存を洗い出し (2)npm auditでアラート確認 (3)GitHubのDependabot / GHSAアラートを点検
当面の対応: 即時アップデートが最優先。上げられない場合はサーバを127.0.0.1に固定し、新設のallowWrite/allowExecフラグを無効のまま運用し、信頼できないテスト・設定ファイルをCIで実行しない

この記事は「自分のプロジェクトが影響を受けるか」を最短で判定し、「どう直すか」「どうCIで再発を防ぐか」までを一本で完結させることを目的にしている。攻撃の具体的なペイロードは扱わず、防御・検知・修正のコマンドのみを示す。

何が起きたか — Vitestの3つのRCE脆弱性

Vitestは、Viteのトランスフォームパイプラインをそのまま使えることで急速に普及したテストフレームワークだ。Jestからの移行先として定着し、週5300万ダウンロードという規模に達している。その中核に、テスト結果を可視化するUIサーバ、実ブラウザでテストを走らせるBrowser Mode、そしてそれらを仲介するWebSocket RPCが組み込まれている。今回のRCE脆弱性は、この「テストのために立ち上がる常駐サーバ」群を狙ったものだ。

公表のタイムラインは次の通り。2026年5月19日に2件(CVE-2026-47428とCVE-2026-47429)が同時に開示され、いずれも@hi-ogawa氏が報告した。続く6月1日に、Browser ModeのChrome DevTools Protocol(CDP)ブリッジを突くRCE(GHSA-g8mr-85jm-7xhm)が@sheremet-va氏(Vitestメンテナ)により公表された。3件はそれぞれ攻撃面が異なるが、いずれも「サーバが信頼できない相手に到達可能であること」を前提条件として共有している。

報道の起点となったsecurityonline.infoの記事(2026年6月5日)は、3件をまとめて「CVSS 9.8のRCE群」として紹介した。ただし後述するように、公式のGitHub Security Advisory(GHSA)を確認すると、CVE-2026-47428のCVSSは9.6(ユーザー操作が必要なためAC/UIの評価が異なる)であり、修正バージョンもアドバイザリごとに異なる。本記事は一次ソースであるGHSAの数値を採用している。

npmエコシステムを狙う攻撃の最近の流れは、Microsoftが警告したnpmサプライチェーン侵害|redhat-cloud-services 31パッケージに自己増殖ワーム「Miasma」でも詳述している。今回のVitest脆弱性は「悪意あるパッケージの混入」ではなく「正規パッケージの設計上の欠陥」だが、依存ツリーの可視化と継続監視という対策の方向性は共通する。

攻撃が成立する3つの経路

3件の脆弱性が、それぞれどの経路でコード実行に至るかを整理しておく。重要なのは、どれも「攻撃者がVitestのサーバ機能に到達できる」ことが起点になっている点だ。

CVE-2026-47428(otelCarrierスクリプト挿入): Browser ModeがotelCarrierクエリパラメータをサニタイズせずにインラインのモジュールスクリプトへ埋め込んでいた。攻撃者が細工したブラウザランナーURLを開かせると、Vitestサーバのオリジン上で任意のJavaScriptが実行され、露出したVITEST_API_TOKENと連鎖させることでサーバサイドのコード実行につながり得る。被害者によるURLオープン(ユーザー操作)が必要
CVE-2026-47429(UIサーバの不正ファイルアクセス): UIサーバの/__vitest_attachment__ハンドラが、非推奨のisFileServingAllowedを誤った順序で使っていたため、Windows上で\\?\..\形式のパストラバーサルで検査を回避できた。任意ファイル読み取りに加え、saveTestFileでテストファイルを書き込みrerunで実行する経路を併用するとRCEに至る
CDP経由RCE(GHSA-g8mr-85jm-7xhm): Browser Modeが公開するcdp()関数が、生のChrome DevTools ProtocolメソッドをWebSocket RPC越しにそのまま転送し、しかもallowWrite/allowExecフラグを尊重していなかった。攻撃者はPage.setDownloadBehaviorRuntime.evaluateを悪用してvite.config.tsを上書きし、設定リロード時にNode.jsコードを実行させる

プロンプトインジェクションのように「信頼できない入力が制御に変わる」攻撃クラスは近年急増している。入力検証の発想を整理したい場合はプロンプトインジェクションとは?攻撃手口・実例・防御策をLLM開発者向けに徹底解説|OWASP LLM01も参考になる。

脆弱性の詳細とCVSS評価

4件のRCE脆弱性のCVSS評価とベクトルを並べると、攻撃の性質の違いが見えてくる。いずれもネットワーク経由(AV:N)かつ攻撃複雑度が低い(AC:L)が、CVE-2026-47428だけは被害者の操作を要する(UI:R)ため総合スコアがやや低い。

CVE / GHSA CVSS ベクトル 認証 ユーザー操作 公表
CVE-2026-47428(GHSA-2h32-95rg-cppp) 9.6 AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H 不要 必要(細工URLを開く) 2026-06-01
CVE-2026-47429(GHSA-5xrq-8626-4rwp) 9.8 AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H 不要 不要 2026-06-01
CVE-2026-53633(GHSA-g8mr-85jm-7xhm・CDP経由RCE) 9.8 AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H 不要 不要 2026-06-15
CVE-2026-73653(GHSA-p63j-vcc4-9vmv) 9.4 AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L 不要 不要 2026-07-21

4件に共通するのは、機密性・完全性に「高(H)」が付いている点だ。任意ファイルの読み取り(機密性)と、設定ファイルやテストファイルの書き換え(完全性)が同時に成立する。CVE-2026-73653 だけ可用性が「低(A:L)」で、その分スコアが9.4に留まっている——プロセスを落としきるのではなく、ファイルアクセスの許可ゲートを迂回することが主眼の脆弱性だからだ。

CVE-2026-73653 の中身は、GHSAの表題どおり「Browser Mode の provider commands がファイルアクセスの許可ゲートを迂回する」というものだ。Browser Mode には本来、テストコードから触れるファイルを制限する仕組みがあるが、プロバイダ経由のコマンドがその検査を通らずに実行できてしまう。CVE-2026-53633(CDP経由RCE)が「公開されたAPIに到達できること」を前提にしていたのに対し、こちらは許可ゲートそのものの実装不備である点が異なる。

攻撃フロー(CDP経由RCEの例)

3件のうち最も「テストツールらしからぬ」のがCDP経由RCEだ。Browser ModeがPlaywright ChromiumのようなCDP対応プロバイダを使い、ブラウザAPIサーバを--browser.api.host=0.0.0.0でネットワーク公開し、アクティブなブラウザセッションが存在する——この3条件が揃うと、生成されたランナーページに含まれるAPIトークン・セッションID・プロジェクト名・ルートパスを足がかりに、攻撃者が設定ファイルを書き換えてコード実行に至る。流れを図にすると次のようになる。

flowchart TD A["攻撃者
公開された Browser API に到達"] --> B["ランナーページから
APIトークン/セッションID取得"] B --> C["cdp() で生の CDP メソッドを
WebSocket RPC 越しに送信"] C --> D["Page.setDownloadBehavior +
Runtime.evaluate を悪用"] D --> E["vite.config.ts を上書き"] E --> F["設定リロード時に
Node.js コードが実行 = RCE"] style A fill:#5b2333,color:#fff style F fill:#7a1f2b,color:#fff

この図のポイントは、最終的な実行が「Vitestが自分の設定ファイルを読み込み直す」という正規の動作を通じて起きることだ。つまり、外形上は「Vitestが普通に設定をリロードしただけ」に見える。だからこそ、攻撃面そのものを閉じる(サーバを公開しない、allowExecを無効にする)ことが本質的な対策になる。

影響範囲:影響バージョンと修正バージョン

影響を受けるパッケージとバージョンを、アドバイザリごとに正確に整理する。Vitestはvitest本体と@vitest/browserでアドバイザリが分かれているため、両方を確認する必要がある。

項目 内容
影響パッケージ vitest@vitest/browservite-plus
CVE-2026-47429(vitest本体) 影響: >=4.0.0 <4.1.0 および <3.2.5 / 修正: 4.1.0・3.2.5
CVE-2026-47428(@vitest/browser) 影響: >=4.0.17 <4.1.6 および >=5.0.0-beta.0 <5.0.0-beta.3 / 修正: 4.1.6・5.0.0-beta.3
CVE-2026-53633(CDP経由RCE・@vitest/browser・vite-plus) 影響: @vitest/browser 3.0.0〜3.2.44.0.0〜4.1.75.0.0-beta.0〜5.0.0-beta.3、vite-plus <=0.1.23 / 修正: @vitest/browser 5.0.0-beta.4・4.1.8・3.2.5、vite-plus 0.1.24
CVE-2026-73653(@vitest/browser) 影響: >=4.0.0 <4.1.10<3.2.7>=5.0.0-beta.1 <5.0.0-beta.6 / 修正: 4.1.10・3.2.7・5.0.0-beta.6
攻撃要件(共通) サーバがネットワーク公開(--api.host / --browser.api.host=0.0.0.0)、またはWindows上での実行(47429)、Browser ModeでのCDP対応プロバイダ利用(53633)、Browser Mode のプロバイダコマンド経由(73653)
Browser Mode 未導入なら 後半2件(53633 / 73653)は対象外vitest 単体では @vitest/browser は入らない(実測確認)
4件を一括で塞ぐ目標 4.x系→4.1.10以降、3.x系→3.2.7以降、5.0ベータ系→5.0.0-beta.6以降
**結論として、各系列の 4.1.10 / 3.2.7 / 5.0.0-beta.6 に上げれば4件すべて解消できる**

。CVE-2026-47429はvitest 4.1.0で修正済みだが、CVE-2026-53633(CDP経由RCE)が@vitest/browser 4.1.8を、さらにCVE-2026-73653が4.1.10を要求するため、4.x系で安全といえるラインは4.1.10まで上がった。4.1.8で止めていると CVE-2026-73653 が残る——本記事が当初「安全ライン」として示していた版なので、当時この記事を読んで4.1.8に固定した場合は再度の更新が必要だ。

ソース記事と公式の数値の差分

冒頭で触れた通り、報道の起点となったsecurityonline.infoの記事は3件を「すべてCVSS 9.8、修正版は4.1.6 / 5.0.0-beta.3」とまとめていた。一方、公式GHSAを確認すると、(1)CVE-2026-47428はユーザー操作必須のため9.6であり、(2)修正バージョンはアドバイザリごとに異なり、CVE-2026-47429は4.1.0 / 3.2.5、CDP経由RCEは4.1.8 / 3.2.5 / 5.0.0-beta.4で修正されている。さらに本記事執筆時点でCVE-2026-47429のNVDエントリは「RESERVED(予約済み・詳細未公開)」状態であり、現時点での一次ソースはGitHub Security Advisoryである。数値はすべて公式GHSAに合わせている。

⚡対応確認の手順(重点セクション)

ここからが本記事の中心だ。「自分のプロジェクトが影響を受けるか」を確実に判定する手順を、パッケージマネージャ別に示す。直接依存だけでなく推移的依存(他のツール経由で入っているvitest)も必ず確認する。

Step 1: 自分のプロジェクトで使っているか確認

まずvitestがツリーのどこに、どのバージョンで入っているかを洗い出す。npm lsは推移的依存も含めて表示する。

# npm: 直接依存・推移的依存の両方をツリー表示
npm ls vitest @vitest/browser

# yarn / pnpm: なぜそのバージョンが入っているかを遡る
yarn why vitest
pnpm why vitest

# モノレポは全ワークスペースを横断して確認
pnpm -r exec npm ls vitest

npm lsが「(empty)」を返せばvitestは依存ツリーに存在しない。逆に複数バージョンが並ぶ場合は、推移的依存で古いvitestが残っているサインなので要注意だ。

Step 2: バージョン確認

検出されたvitestが影響バージョン帯(4.1.0未満 / 3.2.5未満 など)かどうかを、宣言(package.json)と実体(lockfile)の両面から確認する。

# 宣言上のバージョンレンジ
grep -E '"vitest"|"@vitest/|"vite"' package.json

# npm: lockfileで「実際に固定されているバージョン」を確認
grep -A 2 '"node_modules/vitest"' package-lock.json

# pnpm / yarn のlockfile
grep -A 3 "vitest@" pnpm-lock.yaml
grep -A 3 'vitest@' yarn.lock

ここで重要なのは、package.json^4.0.0のような幅を持つレンジでも、lockfileで固定された実体が影響帯かどうかで判定するという点だ。lockfileを基準にすること。

Step 3: npm audit / GHSA 確認

npm auditはlockfileとGitHub Advisory Databaseを突き合わせ、既知脆弱性を報告する。CIに組み込みやすい最も手軽な検知手段だ。

# 既知脆弱性の要約
npm audit

# 機械可読な詳細(CI連携やフィルタ用)
npm audit --json | jq '.vulnerabilities | keys'

# 特定リポジトリのGHSAアラートをAPIで取得
gh api graphql -f query='
  query {
    repository(owner:"YOUR_ORG", name:"YOUR_REPO") {
      vulnerabilityAlerts(first: 20, states: OPEN) {
        nodes { securityAdvisory { ghsaId summary severity } }
      }
    }
  }'

npm auditvitest@vitest/browserをHigh/Criticalとして挙げたら、Step 2で確認した実体バージョンと、本記事の影響範囲表を突き合わせる。

ここで実測から分かった注意点が2つある。

vitest だけを監査しても Browser Mode の2件は出ない。 手元で [email protected] 単体をインストールして監査したところ critical は 0件だった。@vitest/[email protected] を追加した途端に CVE-2026-73653 が1件検出される。監査結果がクリーンでも「Browser Mode を使っていないから出ていないだけ」という可能性があるので、npm ls @vitest/browser で導入有無を先に確認しておく。

② npm 11.1.0 では vitest 4.x のインストール自体が失敗することがある。 検証中、npm i [email protected]Cannot read properties of null (reading 'edgesOut') で落ちた。デバッグログを見ると arborist の #loadPeerSet(peer依存の解決)で例外が出ており、vitest 側ではなく npm のバグだった。同じ構成を pnpm で入れると問題なく完了する。監査以前にインストールで詰まったら、パッケージマネージャを変えて切り分けるとよい。

# npm が peer 解決で落ちる場合の切り分け
pnpm install            # 別リゾルバで再現するか確認
pnpm audit --json | jq '.metadata.vulnerabilities'

Step 4: GitHub Dependabot / Security alerts の点検

GitHubを使っているなら、Dependabotアラートが最も網羅的だ。リポジトリの Settings → Code security → Dependabot alerts を開き、vitest関連のアラートが出ていないかを確認する。あわせて、

・Dependabotのセキュリティ更新(自動PR作成)が有効になっているか
・Dependabotの自動マージ設定が、意図せず未レビューのまま走っていないか
・privateリポジトリでDependabotが無効化されたままになっていないか

を点検する。privateリポジトリではDependabotがデフォルト無効のことがあり、見落としの温床になりやすい。

Step 5: 過去のCI実行を遡って汚染を検査

影響バージョンを使っていた期間に、CIが攻撃を受けた痕跡がないかを確認する。特にfork PRから誰でもトリガーできるテスト経路があった場合は重点的に調べる。

・公開リポジトリで、fork PRがvitestを含むテストジョブを起動できる設定だったか(GitHub Actionsのpull_request_targetは特に注意)
・CIログに、vitest起動時の不審な外部通信・想定外のコマンド実行・vite.config.tsの予期せぬ変更がないか
・CI環境のsecret(トークン・APIキー)が、当該期間にローテーションされず露出していなかったか

CIの認証情報が漏れた場合の封じ込めは多層で考える必要がある。トークン窃取を多層で止める——セッション・AI推論・課金まで含めた防御パターンで、漏洩を前提とした被害最小化の設計を解説している。

⚙️ 修正手順

影響を確認したら、修正は基本的に「各系列の最新パッチへ上げる」だけだ。ただし推移的依存とlockfileの扱いで詰まりやすいので、ケース別に示す。

A. シンプルなアップデート

直接依存としてvitestを持つ単一パッケージのプロジェクトなら、これで十分だ。

# 4.x系を使っている場合(3件すべてを塞ぐ 4.1.8 以降へ)
npm install -D vitest@^4.1.8

# Browser Mode を使っている場合は @vitest/browser も明示的に
npm install -D @vitest/browser@^4.1.8

# 推移的依存も含めてlockfileを更新し、再現インストールで固定
npm update vitest @vitest/browser
npm ci

更新後は必ずnpm ls vitestを再実行し、影響帯のバージョンがツリーに残っていないことを確認する。

B. モノレポでの一括更新

pnpm / yarn workspacesやTurborepoでは、ワークスペースをまたいでバージョンが散らばりやすい。-r(recursive)で一括更新するのが確実だ。

# pnpm workspaces: 全ワークスペースのvitestを更新
pnpm -r update vitest@^4.1.8 @vitest/browser@^4.1.8

# yarn workspaces
yarn workspaces foreach -A up vitest@^4.1.8

# 更新後、残存バージョンがないか全ワークスペースを再確認
pnpm -r exec npm ls vitest

pnpm.overrides(package.jsonのpnpm.overrides)やresolutions(yarn)を使えば、推移的依存として入った古いvitestも強制的に修正版へ寄せられる。

{
  "pnpm": {
    "overrides": {
      "vitest@<4.1.8": "4.1.8",
      "@vitest/browser@<4.1.8": "4.1.8"
    }
  }
}

C. すぐにアップデートできない場合の暫定対策

メジャー更新が絡んでテストが壊れるなど、即時更新が難しい場合は攻撃面そのものを閉じる。今回の3件はいずれもサーバの公開を前提とするため、公開をやめれば実害リスクは大きく下がる。

・サーバをlocalhostに固定する: Vitest設定でserverapi.host127.0.0.1に明示し、0.0.0.0バインドをやめる
・新設のallowWrite/allowExecを無効のまま運用する: 修正版ではサーバが非localhostにバインドされると、これらは既定で無効になり、UIは読み取り専用(ブラウザ内コード編集・テスト実行が無効)になる。暫定対策としてもこの状態を維持する
・CIをfork PRから隔離する: pull_request_targetでsecretを露出させない。fork PRのテストはsecretなしの隔離環境で走らせる
・Vitest実行コンテナをサンドボックス化する: ネットワークegressを遮断し、secretへのアクセス権限を最小化する
・信頼できないテストファイル・設定ファイルをCIで実行しない: 外部から差し込まれたvite.config.tsやテストファイルが、レビューなしに走らない経路を断つ

これらはあくまで時間稼ぎだ。恒久対策は修正版へのアップデートであることを忘れないこと。

SCA(Software Composition Analysis)でCIから検知する

今回のような「依存ライブラリの脆弱性」は、人手の棚卸しでは追いきれない。SCAツールをCIに組み込み、影響バージョンがマージされる前に止める仕組みが本質的な再発防止策になる。代表的なツールを比較する。

ツール 強み 料金(目安) OSS / 無料枠 PR自動化
Dependabot GitHub標準・設定が容易・脆弱性更新PRを自動作成 無料 あり(GitHubに同梱) あり(自動PR)
Snyk 詳細スキャンと修正提案・リアルタイム監視 無料枠+有料 OSS無料枠あり あり(Fix PR)
Socket パッケージの実挙動分析(install script・通信先)に強い 無料枠+有料 OSS無料枠あり あり(PRコメント)
GitGuardian シークレット検知+依存スキャンを統合 無料枠+有料 OSS無料枠あり あり
Phylum サプライチェーンの継続監視・ポリシー制御 有料中心 限定的 あり

実務上の順序としては、まずDependabotで「気づける状態」を作るのが最短だ。GitHubリポジトリなら追加コストなしで脆弱性アラートと更新PRが回り始める。dependabot.ymlの最小構成は次の通り。

version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "daily"
    # vitest等の重大更新を優先的に拾う
    open-pull-requests-limit: 10

そのうえで、npm auditをCIの必須チェックにし、High以上を検出したらマージをブロックする。

# High以上の脆弱性があれば非ゼロ終了でCIを止める
npm audit --audit-level=high

Dependabotで通知を受け、npm auditでマージをブロックし、必要に応じてSocketで挙動を確認する——この3層で「影響バージョンが本番に出ない」状態を作れる。

似たパターンで狙われやすい開発ツール

Vitestの今回の脆弱性は、特殊な事故ではない。「開発者の手元やCIで常駐サーバを立ち上げる開発ツール」は、構造的に同じリスクを抱えている。Vitest自身、2025年2月にも類似のRCEを公表していた。

CVE-2025-24964(GHSA-9crc-q9x8-hgqq): Vitest APIサーバが待ち受け中に悪意あるWebサイトを訪れると、Originヘッダ検証と認可の欠如によりCross-site WebSocket Hijacking(CSWSH)が成立し、saveTestFilererunでRCEに至る(2025年2月)
CVE-2025-24963(GHSA-8gvc-j273-4wm5): Browser Modeが任意ファイルを配信してしまう問題(2025年2月)

これらと今回の3件は、いずれも「ローカル前提で作られたサーバ機能が、ネットワークに露出したときに崩れる」という同根の構造を持つ。開発ツール一般に視野を広げると、devサーバ・ビルドツール・テストランナーが攻撃面になる事例は珍しくない。Jest・Mocha・Playwright・Cypress・Vite・esbuildといったツール群も、HMRサーバやインスペクタ、デバッグポートを開く以上、同じ注意が必要だ。

加えて、正規パッケージの欠陥とは別系統で、悪意あるパッケージの混入というnpmサプライチェーン攻撃も並行して激化している。両者は対策の重なりが大きく、依存ツリーの可視化・継続監視・最小権限という基本が効く。

npmサプライチェーン攻撃の具体例と防御はMicrosoftが警告したnpmサプライチェーン侵害|redhat-cloud-services 31パッケージに自己増殖ワーム「Miasma」で詳しく扱っている。

企業向けチェックリストとよくある落とし穴

最後に、組織として今回のVitest脆弱性に対応する際のチェックリストと、現場で頻発する落とし穴をまとめる。

企業向け対応チェックリスト

・全プロジェクトのvitest使用状況を棚卸しする(npm ls / SBOMで横断把握)
・各系列の最新パッチ(4.1.8 / 3.2.5 / 5.0.0-beta.4)へのアップデート計画を立て、デプロイ環境まで反映する
・CI/CDでSCAを自動化し、High以上の脆弱性はPRをブロックする
・セキュリティポリシーに「信頼できないテスト・設定ファイルをCIで実行しない」を明文化する
・Vitestサーバはデフォルトでlocalhostバインド、allowWrite/allowExecは無効を標準とする
・インシデント対応プレイブックに「CI経由でsecretが漏洩した場合」のローテーション手順を含める

よくある落とし穴

推移的依存の見落とし: package.jsonの直接依存だけ更新し、他ツール経由で入った古いvitestを放置する。npm ls vitestで全バージョンを確認すること
環境間の更新漏れ: ローカルでアップデートしたのに、CI環境のlockfileやキャッシュが古いまま。npm ciで再現インストールし、CIキャッシュも更新する
強制fixによる破壊: npm audit fix --forceがメジャーダウングレード/アップグレードを引き起こしテストを壊す。差分を確認してから適用する
Dependabot PRの放置: 自動作成されたセキュリティ更新PRを承認せず溜める。これでは検知しても直っていない
fork PR経由の設定injection: 公開リポジトリでfork PRからvitest設定ファイルが走る経路を見落とす。pull_request_targetの権限を最小化する
privateリポでのDependabot無効化: privateではDependabotが無効のことがあり、アラート自体が出ない。明示的に有効化する

これらはいずれも「直したつもりで直っていない」状態を生む典型例だ。確認→修正→再確認のループを、npm lsnpm auditを軸に回すことが、結局のところ最も確実な対策になる。

まとめ

Vitestの3件のRCE脆弱性(CVE-2026-47428 / CVE-2026-47429 / CDP経由RCE)は、いずれも「テスト用に立ち上がるサーバが、信頼できない相手に届く」状況で発火する。逆に言えば、各系列の最新パッチ(4.1.8 / 3.2.5 / 5.0.0-beta.4)へ上げ、サーバをlocalhostに固定し、SCAをCIに組み込む——この3点を押さえれば、今回の脆弱性は確実に封じられる。NVDの詳細公開を待つ必要はない。GHSAの情報で影響範囲は確定しており、今すぐnpm ls vitestから始められる。

参照ソース

Vitest Security Advisories(公式・GitHub) — 一次ソース。GHSA-2h32-95rg-cppp / GHSA-5xrq-8626-4rwp / GHSA-g8mr-85jm-7xhm / GHSA-p63j-vcc4-9vmv の影響範囲・修正版・CVSSはここを基準にした(2026-08-27 再確認)
CVE-2026-73653: @vitest/browser Browser Mode provider commands bypass the file-access permission gate(GHSA-p63j-vcc4-9vmv)2026-07-21公表の追加1件。CVSS 9.4、修正は 4.1.10 / 3.2.7 / 5.0.0-beta.6(2026-08-27 参照)
GHSA-g8mr-85jm-7xhm: Exposed Browser Mode API Can Proxy CDP and Overwrite Config Files, Leading to RCE — CDP経由RCEの詳細とallowWrite/allowExec緩和策
CVE-2026-47429: When Vitest UI server is listening, arbitrary file can be read and executed(GitHub Advisory Database)
CVE-2026-47428: Vitest browser mode serves unsanitized otelCarrier query parameter as inline script(GitHub Advisory Database)
Vitest Remote Code Execution Vulnerabilities(securityonline.info、報道) — 本記事執筆の起点。CVSS・修正版の表記は公式GHSAを優先して補正した
・npm レジストリ dist-tags および各バージョンの公開日(2026-08-27 実測)/各バージョンを実際にインストールしての監査結果(macOS・Node 22.13.1・pnpm、2026-08-27 実測) </content> </invoke>