2026 年 3 月,開發者圈子裡接連爆出兩件大事:npm 上每週下載量超過一億次的 axios,以及 PyPI 上 AI 領域熱門的 LiteLLM,都被攻擊者植入了惡意程式碼。只要跑了 npm installpip install 拉到被污染的版本,電腦就會靜悄悄地被裝上後門。

這不是什麼小眾套件被動手腳的故事——axios 幾乎是每個 JavaScript 專案都會用到的 HTTP 請求函式庫,而 LiteLLM 則是串接超過一百種大語言模型的 AI 閘道。影響範圍之大,讓整個開源社群都繃緊了神經。

這篇文章會從套件管理器的基本概念開始,說明為什麼這類攻擊被稱為「供應鏈攻擊」,再拆解這兩起事件的攻擊手法,最後整理開發者可以馬上實踐的防範措施。

什麼是套件管理器

寫程式的時候不可能所有東西都自己從頭寫,發送 HTTP 請求、解析 JSON、連接資料庫這些事情,幾乎都會用到別人寫好的套件(package)。套件管理器就是負責幫我們從公共的套件倉庫下載、安裝、更新這些套件的工具。

可以想像成一個超大的公共倉庫,全世界的開發者都把自己寫好的工具放上去,其他人需要的時候只要一行指令就能取用。npm 是 JavaScript 生態系最早也最廣泛的套件管理器,而 Yarnpnpm 則是後來為了解決 npm 在速度、磁碟空間、依賴結構等方面的問題而誕生的替代方案——三者共用同一個 npmjs.com Registry,所以裝的套件來源是一樣的,差別在於管理依賴的方式和效能。pip 是 Python 的、Maven Central 和 Gradle 是 Java 和 Android 的。每天有數十億次的套件下載發生在這些平台上。

套件管理器程式語言公共倉庫(Registry)安裝指令
npmJavaScript / TypeScriptnpmjs.comnpm install axios
YarnJavaScript / TypeScriptnpmjs.com(同 npm)yarn add axios
pnpmJavaScript / TypeScriptnpmjs.com(同 npm)pnpm add axios
pipPythonPyPI(pypi.org)pip install litellm
MavenJava / KotlinMaven Central寫在 pom.xml 後自動下載
GradleJava / Kotlin / AndroidMaven Central / Gradle Plugin Portal寫在 build.gradle 後自動下載
CargoRustcrates.iocargo add serde
GemRubyrubygems.orggem 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.10.30.4

為什麼發兩個版本?因為 axios 有兩條主要的版本線(1.x 和 0.x),很多舊專案還停在 0.x。攻擊者顯然做了功課,兩條線都沒放過。

攻擊手法拆解

攻擊者在惡意版本中做了幾件事:

  1. 加入了一個新的依賴套件 plain-crypto-js(也是攻擊者自己發布的惡意套件)
  2. package.json 中加入 postinstall hook,讓套件安裝完畢後自動執行一段混淆過的 JavaScript 程式碼(setup.js
  3. 這段程式碼會根據作業系統(Windows、macOS、Linux)下載對應的後門程式,並在背景執行

被植入的後門叫做 WAVESHAPER,是一個跨平台的 C++ 後門程式。它會每 60 秒向攻擊者的伺服器回報一次,等待遠端指令。能做的事情包括:執行任意程式碼、瀏覽檔案系統、列出正在執行的程序、進行系統偵查。

根據 Google Cloud 和 Microsoft 的分析,這次攻擊被歸因給北韓的駭客組織 UNC1069(Microsoft 稱為 Sapphire Sleet),是一個至少從 2018 年就開始活動的經濟動機駭客組織。

影響與修復

如果專案中有安裝到 axios 1.14.10.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 事件更加迂迴,是一個精心策劃的連鎖攻擊:

  1. 3 月 19 日:攻擊者先攻破了 Trivy GitHub Action(一個廣泛使用的安全漏洞掃描工具),竄改了它的 Git tag,讓它指向含有惡意程式碼的版本
  2. 被污染的 Trivy Action 會從 CI/CD 環境中竊取機密資訊,包括 PyPI 的發布 Token
  3. 3 月 24 日 10:39 UTC:攻擊者利用竊取到的 Token 發布惡意版本 litellm 1.82.7
  4. 3 月 24 日 10:52 UTC:發布更危險的 litellm 1.82.8
  5. 約 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.xmlbuild.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

如果有使用 DependabotRenovate 之類的自動更新工具,不要設定自動合併(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.devnpm、PyPI偵測可疑的套件行為(如安裝腳本、網路存取),不只看已知漏洞
Snyknpm、PyPI、Maven、Gradle 等整合 CI/CD,自動掃描 PR 中的依賴變更
npm auditnpm內建指令,免費,檢查 npm 已知漏洞資料庫
pip-auditPyPI官方出品,比對 OSV 漏洞資料庫
OWASP Dependency-CheckMaven、Gradle、npm、PyPI 等免費開源,比對 NVD 漏洞資料庫,有 Maven/Gradle Plugin

值得注意的是,LiteLLM 事件中惡意版本通過了所有標準的完整性檢查,因為它是用合法的 Token 發布的。所以 SCA 工具不是萬能的,但至少能擋下大部分已知的威脅,以及偵測可疑的套件行為模式。

CI/CD 環境隔離與 Token 管理

LiteLLM 事件的根源是 CI/CD 環境中的 PyPI 發布 Token 被竊取。這提醒了我們幾件事: