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 等,是會直接造成財務損失的竊密程式。
真正的破口:沒人收回的權限
套件規模看著嚇人,但根因一點都不高科技。出事的帳號 ehindero 在 2024 年底到 2025 年初還有正常發佈紀錄,之後就沒再動;問題是 npm 不會因為閒置就收回 scope 的發佈權限,一個放著大約 16 個月的舊憑證,就足以推送到整個 scope 底下的每一個套件。Snyk 把話講得很白:真正的根因是專案的權限衛生,不是什麼零時差漏洞。
@mastra/core 這種週下載約 91 萬、整個 Mastra 生態合計週下載超過 110 萬的套件,背後的破口竟然是一把沒人記得要拔掉的鑰匙。能不能攻破,跟有沒有人把鑰匙收回來,是兩件事,這次是後者沒做。
AI 生態正在重演 IT 三十年的老問題
這就是我看這件事最在意的地方。Mastra 投毒事件,是 AI 生態系開始重演企業 IT 三十年的老問題;而它延伸出來的,是 AI 供應鏈最大的漏洞,不是程式碼,而是沒人記得的權限。
離職的人權限沒收、放著不管的存取憑證、沒人回頭審的預設值,這些在傳統 IT 治理裡是講到爛的東西,可是換到 AI 開發這條新管道,又從頭發生一次。我先前寫 ServiceNow 那篇講的是同一種病:一個沒人回頭檢查的預設值,功能照跑,就不會有人多看一眼,直到資料被查走。Mastra 這次只是把場景換成 npm 套件供應鏈,病灶一樣。
而且 AI 開發把它放大了。每一個接進來的外部相依,都該被當成一個新的權限治理對象,但用 AI 一句話就拉進一堆套件的速度,讓相依清單長得比任何人盤得動的還快。沒人記得自己的專案到底拉進了哪些套件、哪些舊帳號還握著發佈權,這就是新破口的養成方式。
三件治理事,現在就能盤
講防禦,不講怎麼攻擊。這次事件其實對應三件可以馬上做的治理事。
第一,定期盤點套件 scope 與 token 權限,離職即撤。誰還握著發佈權、哪些 token 還活著、哪些貢獻者其實早就不在了,要列冊定期清。這正是 Mastra 沒做到的那一格,也是整起事件的起點。第二,鎖版本,不要用浮動範圍。鎖定或釘住套件版本,避免 npm 自動把相依解析到被投毒的版本;CI 裡開 provenance 與 lockfile 稽核,讓每個進到建置流程的套件來源可驗證。這次就是 ^ 這個浮動範圍把武器化版本自動拉進來的。第三,先想清楚出事要輪換哪些憑證。一旦主機可能被碰過,該輪換的不只是 npm token,還有雲端金鑰、CI 的各種 secret、LLM 與其他 API 金鑰、GitHub token 與 SSH 金鑰,因為這段惡意程式碰得到的範圍就是這麼廣。
順序不要倒。先定義這個相依要解決什麼、誰該有發佈權,再決定開放範圍,不是先全開、出事才回頭補。
那這次是誰幹的?
有幾家廠商把這次的手法跟北韓相關的攻擊團體連在一起。Orca 指出這次的 tradecraft 與 Sapphire Sleet(也就是 BlueNoroff)有重疊,而這個重疊是微軟先注意到的。但要誠實補一句:Snyk 明說這起事件本身的歸因尚未確認,不會進一步臆測。對防守方來說,是不是某個特定團體幹的,其實不影響該補的洞。可信度靠的是落地流程的品質,不是猜對是誰。
常見問題
我沒有用 Mastra,這件事跟我有關嗎?
有關。重點從來不是 Mastra 這個框架,是「離職貢獻者的權限沒被收回」這個模式。任何用 npm、用套件管理器的團隊,只要有人離開後帳號和 token 沒清,就會踩到同一個雷。Mastra 只是這個月最大的例子。
鎖了版本就安全了嗎?
鎖版本能擋掉這次這種「浮動範圍自動拉到投毒版本」的攻擊,是該做的第一道。但它不是萬靈丹,還要搭配權限盤點與 CI 的來源驗證。真正的根因是權限殘留,版本鎖定處理的是傳播路徑,兩邊都要顧。
如果我可能裝到了,要換哪些金鑰?
把主機當成可能被碰過來處理。npm token、GitHub token、雲端供應商金鑰、CI 的各種 secret、LLM 與其他 API 金鑰、SSH 金鑰,全部輪換一次;裝過的環境先回滾到事發前的套件版本,再清掉常駐痕跡。寧可多換,不要賭它沒外洩。
結語
一個放了 16 個月、沒人記得的帳號,撬開了週下載破百萬的套件生態。AI 工具讓相依長得更快、讓套件接得更多,可是「誰還握著鑰匙」這個問題,沒有任何模型會替你回答。先把自家的 scope 權限、token、離職帳號盤一次,把版本鎖好,想清楚出事要換什麼。這些事都不性感,但破口就在這裡。
參考來源
- 144 Mastra npm Packages Compromised via Supply Chain Attack(Orca Security)142 個 @mastra 套件+mastra/create-mastra 共 144 個、6/17 UTC 01:12–02:39 88 分鐘、ehindero 帳號、@mastra/core 約 918K 週下載、合計逾 110 萬、postinstall 關 TLS 自刪、tradecraft 與 Sapphire Sleet/BlueNoroff 重疊(微軟注意到)
- Mastra npm Supply Chain Attack: 140+ Packages Backdoored via easy-day-js Typosquat(StepSecurity)easy-day-js 為 dayjs 的 typosquat、6/16 乾淨 1.11.21 後 6/17 武器化 1.11.22、^1.11.21 semver 自動解析、鎖版本與輪換憑證建議
- A forgotten contributor account compromised the entire Mastra npm package scope(Snyk)ehindero 約 16 個月閒置、npm 不會因閒置收回 scope 權限、Project hygiene not a zero-day、歸因未確認不臆測、輪換 cloud/CI/LLM API/npm/SSH 等所有憑證
- Over 140 popular Mastra npm Packages Hit by Supply Chain Attack(Aikido Security)第二階段常駐程式鎖定逾 160 個瀏覽器加密貨幣錢包外掛(MetaMask、Keplr、Coinbase 等)、^1.11.21 caret 解析自動拉到惡意 1.11.22