那顆 fork bomb 救了我們
LiteLLM 1.82.8 裡的惡意程式包含一個 .pth 檔案,只要 Python 一啟動就會執行。它蒐集 SSH 金鑰、雲端憑證、加密貨幣錢包與 CI/CD 機密,用 4096 位元 RSA 金鑰加密後,把壓縮檔外傳到攻擊者控制的網域。這套酬載做工紮實,加密穩固可靠,外傳過程乾淨俐落。1 本文屬於我的代理安全系列,探討那些形塑我們如何為自動化系統建立信任的真實世界失敗案例。5
那個 .pth 檔案還會另外開一個 Python 子行程來執行任務。而子行程又觸發了 .pth 檔案,於是又生出另一個子行程,接著再觸發一次。指數級的 fork bomb 就此成形,幾秒內吃掉 100% CPU 與 5 GB 以上的記憶體。2
這顆 fork bomb 是個 bug。攻擊者從沒打算讓惡意程式現形。若實作正確,它會在每一台受感染機器上、每一次 Python 呼叫時悄然執行,可能一連好幾週。結果卻是開發者發現自己的機器慢到動彈不得,一查之下揪出了憑證竊取程式。PyPI 在發布後 46 分鐘隔離了這兩個版本。1
四萬六千次安裝,四十六分鐘。所謂的偵測機制,其實是惡意程式的實作失誤。
當 AI 代理的相依套件安裝了含有 fork bomb 的套件,指數級的行程衍生會在幾秒內吃光 100% CPU 與數 GB 記憶體,整台機器就此癱瘓。 在 LiteLLM 1.82.8 這起事件中,這顆意外的 fork bomb 是憑證竊取酬載唯一被察覺的原因:開發者發現機器慢到停擺,才動手追查。少了這個 bug,惡意程式會默默把 SSH 金鑰、雲端憑證與加密貨幣錢包往外送好幾週,才可能被發現。
重點摘要
- 那個 bug:LiteLLM 1.82.8 的憑證竊取程式帶著一個 fork bomb bug,讓受感染機器慢到停擺。沒有這個 bug,它會安靜地跑上好幾週。
- 那道缺口:靜態分析、行為監控、程式碼審查全都漏掉了這次攻擊。每一道偵測環節都以為另一道會攔下來,結果一道也沒攔住。3
- 那條曲線:攻擊者的品質會隨著迭代而提升。
.pth手法如今已公開記載,下一個攻擊者接手時不會再附帶這個 bug。 - 不靠運氣也管用的做法:出口流量的網域註冊時間檢查、套件安裝的行為基準線、檔案系統誘餌、安裝環境隔離。無論酬載品質如何,這些都有效。
- 那道不對稱:環境是由防守方決定的。如果安裝環境裡根本沒有憑證可偷,再完美的酬載也一無所獲。
我們只是走運
把 fork bomb 從酬載裡拿掉,這次攻擊就會無聲無息地得手。.pth 檔案在任何 import 之前執行,在任何應用程式碼之前執行,也在任何 Python 層級的沙箱之前執行。沒有掛鉤點,沒有日誌紀錄。憑證竊取程式執行、加密、外傳,Python 行程照常繼續。開發者什麼也沒看見,CI 流程什麼也沒看見,安全掃描工具什麼也沒看見——因為安全掃描工具打從一開始就是攻擊媒介。3
LiteLLM 1.82.8 的偵測故事,講的不是「我們的監控抓到了」,而是「攻擊者寫出了 bug」。
拿這個當供應鏈安全的地基,實在令人不安。正如我在你的代理沙箱只是個建議一文中所主張的,我們以為橫亙在可信與不可信程式碼之間的那些邊界,遠比多數團隊想像的更加千瘡百孔。
攻擊者的品質曲線
軟體品質隨著迭代而提升。這對攻擊者與防守方一體適用。TeamPCP 的行動在一週內橫掃五個生態系:GitHub Actions、Docker Hub、npm、Open VSX 與 PyPI。4 每一次生態系的淪陷,用的都是從前一次收割來的憑證。整場行動展現出高度的作戰成熟度:在投放酬載前 24 小時註冊網域、對可變動的參照做標籤劫持,並藉由 Aqua Security 不完整的金鑰更換來規避憑證輪替。
在一場其餘環節都相當稱職的行動中,fork bomb 是唯一的失手。下一場行動不會再犯同樣的錯。.pth 檔案手法如今已公開記載,CrowdStrike、Microsoft、Wiz 與 Palo Alto 都做過分析。3 下一個攻擊者將原封不動接手這套手法,只是不帶那個 bug。
攻擊能力遵循的成長曲線,與防禦能力並無二致。手法是公開的,分析是公開的。下一個攻擊者的起點,就是 TeamPCP 的終點。關於這條曲線對自主系統的意涵,我在無人監督時真正會出事的地方中有進一步的探討。
偵測不能建立在攻擊者失誤之上
現行的供應鏈偵測模型有三道防線,面對 LiteLLM 時三道全破:
靜態分析沒攔住。.pth 檔案是 Python 的正規功能。酬載經過兩層 base64 編碼,在執行期才解碼。專找已知惡意特徵的靜態掃描工具一無所獲,因為這個特徵是全新的。
行為監控沒攔住。憑證竊取程式只發出一次對外的 HTTPS POST,目標網域看起來像個正當服務(models.litellm.cloud)。要靠檢查目標網域的出口監控攔下它,前提是得知道這個特定網域是 24 小時前才註冊的。而多數出口監控根本不查網域註冊時間。
程式碼審查沒攔住。惡意版本是直接發布到 PyPI 的,完全繞過 GitHub 的 CI/CD 流程。沒有 pull request 可審,沒有 diff 可看。攻擊者用竊得的發布憑證,上傳了預先建好的套件。
每一道偵測防線,都指望攻擊鏈的另一段會攔下問題。結果一道也沒有。攔下問題的是 fork bomb。
真正能揪出無聲惡意程式的做法
既然不能指望攻擊者失手,就需要不受實作品質影響、照樣管用的偵測機制。
對出口請求檢查網域註冊時間。 外傳網域是攻擊前 24 小時才註冊的。一條防火牆規則,只要標記所有指向註冊未滿 7 天網域的對外請求,就能攔下這次攻擊。規則單純,誤報率可控,而且擋得住最常見的外傳手法。
為 Python 行程建立行為基準線。 一次 pip install 突然對不明網域發出 HTTPS POST 請求,這就是異常。追蹤套件安裝期間網路活動的行程層級行為監控,會把它標記出來。
檔案系統誘餌。 在一個誘餌路徑放一把假的 SSH 金鑰,在另一個誘餌路徑放一組假的 AWS 憑證,接著監控是否有任何行程讀取這些檔案。掃遍標準路徑的憑證竊取程式,一定會讀到誘餌;正當的行程則不會。外傳完成之前,誘餌就會觸發警報。
安裝環境隔離。 在一個接觸不到真實憑證的環境裡執行 pip install,事後再把裝好的套件複製到正式環境。.pth 檔案是在 pip 自己的 Python 行程中觸發的,也就是說憑證竊取程式在安裝當下就已經執行。倘若安裝環境裡沒有憑證可偷,這次攻擊就一無所獲。
以上機制,沒有一項需要攻擊者犯錯。無論酬載品質高低,它們照樣有效。這種架構思路——打造出即使遭遇完美攻擊也一無所獲的環境——與部署與防守:代理信任的悖論背後的原則如出一轍。
那道不對稱
防守方握有一項結構性優勢:環境由防守方決定。攻擊者只能在套件被裝進去的那個環境裡施展手腳。若那個環境沒有憑證、沒有網路存取,還布著檔案系統誘餌,酬載在技術上成功了,實際成效卻徹底落空。
LiteLLM 這次攻擊之所以奏效,是因為安裝環境同時也是存放發布憑證、SSH 金鑰與雲端權杖的環境。fork bomb 對安全架構本身無關痛癢,它影響的只是時間軸。
下一次,fork bomb 不會出現了。而憑證,依然會和套件管理器待在同一個環境裡。真正的問題是:在下一個攻擊者投放乾淨的酬載之前,您是否已經把環境改掉了。我在Ralph 代理架構的分析中,說明了該如何組織代理系統,讓遭到入侵的元件無法越過自身的隔離邊界向外擴散。
常見問題
攻擊者為什麼沒測出這顆 fork bomb?
讓 .pth 檔案另外開一個子行程來跑酬載,本身是個合理的實作選擇,可以避免卡住母行程。真正的遞迴觸發,來自 .pth 與 Python site.py 初始化流程之間一個相當隱微的交互作用。這類 bug 只會在整合測試中現形,單元測試抓不到,而惡意程式作者鮮少有機會在貼近真實的環境裡做整合測試。
這顆 fork bomb 有沒有可能是故意的?
不太可能。fork bomb 讓惡意程式瞬間現形,這與攻擊者的目標完全背道而馳。一個安靜跑上好幾週的憑證竊取程式,收割到的憑證會比一個 46 分鐘就被逮的多上好幾個數量級。
網域註冊時間檢查在大規模場景下實用嗎?
實用。網域註冊時間可透過 WHOIS 或 DNS 註冊日期 API 取得,每次請求只增加數毫秒的延遲。多數組織都能把已知的新網域加進白名單。
資料來源
-
FutureSearch (Daniel Hnyk), “LiteLLM Hack: Were You One of the 47,000?” March 2026. ↩↩
-
isfinne et al., “LiteLLM Supply Chain Attack,” GitHub Issue #24512, March 2026. ↩
-
Blake Crosley, “The Supply Chain Is the Attack Surface,” blakecrosley.com, March 2026. ↩↩↩
-
Kaspersky, “Trojanization of Trivy, Checkmarx, and LiteLLM Solutions,” March 2026. ↩
-
Blake Crosley, “When Your Agent Becomes the Researcher,” blakecrosley.com, March 2026. ↩