你今早照常 npm install,幾秒鐘後終端機安安靜靜回到提示號。你沒多想,繼續寫 code——但你剛才安裝的那個套件,或許已經在你的 CI 環境裡種下了一整套間諜軟體。
這不只是杞人憂天。就在 2026 年 4 月 23 日,Socket 安全研究團隊揭露:開源密碼管理器 Bitwarden 的 CLI 版本(2026.4.0)已被 Checkmarx 供應鏈攻擊活動感染。這個被安全界形容為「近年來規模最大的供應鏈攻擊」的事件,已經從 Checkmarx 自家的 MCP Server 擴散到 Bitwarden 這樣擁有超過 1000 萬使用者的基礎設施級工具。
這篇文章將從技術細節切入,完整還原攻擊的全貌——不是為了嚇你,而是讓你看清楚供應鏈攻擊的運作方式,才知道如何保護自己。
不是單一事件,而是正在進行中的大規模活動
要理解 Bitwarden 被入侵的嚴重性,必須先看懂它背後的 Checkmarx 供應鏈活動。
Socket 團隊在 4 月 22 日首次揭露 Checkmarx(一家知名的應用安全測試公司)的內部 MCP Server 套件被植入惡意程式碼。原本以為是針對 Checkmarx 的單一攻擊,但進一步分析後發現:攻擊者拿到的不只是一個 npm token,而是整條 CI/CD 管線的控制權。
攻擊者透過被入侵的 GitHub Action,在 Bitwarden CLI 的建置流程中植入惡意負載。這意味著你從 npm 官方 registry 下載的 @bitwarden/cli 2026.4.0,是經過「正規簽章流程」發布的——你看到的版本號、發布者身份、簽章,全部都是真的。這就是供應鏈攻擊最可怕的地方:你不是下載到假的套件,而是真的套件被餵了毒。
所幸截至揭露為止,Bitwarden 的 Chrome 擴充功能、MCP Server 和其他合法發布渠道尚未受到影響。但如果攻擊者能突破 Bitwarden 這樣等級的 CI 防護,任何 npm 生態系的套件發布者都不能說自己絕對安全。
深入惡意程式碼:bw1.js 的技術拆解
Socket 研究團隊發現,被植入 Bitwarden CLI 套件中的惡意檔案名為 bw1.js。它與前一天在 Checkmarx MCP Server 中發現的 mcpAddon.js 共享了大量核心基礎設施,顯示這是同一組攻擊者(或至少使用同一套工具鏈)所為。
C2 通訊架構
惡意程式碼使用一個固定的命令與控制(C2)端點:audit.checkmarx[.]cx/v1/telemetry。這個 URL 會被 __decodeScrambled 函式進行模糊化處理,種子值為 0x3039。這種手法在 CTF 比賽中很常見,但在真實世界的 APT 等級攻擊中同樣有效——不是為了防專業逆向工程,而是為了繞過初階的自動化掃描規則。
資料外洩不僅透過 C2 端點,還包括:
- GitHub API:以 commit 形式寫入受害者的公開儲存庫
- npm registry:竊取 npm token 後重新發布挾持的套件
程式碼結構與核心功能
bw1.js 的主程式寫在一個名為 bunny 的函式中,執行時會先透過 Bun v1.3.13 直譯器(從 GitHub releases 動態下載)來運行。選擇 Bun 而非 Node.js 並非偶然——Bun 的執行速度更快、啟動開銷更低,更重要的是在 CI 環境中不會留下明顯的 Node.js 進程痕跡。
內嵌的 gzip+base64 負載解壓後包含:
- Python 記憶體掃描腳本:專門針對 GitHub Actions Runner.Worker 進行記憶體傾印,目標是擷取執行中的 GitHub Token
- setup.mjs 載入器:用於在 npm 重新發布的套件中植入 preinstall hook
- GitHub Actions 工作流程 YAML:自動化的植入腳本,用於在受害者的 CI 環境中建立持久化
- 硬編碼 RSA 公鑰:用於加密外洩資料
- 意識形態宣言字串:這點後面會再提到
憑證竊取範圍:遠比想像中全面
bw1.js 的憑證竊取模組涵蓋了現代開發者常用的所有憑證類型:
| 目標 | 來源 |
|---|---|
| GitHub Token | Runner.Worker 記憶體掃描、環境變數 |
| AWS 憑證 | ~/.aws/ 檔案與環境變數 |
| Azure Token | azd 工具 |
| GCP 憑證 | gcloud config config-helper |
| npm 組態 | .npmrc 檔案(包含發布用 token) |
| SSH 金鑰 | ~/.ssh/ 目錄 |
| 環境變數 | 所有 CI 執行環境中的變數 |
| Claude/MCP 組態 | Claude Agent 設定檔 |
換句話說,如果你的 CI 環境中任何一個環節曾經暴露這些憑證,攻擊者都能一網打盡。
供應鏈擴散機制
最令人憂心的環節在於 npm token 的後續利用。攻擊者竊取到 npm token 後,會:
- 讀取該 token 對應的所有可寫入套件清單
- 將惡意 preinstall hook 注入這些套件
- 發布新版本到 npm registry
- 當其他開發者安裝這些被挾持的套件時,preinstall hook 自動執行,讓攻擊擴大
這個機制類似於經典的 typosquatting 攻擊,但更難防——因為被挾持的套件是原本就信任的相依套件,沒有任何異常的名稱或版本提示。
同時,攻擊者還會透過注入的 GitHub Actions workflow YAML 來竊取儲存庫的 secrets,進一步擴張攻擊範圍。
資料外洩手法
外洩的資料透過 GitHub API 寫入受害帳號下的公開儲存庫。這些儲存庫使用統一的命名規則:{word}-{word}-{3位數},主題靈感來自科幻小說《沙丘》中的 Shai-Hulud(沙蟲)。
加密後的結果被 commit 到這些儲存庫中,而 GitHub Token 則藏在 commit message 中,使用標記字串 LongLiveTheResistanceAgainstMachines 作為識別符號。
bw1.js 與 mcpAddon.js 的關鍵差異
雖然兩者共享大量基礎設施,但 bw1.js 新增了幾個值得注意的功能:
鎖定機制避免重複執行
硬編碼路徑 /tmp/tmp.987654321.lock 作為鎖定檔案,確保同一時間只有一個惡意實例在運行。這可以防止因 CI 任務並行執行而觸發多個實例導致的異常或偵測。
Shell Profile 持久化
惡意程式碼會將自身注入 ~/.bashrc 和 ~/.zshrc。這意味著即使駭客初始的 CI 管線入口被關閉,只要開發者在本地終端機開啟 shell,惡意程式碼就可能重新啟動。
品牌明確的意識形態色彩
與 Checkmarx 事件中試圖偽裝成合法組態儲存庫(描述為「Checkmarx Configuration Storage」)不同,Bitwarden CLI 惡意負載使用了明確的品牌命名:
- 儲存庫描述改為
Shai-Hulud: The Third Coming - Debug 字串包含
"Would be executing butlerian jihad!" - 意識形態宣言直接嵌入在惡意程式碼中
這種差異暗示了幾個可能性:可能是同一個操作者使用不同的戰術,也可能是分裂派系使用共享基礎設施但帶有更強烈的意識形態動機。
俄語環境的靜默退出
像多數來自特定地區的惡意軟體一樣,bw1.js 內建了俄語 locale 的檢查。系統會檢查 Intl.DateTimeFormat().resolvedOptions().locale 和環境變數 LC_ALL、LC_MESSAGES、LANGUAGE、LANG,若偵測到以「ru」開頭的 locale 設定,則靜默退出而不執行任何惡意行為。
這對開發者意味著什麼
如果你是 Bitwarden CLI 使用者
Socket 團隊建議所有 Bitwarden CLI 的使用者立即:
- 檢查 CI 日誌中是否有
2026.4.0版本的安裝記錄 - 輪替任何可能在受影響工作流程中暴露的 secrets
- 確認 npm lockfile 中的
@bitwarden/cli版本,如有需要則鎖定到未受影響的版本
更重要的是,這起事件不該被當作「Bitwarden 自己的問題」——攻擊的本質是 CI/CD 管線入侵,任何使用 GitHub Actions 建置 npm 套件的組織都有類似的風險。
如果你是套件維護者
如果你是 npm 套件的維護者,以下是你可以立即採取的防護措施:
第一步:啟用套件發布的 MFA 強制驗證
在 npm 帳號設定中開啟 Two-Factor Authentication(2FA),並在套件設定中啟用 "requires2fa": true。這可以防止單純的 token 竊取就被用於發布。
第二步:限制 GitHub Actions 的權限範圍
檢查你的 .github/workflows/ 中的所有 workflow,使用最小權限原則。如果一個 workflow 只需要讀取權限,就不要授予寫入權限。
permissions:
contents: read
packages: read
第三步:隔離發布流程
將套件建置與發布流程分離在不同的環境中。建置用一般的 CI runner,發布則使用專用、隔離的環境,並需要人為確認。
第四步:監控被動的 GitHub 活動
設定 GitHub 通知或使用第三方監控工具,當你的帳號在非預期時間或 IP 下建立了新的公開儲存庫時,立即收到警報。
如果你是企業安全管理者
對企業而言,這次事件更值得關注的是供應鏈監控的盲點。
許多企業的資安團隊會掃描正式上線的伺服器,但 CI/CD 管線往往是監控的灰色地帶——因為開發環境的變動頻繁、套件更新快速,傳統的靜態掃描工具很難涵蓋所有相依關係。
企業可以考慮以下做法:
- 導入相依性行為監控:不只是掃描已知漏洞(CVE),而是監控套件的執行行為是否異常。Socket 的工具在這方面就是一個例子。
- 建立 CI/CD 管線的異常行為基線:記錄正常的 CI 執行模式(執行時間、對外連線目標、建立的檔案),並在出現異常時自動阻斷。
- 限制 CI runner 的網路出口:不讓 CI runner 能任意連線到外部端點。建立允許清單,阻止惡意程式碼與 C2 端點通訊。
Checkmarx 事件的更大圖景
把 Bitwarden CLI 事件放回 Checkmarx 供應鏈攻擊的脈絡中來看,我們可以畫出更完整的攻擊鏈:
Checkmarx MCP Server (初始入口)
↓
npm token 外洩
↓
Bitwarden CLI CI/CD 入侵
↓
GitHub Token、npm Token、雲端憑證被竊
↓
被挾持套件重新發布 → 攻擊擴散到更多下游
這個攻擊鏈最可怕的地方在於它的遞迴性:每次成功的入侵都會產生新的憑證,而新的憑證又可以攻擊更多目標。從 Checkmarx 到 Bitwarden,再到所有 Bitwarden 的使用者,攻擊半徑不斷擴大。
更令人擔憂的是,攻擊者的工具鏈已經高度自動化。從記憶體掃描、憑證擷取、資料加密外洩、到套件重新發布,每一個步驟都是自動完成的。攻擊者不需要手動操作,只要 CI runner 的環境符合條件,整個攻擊流程就會自動跑完。
觀察家結語
供應鏈攻擊不是新名詞,但 Bitwarden CLI 這起事件把它帶到了新的層次——當一個擁有千萬使用者、經過安全審計、排名前三的密碼管理器都擋不住時,問題的根源已經不是單一公司或工具的安全性,而是整個 npm 生態系的信任模型出了問題。
攻擊者證明了兩件事:一是 GitHub Actions 的權限模型存在被大規模利用的可能,二是 npm 的 token 驗證機制在沒有 MFA 強制的情況下形同虛設。這不是技術上的失誤,而是設計上的漏洞——當你只需要一個字串就能發布套件時,供應鏈安全的基礎就是脆弱的。
對開發者社群來說,這是一個殘酷但重要的提醒:信任應該是動態的、可驗證的、最小化的,而不是靜態的、盲目的、全有全無的。你的套件管理器不會幫你擋這種攻擊,你的 CI 平台不會提醒你 runner 正在外送資料,你的密碼管理器反過來成了攻擊的傳播節點。
那麼,我們該怎麼辦?或許答案不在於更多昂貴的安全工具,而在於回歸最基本的安全原則:最小權限、零信任、持續驗證。如果你的 CI 不需要發送 npm publish 的權限,就不要給它。如果你的 token 不需要寫入公開儲存庫的能力,就限制它。如果一個套件不需要在安裝時執行腳本,就擋住它。
在供應鏈攻擊成為常態的時代,安全的關鍵不是找到完美的工具,而是養成習慣——習慣懷疑、習慣最小化、習慣檢查。不是因為你不信任任何人,而是因為你懂得信任應該建立在可驗證的基礎上。