最近整理部落格依賴的時候,Dependabot 的一條告警讓我停了下來。
不是常見的「某套件有個小問題」那種提示,而是一行加粗的描述:「當 Vitest UI server 正在監聽時,任意檔案可以被讀取與執行。」編號 CVE-2026-47429,CVSS 9.8,滿級分。
花了些時間研究它,發現這可能是 2026 年前端工具鏈最值得關注的安全事件之一。這篇文章把攻擊怎麼做、為什麼可行、誰會中鏢、該怎麼防,一次講完。
兩行 curl,搬走整台電腦的祕密
先看結論。這個漏洞的攻擊只需要兩行指令。
第一步,向受害開發者電腦上正在運行的 Vitest UI 伺服器要一把 API token:
curl http://localhost:51204/__vitest__/第二步,拿著這把 token,用一個精心構造的路徑,把專案目錄之外的檔案「附帶」出來:
curl "http://localhost:51204/__vitest_attachment__?path=C:\path\to\project\?\..\..\secret.txt&contentType=text/plain&token=$TOKEN"回應的內容,就是 secret.txt 的全文。而這個檔案,位於專案目錄之外。
secret.txt 可以是任何東西:.env 檔裡的資料庫連線字串與第三方服務金鑰、SSH 私鑰、瀏覽器儲存的登入憑證匯出、公司內部文件。對開發者來說,專案目錄之外的世界,往往藏著比專案本身更值錢的東西。
為什麼「讀檔」會升級成「執行程式」
如果故事停在讀檔,這會是一個中規中矩的路徑遍歷漏洞。但官方公告的標題寫的是「可以被讀取與執行」。
拆開 Vitest 的 API 會發現,這個測試框架的伺服器本身內建了兩個強大的功能:把內容存成測試檔案(saveTestFile),以及重新執行測試(rerun)。
把兩個功能串起來,攻擊路徑就完成了:先利用檔案寫入,把一段惡意腳本存成 .test.ts 測試檔;再呼叫 rerun,讓 Vitest 把它當成正規測試執行。從這一刻起,攻擊者在你的電腦上擁有了一個程式碼執行環境。
官方公告的結論寫得很直白:把 Vitest UI 或它的 API 暴露到網路上,等同於直接交出腳本執行權。
洞從哪裡來
漏洞的本體藏在 Vitest 原始碼的一個函式呼叫裡。
Vitest 在服務檔案之前,會呼叫 isFileServingAllowed 來判斷「這個路徑是否允許被讀取」。問題是,這個函式已經被標記為棄用,而且它的使用方式有個致命細節:檢查邏輯假設你會先用 cleanUrl() 把路徑清理乾淨再做判斷,但這段程式碼直接把未清理的路徑丟了進去。
在 Windows 上,路徑支援一種以 \\?\ 開頭的長路徑語法。攻擊者把這個前綴與 ..\ 遍歷組合之後,有缺陷的檢查就整個失效了。官方統計,同樣的檢查缺陷在原始碼中至少散布在六個位置:API 初始化、附件端點、瀏覽器模式的檔案讀寫與快照儲存。
還有一層防護的失效加劇了問題。API token 本該是一道鎖,但這把鎖的鑰匙就掛在同一扇門上:token 可以從同一個伺服器的另一個端點取得。信任邊界沒有分隔,等於大門敞開。
誰會中鏢
官方公告給出的影響條件非常精確,只有兩種人:
第一,明確把 Vitest UI 伺服器暴露到網路的人。使用 --api.host 參數或設定檔中的 api.host 選項,讓伺服器綁定到非本機位址。CVSS 的評分中,攻擊向量是「網路」、攻擊複雜度「低」、不需要任何權限、也不需要受害者互動。換句話說,伺服器一旦對網路開放,攻擊就是一行指令的事。
第二,在 Windows 上執行 Vitest UI 或瀏覽器模式的人。\\?\ 的路徑遍歷是 Windows 專屬的繞過手法,Linux 系統因為不存在名為 ? 的目錄而直接報錯。這意味著大量的 Windows 開發者,即使完全沒有對外開放任何連接埠,也處於檔案讀取的風險面。
這個分布對企業環境是個警訊:Windows 恰好是大多數企業開發機的作業系統。

修復方式與新版內建的保險絲
根本解是升級。這個漏洞在 Vitest 3.2.6 修復,低於此版本都在風險範圍:
npm install -D vitest@latest值得稱許的是,修復版本的 Vitest 也加入了兩條新的設定旗標:allowWrite 與 allowExec。它們直接對應這次漏洞的兩段攻擊路徑:寫入測試檔案、執行測試。當伺服器綁定到非本機位址時,這兩個旗標預設關閉,遠端客戶端不再隱式取得寫檔與執行的能力,UI 也會進入唯讀模式。
需要完整互動功能的開發者,必須主動把旗標打開。這種「預設最小權限」的設計,正是這類開發工具漏洞該有的修法。
除了升級,還有幾個習慣可以降低暴露面:沒有遠端查看需求就不要加 --host;真的需要時用 SSH 通道代替直接開放連接埠;CI 環境一律用 headless 模式,不啟動 UI;開發機的 5100 到 5200 連接埠範圍預設拒絕外部連線。

本站的實際處理
最近整理依賴的過程中,我把本站的測試框架從 Vitest 3.2.7 大版本升級到了 4.1.12。
升級的動機一開始是另一個問題:Vitest 3 鎖定的 tinypool 依賴有兩條 critical 告警,而修復版卡在 Vitest 3 拿不到的版本範圍。升級到 Vitest 4 之後,tinypool 從依賴樹中整個消失,那兩條告警直接斷根。
事後回頭核對安全公告才發現,這次升級順帶把 CVE-2026-47429 也免疫了:Vitest 4 不在受影響範圍內。67 個測試全數通過、設定檔零改動、12 秒跑完。升級的成本,遠低於評估「我們會不會中鏢」的成本。
這也是這類依賴升級最值得投資的地方:當修復版本已經存在,升級的收益是確定的,拖延的成本才是未知數。
不只一個:Vitest 的漏洞家族
整理資料的過程中才發現,CVE-2026-47429 並不是孤例。Vitest 的開發伺服器攻擊面在 2026 年被研究者連續挖出了四個漏洞,組成了一個家族。

| CVE | 攻擊面 | 修復版本 | Vitest 4.1.12 |
|---|---|---|---|
| CVE-2026-47429 | UI 伺服器路徑遍歷與程式碼執行 | 3.2.6 | 免疫 |
| CVE-2026-84373 | 瀏覽器模式與 mocker 路徑遍歷 | 4.1.11 | 免疫 |
| CVE-2026-112950 | 反斜線路徑解析差異 | 近期版 | 免疫 |
| CVE-2026-47428 | 瀏覽器模式的釣魚 URL | 行為防護 | 需使用者留意 |
四個漏洞的共通點一模一樣:開發伺服器把使用者的輸入當作檔案系統路徑,而路徑解析在各平台上又各有眉角。這不是 Vitest 團隊不專業,開發伺服器的攻擊面是前端工具鏈的結構性挑戰,Vite 本身在 2023 年也修過同類的檔案服務遍歷問題。
寫在最後
一天之內,路徑處理以兩種完全不同的面貌出現在我面前:一次是攻擊者手中的武器,一行 curl 讀走專案外的檔案;一次是平台手中防禦過度的規則,檔名含雙點就拒絕服務。
路徑處理是資訊安全最古老的主題之一。從目錄遍歷到 dev server,十幾年過去,它的本質從來沒有變過:任何把使用者輸入當作檔案系統路徑的程式碼,都必須假設有人會試著跳出去。
如果你的團隊還停在 Vitest 3.2.5 或更早,這個週末就是升級的好時機。
常見問題(FAQ)
我只用 Vitest 跑單元測試,也受影響嗎?
不受影響。這個漏洞只存在於 UI 模式啟動的 HTTP 伺服器。vitest run 是純 headless 執行,不開任何連接埠。
我沒有加 host 參數,真的安全嗎?
Mac 與 Linux 使用者若未暴露伺服器,檔案讀取的繞過手法無法觸發。但重執行與寫檔的攻擊鏈與作業系統無關,只要伺服器暴露就有風險。防護建議對三個平台一視同仁:升級、不暴露。
Vitest 4 也受影響嗎?
CVE-2026-47429 的受影響範圍是 Vitest 3.2.6 之前的版本,Vitest 4 不在範圍內。本站升級到 4.1.12 後,Dependabot 的這條告警已自動關閉。
怎麼確認我的專案有沒有中鏢?
兩個檢查:一,package.json 或 lock 檔裡的 vitest 版本是否低於 3.2.6;二,檢查 git 歷史與 CI 日誌有沒有 UI 模式搭配 host 參數的使用痕跡。兩者同時成立才構成實際暴露。















