6 月 17 日凌晨,有人用一個早就沒在維護的前貢獻者帳號,在 88 分鐘內把 AI 開發框架 Mastra 的 npm 套件生態整批改寫。142 個 @mastra 套件被重新發佈、塞進同一個惡意相依,連同 mastra 與 create-mastra 共 144 個套件受影響,時間落在 UTC 01:12 到 02:39 這 88 分鐘內。這件事真正該記住的,不是手法多新,而是一個沒人回頭看的問題:離職貢獻者的發佈權限,從頭到尾沒有被收回。

88 分鐘,144 個套件

先把經過講清楚。攻擊者前一天先發了一個乾淨的誘餌,套件名叫 easy-day-js,是知名日期函式庫 dayjs 的 typosquat(仿冒名稱),連作者資訊、首頁、版本號都照抄;第一版 1.11.21 是無害的,隔天才發出夾帶惡意程式的 1.11.22 並標成 latest。手法的關鍵在版本範圍:因為這些套件把相依寫成 ^1.11.21,npm 的 semver 解析會在安裝當下自動抓到符合範圍的最新版,等於把武器化的那一版直接拉進來,不需要任何人手動操作

惡意的那一版藏了一段安裝後(postinstall)腳本。它會先關掉 TLS 憑證驗證、把安裝路徑寫進暫存檔當作回報信標、生出背景常駐程式,跑完再把 setup.cjs 從套件樹裡刪掉,抹掉最主要的鑑識痕跡。它要的東西也很直接:第二階段以常駐背景程式蒐集系統資訊,鎖定超過 160 個瀏覽器加密貨幣錢包外掛,包含 MetaMask、Keplr、Coinbase 等,是會直接造成財務損失的竊密程式。

攻擊者在 88 分鐘內自動化把 144 個 npm 套件重新發佈、塞進惡意相依

真正的破口:沒人收回的權限

套件規模看著嚇人,但根因一點都不高科技。出事的帳號 ehindero 在 2024 年底到 2025 年初還有正常發佈紀錄,之後就沒再動;問題是 npm 不會因為閒置就收回 scope 的發佈權限,一個放著大約 16 個月的舊憑證,就足以推送到整個 scope 底下的每一個套件。Snyk 把話講得很白:真正的根因是專案的權限衛生,不是什麼零時差漏洞

@mastra/core 這種週下載約 91 萬、整個 Mastra 生態合計週下載超過 110 萬的套件,背後的破口竟然是一把沒人記得要拔掉的鑰匙。能不能攻破,跟有沒有人把鑰匙收回來,是兩件事,這次是後者沒做。

一把沒人記得收回的鑰匙,對應離職貢獻者從沒被撤掉的 npm 發佈權限

AI 生態正在重演 IT 三十年的老問題

這就是我看這件事最在意的地方。Mastra 投毒事件,是 AI 生態系開始重演企業 IT 三十年的老問題;而它延伸出來的,是 AI 供應鏈最大的漏洞,不是程式碼,而是沒人記得的權限。

離職的人權限沒收、放著不管的存取憑證、沒人回頭審的預設值,這些在傳統 IT 治理裡是講到爛的東西,可是換到 AI 開發這條新管道,又從頭發生一次。我先前寫 ServiceNow 那篇講的是同一種病:一個沒人回頭檢查的預設值,功能照跑,就不會有人多看一眼,直到資料被查走。Mastra 這次只是把場景換成 npm 套件供應鏈,病灶一樣。

而且 AI 開發把它放大了。每一個接進來的外部相依,都該被當成一個新的權限治理對象,但用 AI 一句話就拉進一堆套件的速度,讓相依清單長得比任何人盤得動的還快。沒人記得自己的專案到底拉進了哪些套件、哪些舊帳號還握著發佈權,這就是新破口的養成方式。

盤根錯節的相依網路,AI 開發把舊的套件與權限風險放大成新的供應鏈破口

三件治理事,現在就能盤

講防禦,不講怎麼攻擊。這次事件其實對應三件可以馬上做的治理事。

第一,定期盤點套件 scope 與 token 權限,離職即撤。誰還握著發佈權、哪些 token 還活著、哪些貢獻者其實早就不在了,要列冊定期清。這正是 Mastra 沒做到的那一格,也是整起事件的起點。第二,鎖版本,不要用浮動範圍。鎖定或釘住套件版本,避免 npm 自動把相依解析到被投毒的版本;CI 裡開 provenance 與 lockfile 稽核,讓每個進到建置流程的套件來源可驗證。這次就是 ^ 這個浮動範圍把武器化版本自動拉進來的。第三,先想清楚出事要輪換哪些憑證。一旦主機可能被碰過,該輪換的不只是 npm token,還有雲端金鑰、CI 的各種 secret、LLM 與其他 API 金鑰、GitHub token 與 SSH 金鑰,因為這段惡意程式碰得到的範圍就是這麼廣。

順序不要倒。先定義這個相依要解決什麼、誰該有發佈權,再決定開放範圍,不是先全開、出事才回頭補。

開發者盤點套件 scope 與 token 權限、鎖版本、開啟 lockfile 稽核的治理清單

那這次是誰幹的?

有幾家廠商把這次的手法跟北韓相關的攻擊團體連在一起。Orca 指出這次的 tradecraft 與 Sapphire Sleet(也就是 BlueNoroff)有重疊,而這個重疊是微軟先注意到的。但要誠實補一句:Snyk 明說這起事件本身的歸因尚未確認,不會進一步臆測。對防守方來說,是不是某個特定團體幹的,其實不影響該補的洞。可信度靠的是落地流程的品質,不是猜對是誰

出事後輪換 npm、GitHub、雲端與 LLM API 等所有憑證的示意

常見問題

我沒有用 Mastra,這件事跟我有關嗎?
有關。重點從來不是 Mastra 這個框架,是「離職貢獻者的權限沒被收回」這個模式。任何用 npm、用套件管理器的團隊,只要有人離開後帳號和 token 沒清,就會踩到同一個雷。Mastra 只是這個月最大的例子。

鎖了版本就安全了嗎?
鎖版本能擋掉這次這種「浮動範圍自動拉到投毒版本」的攻擊,是該做的第一道。但它不是萬靈丹,還要搭配權限盤點與 CI 的來源驗證。真正的根因是權限殘留,版本鎖定處理的是傳播路徑,兩邊都要顧。

如果我可能裝到了,要換哪些金鑰?
把主機當成可能被碰過來處理。npm token、GitHub token、雲端供應商金鑰、CI 的各種 secret、LLM 與其他 API 金鑰、SSH 金鑰,全部輪換一次;裝過的環境先回滾到事發前的套件版本,再清掉常駐痕跡。寧可多換,不要賭它沒外洩。

結語

一個放了 16 個月、沒人記得的帳號,撬開了週下載破百萬的套件生態。AI 工具讓相依長得更快、讓套件接得更多,可是「誰還握著鑰匙」這個問題,沒有任何模型會替你回答。先把自家的 scope 權限、token、離職帳號盤一次,把版本鎖好,想清楚出事要換什麼。這些事都不性感,但破口就在這裡。