2026 年 3 月,開發者圈子裡接連爆出兩件大事:npm 上每週下載量超過一億次的 axios,以及 PyPI 上 AI 領域熱門的 LiteLLM,都被攻擊者植入了惡意程式碼。只要跑了 npm install 或 pip install 拉到被污染的版本,電腦就會靜悄悄地被裝上後門。
這不是什麼小眾套件被動手腳的故事——axios 幾乎是每個 JavaScript 專案都會用到的 HTTP 請求函式庫,而 LiteLLM 則是串接超過一百種大語言模型的 AI 閘道。影響範圍之大,讓整個開源社群都繃緊了神經。
這篇文章會從套件管理器的基本概念開始,說明為什麼這類攻擊被稱為「供應鏈攻擊」,再拆解這兩起事件的攻擊手法,最後整理開發者可以馬上實踐的防範措施。
什麼是套件管理器
寫程式的時候不可能所有東西都自己從頭寫,發送 HTTP 請求、解析 JSON、連接資料庫這些事情,幾乎都會用到別人寫好的套件(package)。套件管理器就是負責幫我們從公共的套件倉庫下載、安裝、更新這些套件的工具。
可以想像成一個超大的公共倉庫,全世界的開發者都把自己寫好的工具放上去,其他人需要的時候只要一行指令就能取用。npm 是 JavaScript 生態系最早也最廣泛的套件管理器,而 Yarn 和 pnpm 則是後來為了解決 npm 在速度、磁碟空間、依賴結構等方面的問題而誕生的替代方案——三者共用同一個 npmjs.com Registry,所以裝的套件來源是一樣的,差別在於管理依賴的方式和效能。pip 是 Python 的、Maven Central 和 Gradle 是 Java 和 Android 的。每天有數十億次的套件下載發生在這些平台上。
| 套件管理器 | 程式語言 | 公共倉庫(Registry) | 安裝指令 |
|---|---|---|---|
| npm | JavaScript / TypeScript | npmjs.com | npm install axios |
| Yarn | JavaScript / TypeScript | npmjs.com(同 npm) | yarn add axios |
| pnpm | JavaScript / TypeScript | npmjs.com(同 npm) | pnpm add axios |
| pip | Python | PyPI(pypi.org) | pip install litellm |
| Maven | Java / Kotlin | Maven Central | 寫在 pom.xml 後自動下載 |
| Gradle | Java / Kotlin / Android | Maven Central / Gradle Plugin Portal | 寫在 build.gradle 後自動下載 |
| Cargo | Rust | crates.io | cargo add serde |
| Gem | Ruby | rubygems.org | gem install rails |
這些套件管理器讓開發效率變得很高——但也代表了一件事:如果倉庫裡某個熱門套件被動了手腳,所有使用這個套件的人都會受到影響。而且因為 npm、Yarn、pnpm 共用同一個 Registry,只要 npmjs.com 上的套件被污染,不管用哪個工具安裝都一樣中招。這就是供應鏈攻擊的核心邏輯。
什麼是供應鏈攻擊
用一個日常生活的例子來說明:假設有一間餐廳的食物被下了毒,直覺會想到是有人闖進廚房動手腳。但供應鏈攻擊不是這樣——攻擊者不會去碰餐廳,而是直接污染餐廳用的食材來源。可能是在醬油工廠的生產線上動手腳,這樣所有買這瓶醬油的餐廳都會中招,而且餐廳根本不知道問題出在醬油上。
軟體供應鏈攻擊也是一樣的道理。攻擊者不直接攻擊目標系統,而是攻擊目標所依賴的上游套件。當開發者透過套件管理器安裝或更新套件時,惡意程式碼就會像合法軟體一樣被安裝到電腦裡。
常見的攻擊方式有幾種:
- 帳號劫持(Account Takeover):取得套件維護者的帳號權限,直接發布含有惡意程式碼的新版本。axios 事件就是這種。
- CI/CD 工具鏈污染:先攻破開發流程中的某個工具(像是安全掃描器),再利用它來竊取發布權限。LiteLLM 事件用的就是這招。
- 惡意仿冒套件(Typosquatting):註冊一個名字跟熱門套件很像的套件,例如把
requests改成reqeusts,等人打錯字安裝到。 - 依賴混淆(Dependency Confusion):利用套件管理器優先從公共倉庫抓取的特性,註冊一個跟企業內部套件同名的公共套件,讓系統誤裝。
這類攻擊最棘手的地方在於:惡意程式碼是透過「正常管道」進來的,傳統的防火牆和防毒軟體很難偵測到。對開發者來說,npm install 跟平常完全一樣,不會有任何警告。
axios 事件:npm 上的北韓駭客攻擊
axios 是什麼
axios 是 JavaScript 生態系中最受歡迎的 HTTP 請求函式庫之一,不管是前端的 React、Vue 還是後端的 Node.js,幾乎都會用到它來打 API。npm 上每週下載量超過一億次,GitHub 上有超過十萬顆星。可以說,在 JavaScript 的世界裡,axios 就像水電一樣的基礎設施。
攻擊時間線
2026 年 3 月 31 日凌晨(UTC 00:21 至 03:20),攻擊者取得了 axios npm 維護者的帳號權限,並將帳號關聯的 Email 改成了一個 Proton Mail 信箱。接著在不到三小時內,連續發布了兩個惡意版本:1.14.1 和 0.30.4。
為什麼發兩個版本?因為 axios 有兩條主要的版本線(1.x 和 0.x),很多舊專案還停在 0.x。攻擊者顯然做了功課,兩條線都沒放過。
攻擊手法拆解
攻擊者在惡意版本中做了幾件事:
- 加入了一個新的依賴套件
plain-crypto-js(也是攻擊者自己發布的惡意套件) - 在
package.json中加入postinstallhook,讓套件安裝完畢後自動執行一段混淆過的 JavaScript 程式碼(setup.js) - 這段程式碼會根據作業系統(Windows、macOS、Linux)下載對應的後門程式,並在背景執行
被植入的後門叫做 WAVESHAPER,是一個跨平台的 C++ 後門程式。它會每 60 秒向攻擊者的伺服器回報一次,等待遠端指令。能做的事情包括:執行任意程式碼、瀏覽檔案系統、列出正在執行的程序、進行系統偵查。
根據 Google Cloud 和 Microsoft 的分析,這次攻擊被歸因給北韓的駭客組織 UNC1069(Microsoft 稱為 Sapphire Sleet),是一個至少從 2018 年就開始活動的經濟動機駭客組織。
影響與修復
如果專案中有安裝到 axios 1.14.1 或 0.30.4,應該立即降回安全版本:
# 檢查目前安裝的 axios 版本
npm list axios
# 降回安全版本
npm install [email protected]
# 或者如果是 0.x 版本線
npm install [email protected]
除了降版之外,如果電腦確實安裝過惡意版本,還需要輪換(rotate)所有在該機器上使用過的憑證和金鑰,包括 API Key、SSH Key、雲端服務的 Access Token 等。
LiteLLM 事件:從安全掃描器到 AI 閘道的連鎖攻擊
LiteLLM 是什麼
LiteLLM 是一個 Python 套件,定位是 AI 模型的統一 API 閘道。它讓開發者可以用同一套程式碼呼叫 OpenAI、Anthropic、Google、AWS Bedrock 等超過一百種大語言模型,不需要為每個服務寫不同的串接程式。在 AI 應用開發越來越盛行的現在,LiteLLM 的日下載量達到 340 萬次。
攻擊時間線
這起攻擊的手法比 axios 事件更加迂迴,是一個精心策劃的連鎖攻擊:
- 3 月 19 日:攻擊者先攻破了 Trivy GitHub Action(一個廣泛使用的安全漏洞掃描工具),竄改了它的 Git tag,讓它指向含有惡意程式碼的版本
- 被污染的 Trivy Action 會從 CI/CD 環境中竊取機密資訊,包括 PyPI 的發布 Token
- 3 月 24 日 10:39 UTC:攻擊者利用竊取到的 Token 發布惡意版本 litellm 1.82.7
- 3 月 24 日 10:52 UTC:發布更危險的 litellm 1.82.8
- 約 40 分鐘後被 PyPI 官方發現並下架
雖然只上架了 40 分鐘,但因為 LiteLLM 的下載量極大,這段時間內已經有超過 11.9 萬次下載。
攻擊手法拆解
LiteLLM 的攻擊手法技術含量相當高。惡意版本中藏了一個 .pth 檔案(litellm_init.pth),這是 Python 的一個特殊機制——放在特定目錄下的 .pth 檔案會在每次 Python 直譯器啟動時自動執行,不需要任何 import,甚至連跑 pip 本身的時候都會觸發。
更麻煩的是,因為惡意版本是用合法的 PyPI 發布 Token 上傳的,所以通過了所有標準的完整性檢查。從技術角度來看,它就是一個「正常發布」的版本。
這個惡意程式會竊取的東西非常全面:
- SSH 金鑰
- AWS、GCP、Azure 雲端憑證
- Kubernetes 設定檔
- Git 憑證
- 所有環境變數(包含各種 API Key)
- Shell 歷史紀錄
- 加密貨幣錢包金鑰
- SSL 私鑰
- CI/CD 機密資訊
- 資料庫密碼
蒐集完之後,惡意程式會把所有資料壓縮加密,再傳回攻擊者的伺服器。在 Linux 環境下還會進一步安裝 systemd 後門服務,甚至嘗試在 Kubernetes 叢集中部署特權 Pod 進行橫向移動。
這起攻擊被歸因給 TeamPCP 駭客組織,他們在 2025 年底開始活躍,同一套手法還被用在 Aqua Trivy 和 CheckMarx VS Code 擴充套件上。
影響與修復
# 檢查目前安裝的 LiteLLM 版本
pip show litellm | grep Version
# 降回安全版本
pip install "litellm==1.82.6"
# 檢查是否有後門殘留(Linux)
ls -la ~/.config/sysmon/
systemctl list-units | grep sysmon
# 檢查 Kubernetes 是否有可疑 Pod
kubectl get pods --all-namespaces | grep node-setup
如果確認有安裝過惡意版本,所有在該機器上存在的憑證都應該視為已外洩,需要全部輪換。特別是 SSH 金鑰、雲端服務憑證、和 API Key。
開發者如何防範供應鏈攻擊
看完這兩起事件,可能會覺得有點絕望——連官方套件都能被動手腳,到底要怎麼防?其實不需要恐慌,但確實需要養成一些好習慣。以下整理幾個實際可行的防範措施,涵蓋 npm、Yarn、pnpm、pip、Maven、Gradle 等主流套件管理器。
鎖定版本與使用 Lock File
最基本的防線就是鎖定依賴版本。Lock file 會記錄每個套件的確切版本和 hash 值,確保每次安裝都拿到一模一樣的內容。如果 axios 的使用者鎖定在 1.14.0,即使 1.14.1 被污染了也不會被自動升級上去。
# npm:確保 package-lock.json 存在並提交到版本控制
# 使用 ci 指令(而非 install)嚴格按照 lock file 安裝
npm ci
# Yarn:確保 yarn.lock 存在並提交到版本控制
# 使用 --frozen-lockfile 嚴格按照 lock file 安裝
yarn install --frozen-lockfile
# pnpm:確保 pnpm-lock.yaml 存在並提交到版本控制
# 使用 --frozen-lockfile 嚴格按照 lock file 安裝
pnpm install --frozen-lockfile
# pip:產生帶有 hash 的 requirements 檔案
pip install pip-tools
pip-compile --generate-hashes requirements.in
# pip:安裝時驗證 hash
pip install --require-hashes -r requirements.txt
Maven 和 Gradle 的依賴版本通常寫死在 pom.xml 或 build.gradle 裡,相對不容易被自動升級。但還是要注意避免使用 LATEST 或 + 這類動態版本號。Gradle 從 6.2 開始支援 Dependency Locking,可以像 npm 的 lock file 一樣鎖定解析後的版本:
// build.gradle — 啟用依賴鎖定
dependencyLocking {
lockAllConfigurations()
}
# 產生 lock file(gradle.lockfile)
./gradlew dependencies --write-locks
# 之後每次建置都會比對 lock file,版本不一致就會失敗
升級前檢查套件變更內容
不要無腦升級依賴。每次升級前,花一點時間看看這次更新改了什麼。如果一個 HTTP 函式庫突然多了一個 postinstall script 或是多了一個從沒聽過的新依賴,那就非常可疑。
# npm:比較兩個版本之間的差異
npm diff [email protected] [email protected]
# npm:檢查套件的安裝腳本
npm show axios scripts
# pip:使用 pip-audit 檢查已知漏洞
pip install pip-audit
pip-audit
# Maven:列出完整的依賴樹,觀察是否有不預期的新依賴
mvn dependency:tree
# Gradle:列出依賴樹
./gradlew dependencies
如果有使用 Dependabot 或 Renovate 之類的自動更新工具,不要設定自動合併(auto-merge),至少要看一下 PR 裡面的 changelog 和版本差異再決定要不要更新。
限制安裝腳本執行
axios 事件中,惡意程式碼是透過 npm 的 postinstall hook 自動執行的。其實 npm 提供了選項可以跳過這類腳本:
# npm:安裝時忽略所有生命週期腳本
npm install --ignore-scripts
# npm:全域設定,永久關閉自動執行腳本
npm config set ignore-scripts true
# 如果某些套件真的需要 postinstall(例如 node-gyp 編譯原生模組)
# 可以在 package.json 中用 allowScripts 欄位白名單管理
不過要注意,有些套件確實需要 postinstall 腳本才能正常運作(例如需要編譯原生模組的套件),所以完全關閉可能會造成一些問題。比較平衡的做法是預設關閉,再對需要的套件個別開啟。
Maven 與 Gradle 的額外防線
Java 生態系在供應鏈安全方面其實比 npm 和 PyPI 多了幾道防線,值得好好利用。
Gradle Dependency Verification:Gradle 從 6.2 開始提供了依賴驗證機制,可以對每個下載的依賴檔案驗證 checksum 和 GPG 簽章。第一次執行時 Gradle 會產生一份 verification-metadata.xml,記錄所有依賴的 hash 值,之後每次建置都會比對。如果有人在 Maven Central 上替換了某個 jar 的內容,建置就會直接失敗。
# 產生依賴驗證的 metadata 檔案(包含 checksum 和 GPG 簽章)
./gradlew --write-verification-metadata sha256,pgp help
# 產生後會在 gradle/ 目錄下建立 verification-metadata.xml
# 將這個檔案提交到版本控制
gradle/verification-metadata.xml 的內容大概像這樣:
<verification-metadata>
<components>
<component group="com.google.guava" name="guava" version="33.4.0-jre">
<artifact name="guava-33.4.0-jre.jar">
<sha256 value="0a4a2ab1e13a1e7c7936..." />
<pgp value="ABCDEF1234567890" />
</artifact>
</component>
</components>
</verification-metadata>
Maven Enforcer Plugin:Maven 的 Enforcer Plugin 可以在建置時強制執行各種規則,例如禁止使用 SNAPSHOT 版本、禁止特定的依賴、或是要求所有依賴都必須收斂到同一個版本。雖然不是直接針對供應鏈攻擊設計的,但可以有效防止一些意外引入的問題。
<!-- pom.xml — 使用 Enforcer Plugin 禁止 SNAPSHOT 依賴 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.5.0</version>
<executions>
<execution>
<id>enforce-no-snapshots</id>
<goals><goal>enforce</goal></goals>
<configuration>
<rules>
<requireReleaseDeps />
<banDuplicatePomDependencyVersions />
</rules>
</configuration>
</execution>
</executions>
</plugin>
Wrapper 腳本的安全性:很多 Java 專案會把 gradlew(Gradle Wrapper)或 mvnw(Maven Wrapper)提交到版本控制裡,方便團隊成員不用自己安裝 Gradle 或 Maven。但這也代表了一個攻擊面——如果有人在 PR 裡偷偷修改了 Wrapper 的設定檔(gradle-wrapper.properties 或 .mvn/wrapper/maven-wrapper.properties),把下載網址指向惡意的 Gradle/Maven 發行版,那所有執行 ./gradlew 的人都會中招。Code review 的時候如果看到 Wrapper 設定檔被修改,一定要特別留意 distributionUrl 指向的是不是官方來源。
整體來說,Maven Central 的發布流程比 npm 和 PyPI 嚴格不少——發布到 Maven Central 需要經過 GPG 簽章、Namespace 驗證(要證明擁有該 groupId 對應的 domain),所以直接偽造套件的難度相對高。但這不代表完全沒有風險,帳號劫持和依賴混淆攻擊在 Java 生態系中仍然是可能的威脅。
使用軟體組成分析(SCA)工具
SCA(Software Composition Analysis)工具可以掃描專案中的所有依賴,檢查是否有已知的漏洞或可疑行為。以下是幾個常用的工具:
| 工具 | 支援的生態系 | 特色 |
|---|---|---|
| Socket.dev | npm、PyPI | 偵測可疑的套件行為(如安裝腳本、網路存取),不只看已知漏洞 |
| Snyk | npm、PyPI、Maven、Gradle 等 | 整合 CI/CD,自動掃描 PR 中的依賴變更 |
npm audit | npm | 內建指令,免費,檢查 npm 已知漏洞資料庫 |
| pip-audit | PyPI | 官方出品,比對 OSV 漏洞資料庫 |
| OWASP Dependency-Check | Maven、Gradle、npm、PyPI 等 | 免費開源,比對 NVD 漏洞資料庫,有 Maven/Gradle Plugin |
值得注意的是,LiteLLM 事件中惡意版本通過了所有標準的完整性檢查,因為它是用合法的 Token 發布的。所以 SCA 工具不是萬能的,但至少能擋下大部分已知的威脅,以及偵測可疑的套件行為模式。
CI/CD 環境隔離與 Token 管理
LiteLLM 事件的根源是 CI/CD 環境中的 PyPI 發布 Token 被竊取。這提醒了我們幾件事: