LiteLLM 1.107.0 遭供應鏈攻擊:原碼標籤乾淨,為何安裝包仍能竊取密鑰?
LiteLLM 1.107.0 的 PyPI 安裝包與部分 Docker 映像遭植入竊密程式,官方原碼標籤卻未包含惡意檔。本文整理受影響版本與台灣時間窗,解釋 Python 啟動風險、重建環境與撤換金鑰的先後,以及官方仍在調查的根因。
LiteLLM 1.107.0 事件讓人重新檢視套件發布。檢查開源套件的程式碼,通常是確認更新內容的起點。
但 LiteLLM 這次事故顯示,看到乾淨的原碼,仍可能裝到不同內容。
LiteLLM 在十月二十一日通報,1.107.0 的發布流程被利用,PyPI 安裝包與部分容器映像帶入竊取憑證和載入遠端程式的功能。
官方說,GitHub 上對應的原碼標籤沒有那些惡意檔案,實際發布物卻來自攻擊者控制的另一個程式庫。
對使用者來說,問題不只是現在最新版本是什麼,還包括當時從哪裡下載、環境是否啟動過,以及它能讀到哪些金鑰。
我會先依安裝與執行紀錄定位受影響環境,再處理可信重建和憑證撤換。單純升版,無法讓已被拿走的密鑰自動失效。
第一步是把套件、映像和各自的發布時間窗分清楚,避免只看現在的版本號,就錯判過去是否曝險。
LiteLLM 1.107.0 影響哪些安裝?套件與容器時間窗
受影響的是特定發布物與浮動標籤,不是每個使用者都能由品牌名稱直接判定。
官方事故公告列出 PyPI 上的七個惡意 wheel 安裝檔,以及經由同一發布流程送到容器登錄庫的映像。因此判斷範圍時,版本、來源與實際下載時間必須一起看。
LiteLLM 提供的時間以世界協調時間記錄,換成台灣時間如下。這些是各登錄庫出現及移除相關發布物的時間,不代表攻擊者只可能在這段期間操作已遭入侵的環境。
| 發布位置 | 台灣時間十月二十一日的已知窗口 | 對照重點 |
|---|---|---|
| PyPI | 十九時三十九分五十一秒至二十一時二十三分 | 是否取得受影響的安裝檔 |
| Docker Hub | 十九時四十六分五十六秒至二十二時二十分 | 映像版本、標籤及實際摘要 |
| GitHub Container Registry | 十九時四十六分五十六秒起,至二十一時五十一分相關映像不可用 | 不要套用其他登錄庫的移除時間 |
容器的相關標籤包括 v1.107.0,以及 latest、main-latest、main-stable。後三者屬於會隨發布改變指向的標籤。
因此今天拉到的內容,可能已經不同於昨天。若部署紀錄保留了映像摘要,就能比只留下「latest」更精確地對照實際執行物。
官方表示私人企業登錄庫未受影響,這個範圍限定在那個發布管道。企業客戶若自行使用公開套件或公開映像,仍需按自己的取得方式檢查,不能僅憑付費帳號身分排除。
十月二十三日查詢 PyPI 時,惡意版本已不在現行版本清單,也同樣不能回頭證明先前從未安裝。
但下載、安裝與啟動又是不同事件。快取、建置機與部署主機可能各自保留發布物,即使線上的套件已移除,本地保存的內容仍需追查。
範圍對上後,這次最反直覺的地方,就是原碼與實際發給使用者的檔案並不相同。

原碼標籤沒變,安裝包為何不同?
使用者執行的是建置後的發布物,而不一定是剛才在 GitHub 上閱讀的那份原碼。一般流程會從指定原碼版本建置套件、測試、簽署,再發布到登錄庫。
每一段都需要能對回前一段,才能讓閱讀原碼的結果延伸到實際安裝內容。
依維護者的說明,這次官方 GitHub 的 v1.107.0 原碼標籤沒有包含惡意檔案,發布流程卻被導向攻擊者控制的相似名稱程式庫。
合法組織是 BerriAI,外觀相近的來源則是 Berri-AI。差一個連字號,就可能指向另一個擁有者。不能只看專案名稱仍叫 litellm,就認定建置來源相同。
這不是使用者把網址打錯才會發生的問題。
LiteLLM 描述的是發布身分與工作流程遭利用後,由原本的正式管道送出內容,因此看起來可信的下載位置,也可能交付被污染的檔案。
所以對使用者來說,來源頁面、發布帳號與發布物內容是相關證據,卻不是可以互相代替的同一件事。
簽章也要放在這個脈絡裡看。它能協助確認檔案由哪個身分或流程簽署,以及之後是否被更動。若那個正式流程本身被操控,簽章並不會自動判斷內容是否符合維護者原意。
這不是說簽章沒有價值,而是還需要知道當時建置了哪份原碼、誰能改變流程,以及最後產生什麼檔案。
最早的 GitHub 通報由外部研究者提出,提供了實際發布物的線索。所以閱讀這類紀錄時,也要把研究者的觀察與維護者後續確認分開,避免把最初推測全部當成官方結論。
一旦惡意檔進入環境,它何時執行,就會改變清理的順序。
為什麼不能先重跑 pip?Python 啟動時就可能執行
這次惡意檔使用 Python 啟動機制,沒有呼叫套件功能也可能開始動作。
官方指出,相關內容利用會在直譯器啟動時處理的檔案,例如 .pth 與 sitecustomize。
因為它們本來可用於環境設定,遭濫用後,執行時機就不再限於程式明確匯入某個套件的那一刻。
因此,「我沒有在程式裡 import」不足以排除影響。環境內的其他 Python 程式啟動時,也可能碰到這段機制。
但常用的套件管理工具 pip 本身就會啟動 Python。若直接在疑似受污染環境裡重跑更新或移除指令,可能再次觸發惡意程式。
LiteLLM 建議的處理方向,是從乾淨環境進行調查與重建,而不是依賴原環境自行清掉自己。
所以對容器部署而言,重點也不只是讓浮動標籤改指新版本,而是確認新的建置來源、快取與部署映像都不再沿用可疑內容。舊環境應留給適當的事故調查流程處理。
因此,檢查標記檔時,同樣有單向的證據界線。找到已知惡意檔,可以支持該環境確實含有相關內容。沒有找到,卻不能保證從未執行、沒有遭刪除,或沒有其他殘留。
若安裝紀錄已顯示取得受影響發布物,不能只靠某個檔案現在不存在就結案。
這也是為什麼單純「降回舊版」不夠。替換套件可能停止某段程式,卻不會讓它先前讀到的外部憑證失效,也未必處理所有主機狀態。
環境恢復和外部存取權撤換,需要分成兩份工作完成。
重建環境與換金鑰:兩種不同的恢復工作
環境重建處理主機上的惡意程式,撤換憑證則阻止舊密鑰繼續存取外部服務。這次產品常位於模型代理或閘道的位置,可能接觸多家模型供應商金鑰。
若資料庫保存了供應商憑證,調查就不能只看啟動環境中的一個變數。
官方提醒的範圍還包括代理資料庫可取得的金鑰、主金鑰與虛擬金鑰、雲端認證及其他環境機密。實際要撤換哪些,取決於可疑環境能讀到什麼。
某一類憑證理論上可被讀取,與已確認全部被帶走,仍是不同主張。處置可以按曝險先進行,對外描述則應保留證據界線。
撤換也不等於只改設定檔。舊金鑰要在提供它的服務端撤銷或停用,新的金鑰再放到可信部署。否則即使自己的程式已改用新值,外部服務仍可能接受舊值。
與模型用量相關的金鑰,還需要回到供應商側核對專案、時間與呼叫紀錄,觀察是否有不符合日常流量的使用。
如果同一組認證也用於其他主機,更新時就得對照那些使用位置,避免一邊撤掉舊值,另一邊仍持續用它而中斷服務。
這不是要求把所有系統一律重做,而是沿著這次環境實際能接觸的憑證,找到它的有效範圍與使用者。
類似的外部模型帳號追查,可參考OpenCode 通報 Console 安全事件:影響 1.4% Console 使用者,外部模型帳號該先查什麼?。
不同事件的受影響範圍不可混用,但「平台恢復」與「外部金鑰失效」需要分開確認,這個判斷可以沿用。
官方如何描述根因?已觀察的 token 與仍在調查的入口
LiteLLM 維護者已交代發布帳號與工作流被利用的路徑,但進入內部部署的方式仍有未確認部分。
官方描述觀察到三組 GitHub 命令列認證遭利用,並交代流程覆寫與保護設定被更動的情況。這些內容回答的是攻擊者如何影響發布,不能全部直接當成最初入侵點已被證實。
公司認為內部代理部署中可存取的紀錄,可能讓相關認證暴露。其中提到特定 Claude Code 互動情況下,回應內容包含 GitHub 命令列認證的細節。
因為這個描述的主體是該公司的部署、紀錄與觀察,不能推成所有 Claude Code 使用者都會洩漏相同資訊。
至於攻擊者如何先進入那個內部環境,官方仍以懷疑及調查中的措辭說明。近期修補過的漏洞是調查方向,不是已完成的獨立定論。
也不能只因多起 AI 工具事件時間接近,就認定出自同一人或同一入侵方法。
三月曾發生的套件事件,也需要與十月的 1.107.0 分開。
版本、時間、發布物與攻擊路徑各有紀錄,把兩次合成一個故事,反而會讓使用者難以判斷自己的部署到底落在哪個範圍。
所以對仍在發展的事故,明確保留未知,能避免恢復決策建立在錯誤的排除條件上。
維護者該留下哪些發布證據?
我會讓每次發布能連回核准的原碼版本、實際建置來源與最後交付的檔案。
這次特別需要對照完整的程式庫擁有者與版本識別,因為只比專案名稱或標籤文字,抓不到外觀相似來源的差異。檔案摘要則能幫助後續辨認,某台主機究竟使用哪一份實際內容。
若發布流程允許臨時改寫來源或提高權限,也應留下何時啟用、由誰核准及何時收回的紀錄。
這些證據的用途,是把「維護者看過的原碼」與「使用者執行的發布物」接起來,而不是只增加另一個形式上的簽署步驟。
代理工具本來就會把程式執行、模型呼叫與外部帳號接在一起,權限範圍可延伸閱讀NVIDIA Open Agent Safety Platform 是什麼?OpenShell、Sentry 如何防止 AI Agent 越權。
這次事故更直接指出,工具尚未開始正式工作,發布與啟動階段就可能影響憑證。確認交付物,必須和後續任務權限一起考慮。
對使用套件的團隊而言,還有一個容易遺漏的位置:持續整合環境。即使正式服務沒有更新,某次建置或測試也可能在那段時間取得新版本。
若建置機能讀取發布認證或其他專案機密,它的曝險範圍就不只限於測試資料。因此,調查應以實際安裝紀錄為起點,而不是只問正式環境目前顯示哪個版本。
自動建置的快取也需要對照。登錄庫移除檔案,不會同步清空所有組織的套件鏡像、快取或已建出的映像。日後若從本地快取重新建立,仍可能沿用原內容。
所以保留檔案摘要與取得時間,可以協助辨認哪些快取需要由乾淨來源重建,也避免把不同發布物只因版本文字相同就視為一致。
這次事件讓發布來源證明與內容檢查的分工更清楚。前者需要回答檔案從哪個流程產生,後者則檢查它是否包含預期之外的啟動行為。
兩種證據搭在一起,才比較能發現正式流程被導向另一份來源的情況。只閱讀變更說明,並不足以確認最後交付的每個檔案。
因此,恢復紀錄也應把未知留下。若某台主機曾執行受影響內容,但無法確認是否成功外傳,可以記為需要按曝險處理。不必為了給出單一結果,就硬寫成已確認失竊或已完全排除。
這讓後續調查能補上證據,而不會被一個過早的結案文字限制。
對開源維護者,具體改進可以對準本案的來源覆寫與發布權限:核准的是哪個完整來源、工作流實際抓了哪個版本,以及最後簽署的檔案是否由同一份輸入產生。
若這三段能被獨立對照,即使帳號或流程出現異常,也較有機會在交付前看出差異。
想繼續追蹤這類工具的正式推出條件與後續更新,可以免費訂閱 AI 郵報。
LiteLLM 1.107.0 常見問題
沒有 import LiteLLM,也可能受影響嗎?
可能。這次惡意內容利用 Python 啟動機制,官方提醒不要在疑似受污染的環境直接執行 pip。
現在 latest 已更新,能排除之前的曝險嗎?
不能。浮動標籤會改變指向,應查當時下載、建置與部署的實際內容及摘要。
所有企業客戶都不受影響嗎?
官方未受影響的說明針對私人企業登錄庫。使用公開套件或公開映像的部署,仍要按實際來源對照。
這和三月的套件攻擊是同一個事件嗎?
不是同一批發布物與時間窗。不能把不同事件的版本和處理紀錄混在一起判斷。