你收到同事一句「我們好像裝過 1.107.0」,第一反應是不是打開終端機查版本?這篇 LiteLLM 曝險盤點教你先停下這一步:把安裝產物、執行環境與能讀到的憑證分開記,避免查詢動作本身再次啟動可疑程式。
本文寫給第一次協助事故處理的開發者與系統管理者。你會拿到一份可照填的多環境紀錄,以及先隔離、再核對、重建和撤權的工作順序。沒有管理權限的讀者,先把工作表交給部署負責人;磁碟快照與雲端權限操作由有授權的人處理。
事件資料查閱於 2026 年 10 月 23 日;官方事件頁可見更新標示為 10 月 21 日 20:30 UTC。本文不執行污染版本,後面的三環境案例是教學假設。若想理解攻擊者如何挪用出貨流程,先讀LiteLLM 供應鏈攻擊解析;這裡專心完成你的資產與復原紀錄。
先說結論:曝險盤點=產物證據+執行邊界+憑證去向
把電腦想成辦公大樓:套件是收到的包裹,venv(Python 的獨立套件環境)是房間,憑證是房間裡能拿到的鑰匙。找到壞包裹後,還要知道它進過哪些房間、那些房間通往哪裡。換掉包裹與讓舊鑰匙失效,是兩項要各自驗收的工作。
- 先由乾淨的管理裝置隔離可疑工作負載,保全既有日誌及快照;避免在原環境啟動 Python、pip、Notebook 或 IDE 的 Python 工具。
- 一個主機可以有多個 venv;一個容器標籤可以指向不同產物。每個執行環境各填一列,再把共用主機與憑證連起來。
- 查到受影響成品,與確認已外傳資料,分開記錄;證據缺漏的環境保留「無法排除」,繼續處理。
一、LiteLLM 曝險盤點先圈時間,別把下架當成截止線
官方列出的受影響 PyPI 版本是 litellm==1.107.0 的七個 wheel;wheel 是預先打包的 Python 安裝產物。容器則涉及 v1.107.0、latest、main-latest、main-stable。下圖把發布紀錄換算成 UTC+8,方便對照本地 CI(持續整合,自動建置與測試流程)紀錄;原始時間也保留。

時間線用來縮小搜尋範圍,不是用來替較晚啟動的環境排除風險。例如在窗口內下載的 wheel,隔天才從 CI 快取安裝,仍須核對。同樣地,今天 registry 的 latest 已換乾淨,也回答不了昨天那個容器跑了什麼。請保存紀錄使用的時區,統一換算後再比較。
二、第一步「先封住門」:隔離與保存證據
服務正在執行,能不能先查一下?先在管理平面處理隔離。由乾淨裝置,透過雲端、虛擬化或編排系統的管理入口限制可疑工作負載對外連線,並防止排程器自動補回同一污染映像。記下誰在何時改了什麼,再由事故負責人安排快照、日誌與必要的程序證據保存。發現正在外傳時,立即圍堵,不為追求完整取證而延後止損。
不要先刪掉所有檔案或重建唯一一份磁碟;那會讓後續追查失去材料。也別把新金鑰貼回可疑主機。後面的檔案命令限定在乾淨 Linux 救援環境,讀取已掛成唯讀的證據副本;/mnt/evidence 是範例掛載點,由管理者先確認。沒有這個條件,就先完成日誌與工作表,不在原機照貼。
三、第二步「只看包裝」:不啟動 Python 的檔案核對
為什麼連 pip show 都先避開?Python 3.14 的 site 文件說明,一般啟動會處理套件目錄中的 .pth 可執行行,也會嘗試載入 sitecustomize。本次樣本正利用這類啟動掛鉤。範圍是會載入污染套件路徑的 Python 環境,不是只要電腦上有一份壞檔,就能斷言所有直譯器都已執行它。
先找安裝記錄及可疑檔名。以下只搜尋普通檔案,不執行搜尋結果;末尾的 sed -n l 將不可見字元以轉義形式顯示。搜尋錯誤也要留存;出現拒絕存取,代表那個範圍尚未查完。
find /mnt/evidence -type f \( -path '*/litellm-*.dist-info/METADATA' -o -name 'cook.pth' -o -name 'cook.py' -o -name 'sitecustomize.py' \) -print | LC_ALL=C sed -n l
找到實際路徑後,只讀出 METADATA 裡的名稱和版本。將下面的範例路徑換成剛才找到的檔案,保留單引號:
LC_ALL=C sed -n '/^Name: /p;/^Version: /p' '/mnt/evidence/app/.venv/lib/python3.12/site-packages/litellm-1.107.0.dist-info/METADATA' | LC_ALL=C sed -n l
預期看見 Name: litellm 與 Version: 1.107.0,表示副本中有這份安裝中繼資料。依 Python 安裝記錄規格,同目錄的 RECORD 記錄安裝檔案;可交給調查者比對快取 wheel、雜湊與實際內容。版本資料與 RECORD 都是證據線索,遭入侵系統上的文字檔仍可能被改寫。
只找到 sitecustomize.py,先記「待比對」,因為這也是 Python 合法使用的檔名。SafeDep 的原始樣本分析把本次 wheel 中的 cook.pth、cook.py 與 sitecustomize.py 連到蒐集及後門流程;應結合位置、套件記錄與內容識別,別把檔名搜尋當成萬用掃毒。找不到指標也不等於乾淨:副本範圍、清理與短命容器都可能留下缺口。
四、第三步「把箱號對上」:CI 與容器各留什麼?
從已保存的 CI 安裝輸出、套件庫下載記錄、lockfile 與建置紀錄找版本、下載時間及 artifact hash。lockfile 記的是預期配方;安裝輸出和產物記錄才補上當時實際取得什麼。別為了補紀錄,重新啟動那個 CI job。也要查間接依賴,因為你可能透過另一個工具帶入 LiteLLM。
容器部分,請在乾淨管理裝置,連到已確認的 Docker 管理端,查現存容器的中繼資料。將 CONTAINER_ID 換成真實 ID;以下不使用 docker exec、不重啟容器、不拉取污染版本:
docker container inspect --format '{{.Image}}' CONTAINER_ID
docker container inspect --format '{{.Config.Image}}' CONTAINER_ID
第一行記容器使用的本地 image ID;第二行記建立時給的映像參照。把第一行的結果填入 IMAGE_ID,再查:
docker image inspect --format '{{json .RepoDigests}}' IMAGE_ID
命令語法依 container inspect 與 image inspect 文件。只取必要欄位,避免把完整 inspect 裡的環境變數秘密貼進工單。若 daemon 或主機也疑似遭控制,把回覆視為待交叉核對證據,另取 registry、編排系統與部署日誌。
這裡有三種「箱號」:本地 image ID、單一平台 manifest digest、多平台 index digest。Docker 的 digest 說明指出,一個 index 可以再指向多個平台映像;不同層級的值本來就可能不同。請記錄 repository、平台與識別層級,對照事件頁清單及當時的 index→平台映射。官方完整列出的主要 index 是 sha256:1bbcb1443bc962e45f5aad53fe3d2c30600e0379715fb6c664cdd3ac126c339e;其他變體要各自核對。
RepoDigests 空白,或本地 ID 跟公告 index 不相等,都不能直接填「排除」。把缺的映射寫出來,交由保存了 registry 紀錄的人補齊;別重新 pull 受影響標籤來做比對。
五、LiteLLM 曝險盤點工作表:每個環境各填一列
不要把一台筆電只填成「有/沒有」。複製下面欄位到內部工單;只記憑證名稱或遮罩後的識別碼,不填秘密值。這是本文建議的工作格式,不是官方偵測工具。
- 環境:主機代號__;負責人__;venv 路徑/容器 ID__;可用證據範圍__。
- 產物:來源__;版本__;wheel hash/repository+digest+層級+平台__;證據位置__。
- 時間:下載/安裝__;第一次與最後一次可能啟動__;時區__;出站連線證據__。
- 可達範圍:執行帳號__;掛載目錄__;服務身分__;能讀的金鑰/資料庫/雲端角色__。
- 處置:狀態__;隔離證據__;撤權收據__;乾淨重建版本與 hash__;日誌查核__;未解項目__。
狀態用三格理解:已確認接觸受影響產物,有版本或產物證據,並另記是否啟動;無法排除,記錄缺漏或層級尚未對上;已排除此列已知產物,有相互支持的安裝與部署證據。第三格只針對這一列及這起事件,不能當成整台主機的安全保證。確認安裝過 1.107.0 且能連外時,依事件頁的保守處理建議,按可能外傳安排撤權。
完整走一次:筆電、CI、正式容器怎麼分?
假設甲的筆電救援副本有 1.107.0 的 METADATA,IDE 曾啟動該 venv;填「已確認接觸,曾執行」,並追到該使用者可讀的工作金鑰。乙的 CI 只留下一份舊 lockfile,下載紀錄已遺失;填「無法排除」,追 runner、共用快取與當時注入的部署憑證。丙的正式容器只有一個平台 digest,公告卻列 index;先補映射,不急著填排除。
三列可以指向同一把部署金鑰。只要其中一列需要撤銷,它在其他環境的使用也要一併換掉;反過來,也不要把某個容器內沒有掛載的私人目錄,直接算成已讀取。以實際權限畫關係,才知道復原會影響哪些服務。

六、第四步「換房間,也換鑰匙」:重建、撤權與驗收
能不能直接 pip 降版結案?先把可疑環境保留作調查,另建乾淨環境。由已核准的作業系統或基底映像重新部署,重新核對完整依賴與來源;不要複製舊 venv、Python 啟動檔或未審核快取。事件頁當時建議暫時固定 1.106.2;這是該次事件的處理快照,不代表它涵蓋所有後續漏洞。選版時要再核對當日安全公告與修補狀態。
依 pip 的可重複安裝說明,固定版本之外還能保存依賴雜湊。請從乾淨建置流程產生經審核的版本與 hash 清單;hash 的用途是辨認同一份內容,若核准的原本就是惡意產物,固定 hash 也會把它保留下來。
撤權與重建可以並行,不要等待新服務驗收完才處理舊憑證。先從高權限且可向外橫移的雲端、發布與部署身分開始,再處理可達的模型供應商金鑰、Proxy master/virtual keys、資料庫密碼及其他工作階段。為每項留下撤銷時間、替換位置與供應商端確認;新憑證只進乾淨部署。
臨時雲端角色也要處理。以 AWS 為例,IAM 撤銷角色工作階段文件提供 IAM → Roles → 指定角色 → Revoke sessions → Revoke active sessions 路徑;它會影響該角色較早取得的工作階段,不能只按一下就讓仍能取新憑證的污染工作負載繼續在線。先封住重新取得權限的入口,並評估共用角色的服務中斷範圍。
最後查供應商用量、帳單、金鑰使用紀錄與雲端活動,從最早可能接觸起查到撤權後。AWS 的 CloudTrail Event history按區域提供近 90 天管理事件,並不涵蓋所有資料事件或網路活動;要結合已啟用的其他日誌。帳單正常、沒有找到單一外傳標記,都只是一項觀察,不能抵掉憑證處理。
結案時分開簽三張收據:污染工作負載已停止並隔離;新環境的來源與依賴可追溯;舊憑證已失效且外部活動已查核。每張寫負責人、時間與證據位置。功能測試通過,就填功能通過;安全未解項目繼續保留。
七、常見問題:八個直接答案
1. 沒有 import LiteLLM,就可以排除嗎?
不可以只靠這一點。會載入污染路徑的 Python 啟動流程可能先執行掛鉤,應查安裝與啟動證據。
2. 可以在原 venv 執行 pip show 嗎?
先避開。使用救援副本的文字證據與既有日誌,別為查版本再啟動可疑 Python。
3. 只有下載 wheel,還沒安裝呢?
下載證據與執行證據分開記。隔離快取、禁止後續使用,再核對是否曾被安裝、建置或交給其他工作負載。
4. 找到 sitecustomize.py 就確定中毒嗎?
檔名本身不夠。這也是合法啟動模組名稱,要比對位置、安裝記錄及樣本內容。
5. 今天 latest 已乾淨,舊容器也會變嗎?
不能這樣推。先查舊容器的實際 image ID、digest 與建立紀錄,再安排乾淨重建。
6. 容器沒有掛主機家目錄,就不用撤權嗎?
仍要盤點容器能讀的環境變數、服務帳號、資料庫與掛載秘密;處理範圍依實際可達權限決定。
7. 重建好了,舊金鑰可以繼續用嗎?
對可能曝露的金鑰應撤銷或輪替。重建換掉程式,供應商端失效才處理已被複製的鑰匙。
8. 不懂命令,現在先做什麼?
先填環境、負責人與紀錄位置,把不確定的地方寫出來,交給有管理權限的人接手;不要自行下載污染版本試驗。
給新手的三個重點
- 每個環境各一列:把「有證據」與「缺證據」都留下。
- 每個識別碼寫清層級:版本、image ID 與 digest 各回答不同問題。
- 每把可達憑證有收據:停止、重建與撤權都要能核對。
接著閱讀
左右滑動查看更多推薦
下一步:今天先交出第一列完整紀錄
回到開頭的把手:曝險盤點=產物證據+執行邊界+憑證去向。今天先選一個環境,填完它的來源、版本、時間、可達秘密與未解項目,再指派下一位負責人。先讓一列可核對,再擴大到整個部署。想繼續建立可接手的工作流,可從AlphaLab AI 專區補齊觀念,或到AlphaLab 線上課程選下一個練習。






