跳到正文
DEV Community· quietkernel·· 3 小時前精選AI 評分76

npm 蠕蟲如何竊取憑證,以及憑證輪替次序

How npm worms steal your credentials, and the order to rotate them in

AI 導讀

npm 蠕蟲可利用套件生命週期指令碼竊取開發者憑證,文章提出遭入侵後按風險安排的輪替次序。npm 的 preinstall、install 和 postinstall 指令碼會以用戶權限執行,能讀取用戶可讀檔案並發出網絡請求。作者建議先隔離及清除惡意程式,再撤銷 npm 等套件 registry token,之後處理 GitHub、雲端、CI 和其他憑證,並在乾淨裝置上進行輪替。

推薦理由

文章按蠕蟲的散播風險排列憑證輪替步驟,解釋為何應先清除持續執行的惡意程式,再撤銷套件 registry token。

正文 · 繁體中文

幾乎每則 npm 供應鏈安全公告,最後都會附上同一項指示:更換這部電腦可能存取到的所有憑證。聽起來很簡單,直到你在凌晨 2 時真的要動手。這部電腦有哪些憑證?它們存放在哪裏?更換次序重要嗎?

次序確實重要。至少在近期一宗個案中,先做最直覺的事會刪除你的家目錄。

本文會逐步説明惡意套件可以讀取開發者電腦上的哪些資料,為何蠕蟲特別會先竊取某些憑證,以及一套可靠的更換次序。文末的實例會使用一個小型開源命令列工具,但無論你使用工具還是紙本清單,次序都適用。

惡意套件如何執行

npm 套件可以在 package.json 中宣告生命週期指令碼:preinstall、install 和 postinstall。執行 npm install 時,npm 會以你的用戶權限執行這些指令碼。不會提示,也沒有沙盒。

{
  "name": "innocent-looking-lib",
  "version": "1.2.4",
  "scripts": {
    "preinstall": "node ./setup.js"
  }
}

setup.js 中的任何內容都可以讀取你的用戶有權讀取的任何檔案,並發出網絡請求。整個攻擊就是如此。本月的兩個真實案例,展示了這些酬載在實際情況下的運作方式。

2026 年 10 月 8 日,tensorlake@0.5.144 由一個遭入侵的維護者帳戶發佈。根據項目自己的安全公告(GHSA-8g63-53c9-65j2),酬載透過 preinstall 掛鈎執行,並竊取了「GitHub 和 npm 權杖、雲端服務供應商憑證(AWS、GCP)、Kubernetes 和 Vault 權杖、SSH 和 GPG 金鑰、.env 檔案、瀏覽器儲存的密碼、加密貨幣錢包,以及 AI 工具和 MCP 設定」。之後,它利用偷取的權杖,將自身重新發佈至受害者有權寫入的其他套件。該版本上線約一小時四十分鐘,而且具備有效的 npm 來源證明,因為攻擊者是透過項目自己的發佈工作流程發佈套件。

幾天前,@subql/common@5.8.3 發佈了一個 postinstall 掛鈎,用來解碼並執行經混淆處理的酬載。OSV 條目 MAL-2026-17571載有相關分析。

這兩個案例使用的手法都不是新招。CISA 在2025 年 9 月有關 Shai-Hulud 蠕蟲的警示中,描述了同一種模式:竊取權杖,再利用它們發佈受害者自己套件的受感染版本。

竊取程式會先讀取甚麼

大部分這類酬載不需要甚麼複雜手法。開發者憑證通常存放在廣為人知的明文檔案中:

檔案 內容
~/.npmrc //registry.npmjs.org/:_authToken=...,你的發佈權杖
~/.config/gh/hosts.yml,~/.git-credentials 未使用作業系統金鑰環時的 GitHub 權杖
~/.aws/credentials AWS 存取金鑰,通常有效期很長
~/.kube/config 叢集權杖及用戶端金鑰
~/.ssh/id_* 私鑰,有時沒有密碼短語
專案中的 .env 檔案 資料庫 URL、付款金鑰、webhook 密鑰
MCP 設定(~/.cursor/mcp.json、Claude Desktop 設定等) 直接貼入 env 區塊的 API 金鑰
CI 中的 process.env 工作傳遞至安裝步驟的任何密鑰

你可以用一行指令檢查自己在 npm 上的憑證暴露情況:

grep -E '_authToken|_auth|_password' ~/.npmrc

如果輸出的是實際權杖(而非 ${NPM_TOKEN}),這部機器上的任何安裝指令碼都可以讀取它。

為何次序重要

當一部機器遭入侵時,你要同時與兩件事競賽:可能仍在運行的惡意軟件,以及已被竊取並正在其他地方使用的憑證。以錯誤次序輪換憑證,可能讓攻擊者再次竊取你剛輪換的憑證,或引發更嚴重的後果。

以下逐步説明箇中原因。

1. 先停止惡意軟件。如果載荷安裝了持久化機制,你從該電腦輪替的每項憑證都會再次被盜。tensorlake 的載荷令這點變得具體。其安全公告指出,它會安裝一個名為 gh-token-monitor 的服務,「如果被盜的 GitHub token 被撤銷,就會刪除用戶的家目錄」,並指示你在輪替任何 GitHub token 前先將它移除。因此,第一步是中斷該電腦的網絡連線、移除持久化機制,然後在另一部乾淨的電腦上完成以下所有輪替。

在 Linux 上,安全公告的移除步驟如下:

systemctl --user disable --now gh-token-monitor.service
rm -rf ~/.config/gh-token-monitor ~/.local/bin/gh-token-monitor.sh

在 macOS 上:

launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.user.gh-token-monitor.plist
rm ~/Library/LaunchAgents/com.user.gh-token-monitor.plist

另外檢查 crontab -l、systemd 用戶單元、LaunchAgents 和 .vscode/tasks.json,看看有沒有任何你沒有新增的項目。

2. 接着處理套件登錄檔 token。這正是蠕蟲能成為蠕蟲的關鍵。被盜的 npm token 讓攻擊者可以為你維護的每個套件發布受感染版本,而這些版本會在每部安裝它們的電腦上執行。只要 token 仍然有效,感染就可能繼續擴散到你以外。撤銷它:

npm token list
npm token delete <token-id>

npm 自己的文件指出,撤銷最多可能需要一小時才會生效。然後對你維護的每個套件執行 npm view <your-package> time,並查看有沒有你未曾發布的版本。同樣的做法亦適用於 PyPI、RubyGems 和 crates.io token。

3. GitHub。GitHub token 讓攻擊者可以推送提交、加入工作流程,以及讀取私人儲存庫。它們排在 npm 之後,因為作為傳播途徑稍為不直接;也排在第 1 步之後,原因是上文提到的挾持服務伎倆。在 github.com/settings/tokens 撤銷 token,並在 /settings/applications 撤銷 OAuth 應用程式,然後執行 gh auth logout 和 gh auth login。

4. 雲端及基礎設施。AWS、GCP、Azure、Terraform、Kubernetes。這些憑證往往造成最嚴重的損害,但它們不會令蠕蟲傳播到其他人,因此排在傳播途徑之後。使用 AWS 時,先建立新金鑰再刪除舊金鑰,以免影響正在運作的系統;並在受影響期間檢查 CloudTrail,查看是否有人讀取 SSM Parameter Store 和 Secrets Manager。

5. 部署平台及 CI。包括儲存在平台環境變數儲存區的所有資料,以及 CI 傳遞給各個步驟的機密資料。記得重新部署,因為大多數服務會在啟動時讀取環境變數,並一直沿用舊值,直至重新啟動。

6. AI 供應商金鑰、SSH 金鑰和應用程式機密資料。這些仍然重要,也仍須處理,但無法讓攻擊擴散。

因此,處理順序是:停止正在執行的程式碼,封鎖攻擊用來擴散的途徑,然後先處理影響最大的項目,再清理其他所有項目。

範例:在工具中編碼處理順序

我把這個順序寫進一個名為 secret-blast-radius 的小型 CLI 工具,讓掃描結果可以把「輪替所有項目」轉成具體清單。有趣之處在於,排序所需的程式碼非常少。掃描器產生的每項發現都有一個 category,而各類別會對應至 src/index.js 中的一個表格:

export const ROTATION = {
  persistence: { order: 0, label: 'Stop the malware first (worm services, malicious packages/extensions)', /* steps, verify, docs */ },
  npm:         { order: 1, label: 'Package registry tokens: npm, PyPI, RubyGems, crates.io, Composer (stops a worm republishing your packages)' },
  github:      { order: 2, label: 'GitHub tokens and sessions' },
  cloud:       { order: 3, label: 'Cloud and IaC credentials (AWS, GCP, Azure, Terraform, Pulumi)' },
  kubernetes:  { order: 4, label: 'Kubernetes and container registries' },
  paas:        { order: 5, label: 'Deploy platforms (Railway, Vercel, Fly, Render, Heroku, Netlify)', redeploy: true },
  env:         { order: 6, label: 'Secrets present in the environment / CI', redeploy: true },
  ai:          { order: 7, label: 'AI provider keys and MCP servers' },
  ssh:         { order: 8, label: 'SSH keys' },
  dotenv:      { order: 9, label: 'Application secrets in .env files', redeploy: true },
  // ...
};

(已刪節。每個項目亦包含 steps、用來確認舊憑證已失效的 verify 檢查,以及供應商文件的連結。)

接着,操作手冊會進行篩選和排序。它只保留掃描實際發現項目的類別,避免一部只有 npm token 和 SSH 金鑰的電腦收到一份 12 步驟計劃:

export function runbook(result) {
  const cats = [...new Set(result.findings.map((f) => f.category))]
    .filter((c) => ROTATION[c])
    .sort((a, b) => ROTATION[a].order - ROTATION[b].order);
  return cats.map((c) => ({ category: c, ...ROTATION[c], items: result.findings.filter((f) => f.category === c) }));
}

一般報告中的發現會先按嚴重程度排序,再按輪替順序排序,因此兩項重大發現中,持久化項目會排在 npm token 上方。

如果你自行編寫工具,我會採納其中一個設計:表示「你已經感染」的發現,應歸入 persistence 類別,而不是另設類別。鎖定檔中的已知惡意版本、蠕蟲標記相依套件,或會執行偽裝檔案的 VS Code 工作,都歸入第 0 步。如果你已安裝惡意版本,首要工作是清理電腦,而不是在該電腦上輪替金鑰。

掃描器會檢查上表列出的明文儲存位置,並以簡短指紋(SHA-256 的首 8 個十六進位字元)代替實際值輸出,讓你分辨兩個權杖,而工具無須輸出任何機密資料。

試用方法:

npx secret-blast-radius            # scan and print findings plus the rotation order
npx secret-blast-radius --runbook  # Markdown checklist with steps and verify checks
npx secret-blast-radius --harden   # read-only audit of settings that would have limited the damage

減輕下一次事件的損害

輪替屬於清理工作。一些設定可限制下一個惡意負載能存取的範圍:

  • 在 ~/.npmrc 中設定 ignore-scripts=true,並將少數需要建置指令碼的套件加入允許清單。pnpm 預設已封鎖相依套件的建置指令碼。
  • 設定版本發佈後的冷卻期,避免立即安裝剛發佈的版本。pnpm 提供 minimumReleaseAge。tensorlake 的版本上線時間不到兩小時。
  • 避免將權杖存放在明文檔案中。gh auth login 在作業系統金鑰環可用時會使用它。從 CI 發佈時,請使用 npm trusted publishing,而非長期有效的 NPM_TOKEN。
  • 不要在 CI 中把機密資料傳給 npm install 步驟。只向需要機密資料的步驟提供這些資料。

關於來源證明,有一點要注意:它能告訴你套件的建置位置,卻不能判斷程式碼是否安全。tensorlake 公告指出,該惡意版本附有有效的來源證明,因為攻擊者使用了該專案自己的工作流程。

停止惡意軟件,撤銷讓它得以擴散的權杖,然後在乾淨的電腦上輪替其餘權杖。


披露:我是 secret-blast-radius 的維護者。

來源:DEV Community · dev.to