深藍色背景上的抽象技術插圖:中偏左有一個小型扁平向量套件方塊,一條細琥珀色線向下勾入一個精簡的開發者工作站示意;一束細緻的青色與鋼藍色細絲呈扇形從工作站向右展開,朝鬆散網格上的許多小型圓形節點延伸,其中兩條向上彎回套件方塊,而最右側的一個節點孤零零地獨立、未連接。畫面中沒有出現人物、標誌或文字。OrcaRouter 標誌合成於右下角。
AI Safety Incidents

Tensorlake 的 npm SDK 遭下毒,以竊取 AI 代理憑證——並在你撤銷權杖時清空你的家目錄

作者

Alistair Wren

發佈日期

最新模型 · 20查看全部模型 →
基準測試:Artificial Analysis · 每日更新
返回全部文章

2026 年 10 月 8 日,一個遭投毒的tensorlake版本——這是 Tensorlake 平台(可在隔離沙箱中執行不受信任、由 LLM 生成的程式碼)的 npm SDK——進入了 npm registry。0.5.144 版於 01:12:07 UTC 發布;Socket 的研究人員表示,他們在大約十一分鐘後將其標記出來。這並非經授權的發布。Tensorlake 表示,攻擊者直接將程式碼推送至該公司的 GitHub 儲存庫,並透過專案自身的發布工作流程發布,因此該套件帶有 有效的 npm 來源證明——針對已被投毒的原始碼,簽署的證明顯示其建置位置。該公司表示,該版本上線約 1 小時 40 分鐘,從 01:12 到 02:54 UTC,之後才被 npm 移除。

該酬載不需要匯入,也不需要執行中的代理程式。一個 preinstall 勾點在套件資訊清單中執行了 node lib/setup.mjs,這是一個經過混淆的載入器,會將 Bun 執行環境植入機器,並用它來執行 lib/Math_Symbol.js,這是一個 856,501 位元組的憑證竊取程式與自我傳播蠕蟲。任何對該版本執行一般安裝的人,都會執行它。因為它是該套件的 latest 標籤,所以當它仍上線時,預設安裝會解析到該版本。

這份紀錄之所以值得留存,不是因為酬載的大小——Shai-Hulud 家族過去已有紀錄。重點在於目標清單。除了 npm 與 GitHub 權杖、AWS 憑證、Kubernetes 與 Vault 機密、SSH 金鑰,.env檔案、瀏覽器密碼與加密貨幣錢包之外,這個建置特別蒐集了 AI 開發工具設定與 MCP 檔案——與之相關的包括Claude Code、Cursor、Kiro、Windsurf 與 Zed,根據 Socket。它還把自己的 .claude/settings.json 和 .vscode/tasks.json 寫入它能觸及的儲存庫,這樣當開發者下次在 Claude Code 或 VS Code 開啟該專案時,程式碼就會再次執行。這是一場直接瞄準人們用來建構代理程式的機器的供應鏈攻擊。

發行版是如何從維護者的帳號流出的

Socket、SafeDep 和 Aikido 各自在 10 月 8 日發表了自己的分析,且他們對該機制的說法一致。這筆紀錄在檔案庫中的信心評級為 A,未被標記為有爭議,且來源中沒有發現任何與它們相矛盾的內容。

SafeDep 的報告將八筆提交追溯至該儲存庫的 main 分支,時間介於 UTC 01:20 至 03:57,於 10 月 7 日,這些提交被歸因於一個儲存庫管理員帳號,且是透過 GitHub 網頁介面所做。該存檔指為第一個惡意提交的是 41b38f0,這是 10 月 7 日 UTC 03:44:48 涉及四個檔案的修訂,其提交訊息為「Add files via upload」,並帶有 GitHub 的 已驗證 簽章——GitHub 會簽署在其自家網頁編輯器中做出的提交,因此「已驗證」記錄的是編輯介面,而非個人。根據 GitHub API,該提交除了 typescript/lib/Math_Symbol.js 和 typescript/lib/setup.mjs 之外並未觸及任何檔案:只有該酬載,別無其他。

SafeDep 對操作者的行為提出了一種解讀,並將其標示為自身的推論:preinstall 鉤子的第一次編輯破壞了該檔案的 JSON 語法,十九分鐘後隨之而來的是一個修復提交;它形容這與一個人在瀏覽器中編輯檔案、而非透過腳本化管線的情況相符。Socket、SafeDep、Aikido、StepSecurity 或 Tensorlake 所發布的任何內容,均未指明維護者帳號遭接管所使用的方法。

攻擊者不需要 npm token。SafeDep 報告指出,該帳號於 10 月 8 日 00:08 UTC 手動啟動了專案的 publish_npm.yaml 工作流程;建置紀錄顯示已發佈的 tarball 內含酬載檔案。該發佈使用了 npm 受信任發佈,而同一輪執行所發佈的同系列 tensorlake-native-* 套件帶有有效的 SLSA 來源證明——對於遭汙染原始碼的建置而言,該證明確實有效。該發佈在工作流程啟動十二分鐘後上線。

封存記錄顯示,該儲存庫遭到入侵約20 小時之後才觸發發布——下方時間軸逐筆提交所鋪陳出的這段空檔——這與 Tensorlake 自身所述一致:攻擊者是「透過我們自家的發布工作流程」發布的。

酬載在執行後做了什麼

A screenshot of a card titled 'A credential stealer with an AI-tooling list', kicked 'tensorlake@0.5.144 · what the payload collected', subtitled 'Per Socket, SafeDep and Tensorlake's advisory — grouped by what each collector reached for'. Three columns of paired labels sit side by side. 'Publishing and source control' lists npm tokens from .npmrc, the token API and the OIDC exchange; GitHub tokens with a repository and workflow permission check; GitHub Actions secrets read from Runner.Worker memory; and cryptocurrency browser wallets across 14 extensions. 'AI agent tooling' lists ~/.claude.json for Claude Code settings; ~/.kiro/settings/mcp.json for Kiro MCP config; .cursor, Windsurf and Zed config and MCP files; and .claude/settings.json and .vscode/tasks.json written back into reachable repositories. 'Cloud, cluster and endpoint' lists AWS via STS, SSM Parameter Store and Secrets Manager; Kubernetes service-account tokens and kubeconfigs; HashiCorp Vault at 127.0.0.1:8200; SSH and GPG keys, .env files and Docker and CLI files; the Wallets row, wallet.dat, Exodus, Electrum and MetaMask; and saved passwords via a downloaded HackBrowserData binary. A footer reads 'Collector list per Socket's initial assessment, SafeDep's decoded payload analysis and the Tensorlake advisory (GHSA-8g63-53c9-65j2). Socket flags AI development tooling for Claude Code, Cursor, Kiro, Windsurf and Zed by name.'

Socket 的評估指出,其會從本機檔案、CI 環境、Kubernetes 與 Vault 來源中蒐集資料,並涉及資料外洩、持續潛伏,以及執行遠端提供的程式碼。lib/setup.mjs會從官方 GitHub 發行版下載 Bun 1.3.13,並用它來執行該蠕蟲,而且它在 CI 執行器上會結束——目標是開發人員的電腦,而非建置代理程式。SafeDep 亦發現該酬載帶有同一個載入器的一份單純副本,並將其植入其他套件與儲存庫中。

該酬載執行了三層混淆,而 SafeDep 在未執行樣本的情況下將其解碼:一個混淆器字串陣列、一個使用鹽值 svksjrhjkcejg 的自訂加密法——與先前 keyv 入侵事件中所回報的完全相同——以及對十一個內嵌檔案(包括指令碼、鉤子與兩把 RSA 公開金鑰)使用 AES-256-GCM。其第一行帶有建置標籤 WORMTAG='tensrlake',拼寫錯誤,這正是 SafeDep 用來區分此建置與持續進行中的重複感染的方式。

除了 AI 工具配置之外,收集清單既廣泛又具體:~/.claude.json 和 ~/.kiro/settings/mcp.json用於代理程式設定;SSH 金鑰、雲端 CLI 檔案、.npmrc、.env、Docker 與 Kubernetes 檔案,以及 shell 歷史紀錄;wallet.dat以及 Exodus、Electrum 與 Ledger Live 資料,還有 MetaMask、Phantom 等瀏覽器錢包擴充功能;AWS STS、SSM Parameter Store 與 Secrets Manager;從 Runner.Worker 處理程序記憶體讀取的 GitHub Actions 密鑰;以及 Kubernetes 服務帳戶權杖與 Vault 權杖。它從 iseekaigogo[.]com/hbd/<platform> 取得各平台專屬的執行檔,並以「dump -b all -c password -f json」這些參數執行——這些參數與 HackBrowserData 工具相符,不過 SafeDep 指出該執行檔本身並未被尋獲,並將此辨識標記為推論。SafeDep 補充,該蠕蟲會在俄文地區設定下結束。

A screenshot of a card titled 'Persistence, resolution, and the wipe trigger', kicked 'tensorlake@0.5.144 · staying power', subtitled 'The release was removed in under two hours; the implant it installed was built to outlive that.' Three columns sit side by side. 'Persistence: gh-token-monitor' lists a systemd user service on Linux, a LaunchAgent com.user.gh-token-monitor on macOS, a scheduled task with a PowerShell monitor on Windows, and files left behind in ~/.local/bin, ~/.config and %LOCALAPPDATA%. 'Endpoint resolution order' lists, in numbered order, the primary endpoint iseekaigogo[.]com:443/router; an Ethereum contract 0xb614155Fd88...1Df091B9; the public RPC endpoints that contract is read through, given as ~30 by Socket and 35 by SafeDep; signed GitHub commits found by the string thebeautifulmarchoftime; and public dead-drop repositories described as 'Shai-Hulud: Here We Go Again'. 'The dead-man switch' lists a poll of api.github.com/user every 60s, for 24 hours, firing on a 40x response to that token, with the effect rm -rf ~/ (advisory: home dir), armed only if the account has no orgs, and the order that matters: remove monitor, then revoke. A footer reads 'Per Socket's blog and SafeDep's analysis, with the C2 endpoint, the contract and the gh-token-monitor service confirmed in Tensorlake's advisory. Socket and SafeDep give different counts of the public RPC endpoints the contract is read through.'

持續性是刻意為之的。Socket 在談到該酬載時寫道:「這種組合讓風險擴及單一被竊取的 API 金鑰之外」,並補充說「即使受影響的相依套件遭到移除,持續性仍可讓攻擊者保有存取權」。SafeDep 指出,該蠕蟲以 git 作者 claude 的名義提交 Claude Code 與 VS Code 的 hook 檔案,並植入一個「Run Copilot」工作流程,該流程會傾印所有儲存庫機密,然後刪除該次執行與該分支。Tensorlake 的公告提醒開發者檢查日誌時,留意名為 dependabot/github_actions/format/setup-formatter 的分支,以及以同一身分提交的提交紀錄。

Spread 靠竊取來的權杖運作,而非靠第二個漏洞。Socket 表示,這隻蠕蟲會列舉與受害者發布身分相關的套件,建立 Sigstore 來源證明,並重新發布遭投毒的版本。SafeDep 補充了一個細節:在 CI 內,它會新增一個 git 相依項目,並以 Fulcio 和 Rekor 簽署其輸出——因此它接下來發布的套件上的來源證明,就和 0.5.144 上的來源證明一樣有效。

發佈前的二十小時

第一個惡意提交與該發布版本之間的落差,是時間線上解釋一個遭投毒的套件如何帶有有效來源證明的那一部分。所有時間均為 UTC;提交時間來自 SafeDep 與 GitHub API,而發布、移除與公告時間則來自 Tensorlake。

A screenshot of a card titled 'Compromised source in the repo, then one manual publish', kicked 'tensorlake@0.5.144 · the ~20-hour window', subtitled 'All times UTC. Commit times per SafeDep's timeline and the GitHub API; publish and removal times per the Tensorlake advisory.' Three columns sit side by side. '7 October 2026 — source, main branch' lists 01:20 setup.mjs and Math_Symbol.js added; 01:24 the preinstall script added; 01:43 package.json JSON repaired; 02:13 to 03:44 four loader and payload revisions; 03:44 commit 41b38f0, the payload commit; 03:57 the version set to 0.5.144. '8 October 2026 — release and removal' lists 00:08 publish_npm.yaml started by hand; 01:12:07 version 0.5.144 published to npm; 01:22:02 issue #1014 opened by StepSecurity; 01:23:10 flagged by Socket, about eleven minutes in; 02:54 the version removed, after roughly 1h 40m live; 20:24 version 0.5.145 published next. '9 October 2026 — disclosure closed' lists advisory GHSA-8g63-53c9-65j2; pull request #1016, source reverted and 0.5.145 cut; issue #1014 closed as completed; 0.5.143 as the last version stated unaffected; and no usage seen, per Tensorlake's user-agent telemetry. A footer reads 'The ~20-hour gap between the first rogue commit and the publish is SafeDep's commit timeline, and matches the archive's own upstream record.'

綜觀整起事件:酬載檔案在 10 月 7 日進入儲存庫的主分支,當天清晨 03:57 版本被設為 0.5.144,而直到隔天 00:08 有個帳號手動啟動發佈工作流程,才發佈了東西。遭入侵的原始碼在分支裡待了大約二十個小時,專案自己的管線才建置了它。這就是針對發佈路徑的攻擊全貌——沒有偽造的證明,也沒有重新發佈的 tarball。這份來源證明對於一次本不該出現在分支裡的程式碼建置,記述得準確無誤。

失效安全開關

這起事件中,在先前 npm 入侵事件裡沒有先例的部分,是受害者正確反應之後發生的事。SafeDep 報告指出,如果被竊取的 GitHub 權杖屬於沒有組織的帳號,該蠕蟲會安裝 gh-token-monitor:一項會輪詢 api.github.com/user 的服務,使用該被竊取的權杖,每 60 秒一次,持續 24 小時。當 GitHub 傳回 40x——正如權杖一被撤銷時所發生的情況——該監控程式會執行攻擊者提供的處理常式,並刪除使用者的家目錄。

Socket 將同一個元件描述為使用一個 PowerShell 監控程式,該監控程式透過 ONLOGON 排程工作持續存在,並透過 Invoke-Expression 執行攻擊者提供的處理常式,並指出該程式碼帶有字面字串 "IfYouRevokeThisTokenItWillWipeTheComputerOfTheOwner",此字串曾在先前的 Shai-Hulud 攻擊浪潮中出現。SafeDep 將該處理常式命名為 rm -rf ~/。Socket 的措辭明確表示,無論撤銷是在哪裡發生,這都會觸發;監控程式是本地的,而撤銷並非如此。全部四個來源 —— Socket、SafeDep、StepSecurity 以及 Tensorlake 自家的安全公告 —— 都給出相同的操作順序:先移除監控程式,再撤銷。

什麼是已確立的,什麼僅屬推論

檔案庫記載,沒有已確認的傷害就本條目而言,且來源支持這一點,而不只是未能反駁它。

• Tensorlake 表示該版本並無任何使用紀錄。其公告指出,該公司透過使用者代理標頭監控 SDK 的使用情況,且「自該版本發布以來,尚未見到任何使用該版本的情形」。這是廠商針對自身遙測資料所作的陳述,並非經稽核的統計數字。

• 下載數字並非感染數量。Socket 指出該套件每週下載量約為12,000 次,並註明這描述的是該套件的整體使用情形,而非惡意版本的下載次數;SafeDep 則引用同一個套件每月約106,000 次下載。這兩者都不是 0.5.144 曾在任何地方執行過的證據。Socket 的標記發布時間窗與 Tensorlake 的兩小時時間窗,都與一個在擴散前就已被移除的版本相符。

• 酬載本身的程式錯誤可能限制了它。 SafeDep 發現了兩個問題:npm 傳播路徑需要 ./dist/Math_Symbol.js 存在於磁碟上,否則就會停止;而植入的載入器會尋找 ai_init.js,但蠕蟲卻寫入 math_init.js。SafeDep 將這些發現標示為傳播上的限制,而文章將它們視為某一項分析對程式碼的解讀,而非保證沒有任何東西傳播出去。

• 出處證明是真實的。這並非有爭議的說法:npm 出處證明會記錄套件在何處建置、由哪個工作流程建置,而在這個案例中,它記錄的是事實——該專案自家的發布工作流程,建置了遭汙染的原始碼。Tensorlake 的公告直言不諱地這麼寫道:「該套件帶有有效的 npm 出處證明」。Socket 也明白指出同一點,表示出處證明「說明了套件在哪裡建置,但並未說明程式碼是安全的」。

目前流傳的若干細節屬於單一分析來源的說法,應以此角度理解。攻擊者取得維護者帳號的具體機制,尚未由任何調查公司或 Tensorlake 公布。以太坊合約位址及其在解析端點時所扮演的角色,出現在 SafeDep 與 Socket 的敘述中——Socket 表示,該酬載透過一份以太坊合約來解析其端點,使用約 30 個公開 RPC 端點,並以 GitHub 作為備援;而 SafeDep 則將 RPC 數量定為 35 個,並回報該合約在 10 月 8 日回傳 iseekaigogo.com——Tensorlake 也在其安全公告中確認了該端點與該合約。兩份報告中的確切 RPC 數量有所不同;設計架構則無差異。

公開紀錄中有一個缺口值得直白說明。本文檢視過的來源,沒有任何一個回報已確認的下游感染——也就是另一個套件或儲存庫,被這隻蠕蟲利用從此處竊取的憑證所毒害。傳播程式碼確實存在,SafeDep 也已讀過;它是否造成了第二個受害者,則不得而知。

之後有什麼改變?

回應比事件本身更快且更協調。

• 該版本已消失。根據 Tensorlake,它曾於 10 月 8 日 UTC 01:12 至 02:54 期間上線;SafeDep 指出 npm 已將其移除。為撰寫本文,於 10 月 10 日直接查詢 npm registry 時,0.5.144已不再出現在該套件已發佈的版本中,且該套件的最新標籤為 0.5.148。Tensorlake 的公告建議開發人員使用 0.5.143 作為最後一個未受影響的版本。

• 該公告已隨修復一同發布。Tensorlake 的 GHSA-8g63-53c9-65j2 公告指出,PyPI 與 crates.io tensorlake 套件以及 tensorlake CLI 並未受到影響——只有 npm 套件受到影響——且 0.5.143 及更早版本不受影響。SafeDep 報告指出,維護者已在提取要求 #1016 中還原原始碼,並發布了 0.5.145。

• 這起披露討論串異常完整。StepSecurity 的研究員 Ashish Kurmi 開設了 GitHub 議題#1014,時間為10 月 8 日 01:22:02 UTC——約在發布後十分鐘——並指出 StepSecurity 自己針對其所稱「hostage token」蠕蟲所做的說明。Aikido 的 Oliver Smith 留言指出,該酬載是在提交 41b38f0中引入,並將其識別為新的 Shai-Hulud 資訊竊取程式。維護者 David Lorenzo——npm 套件上列出的維護者身分為 calavera——回覆於10 月 9 日,確認了該安全公告,並於同日將該議題以已完成結案。議題標題本身也反映了證據:它最初是一份「可能為惡意」的通報,到結案時已更名,將該酬載直接描述為惡意,不再有任何保留。

• 這起事件所屬的攻擊行動規模比這個套件更大。Socket、SafeDep 與 Aikido 都將 Tensorlake 的發行版本歸入 ChainDrop / Mini Shai-Hulud 攻擊浪潮,該波攻擊最早於 2026 年 8 月初被記錄,其 npm 受害者包括 keyv、cacheable及相關套件。Tensorlake 的公告也如此表示,並引用 Socket、SafeDep 與 Aikido 的說法。

Socket 對任何安裝了該版本者的指引是,應將主機視為已遭入侵:檢查 lockfile、manifest 與該版本的建置日誌;先移除 gh-token-monitor 服務,且必須在撤銷任何權杖之前完成;接著在乾淨的機器上輪替憑證。Tensorlake 的公告補充了相同的處理順序,並建議檢查外洩權杖可能寫入的套件登錄庫與儲存庫,看看是否有非預期的發行版本。Aikido 的文章建議設定 ignore-scripts=true 於 .npmrc 中,以阻擋安裝掛鉤,並將任何執行過該掛鉤的機器視為已完全遭入侵。

這是一筆記錄,由他人報導,並在此引用他們作為出處。其他有紀錄的代理事件,各自有其來源、嚴重性、信心等級與爭議標記,都收錄在 AI 事件檔案庫——因此,針對代理工具而來的供應鏈入侵,可以與其餘實際發生過的事件並列閱讀。