TIMELINE10月21日の時系列
悪性の1.107.0は、遅くとも約1時間13分後にはPyPIから消えていた
-
19:44 1.106.2
公開。いまの安全な版
-
20:39 1.107.0
8ファイルが公開される
-
同日 報告と解析
GitHub Issue・GMO Flatt Security
-
21:53 削除済み
削除の時刻は未確認
LiteLLM マルウェアが PyPI で見つかりました。LLM の API を1つの書き方で呼べるようにする Python のライブラリ LiteLLM(PyPI の litellm)に、2026年10月21日、情報を盗む infostealer を仕込んだ 1.107.0 が公開されたものです。GMO Flatt Security(以下 Flatt)によれば、3月の 1.82.7・1.82.8 とは別の再侵害で、入れた環境から SSH 鍵やクラウドの認証情報など16種類の秘密を集めて送り、バックドアを常駐させます。安全な版は 1.106.2 です。依存パッケージから入る攻撃の全体像はサプライチェーン攻撃とは|手口・防御ツール比較・npm 12の新機構まで実践解説にまとめています。
30秒でわかる
・何が起きたか:PyPI の litellm 1.107.0 に情報を盗むマルウェアが入っていた。日本時間 10/21 20:39 に公開され、21:53 には PyPI から消えていた
・盗むもの:Flatt によれば SSH 秘密鍵・AWS/GCP/Azure の認証情報・ブラウザに保存したパスワード・AI 開発ツールの設定・環境変数・Kubernetes のトークンなど16種類
・入ったあと:暗号化して www[.]litellm[.]dev へ送り、遠隔でコードを動かすバックドアをデーモンとして常駐させる(Flatt)
・安全な版:1.106.2。rc 版(1.107.0rc1・rc2)が影響を受けるかは未確認
まずやること
・開発者・CI の担当:10/21 20:39〜21:53 に pip install・uv lock・依存の自動更新が走らなかったかを確かめる。疑いのある環境では python と pip を起動しない(理由は確かめ方の節)
・入れていた場合:鍵とトークンを別の端末から失効・再発行し、マシンやコンテナは作り直す。pip uninstall だけで常駐したバックドアが止まるとは限らない
・入れていない場合:litellm を 1.106.2 などに固定し、公開直後の版を選ばない設定を足す
LiteLLM 1.107.0 で何が起きたか(時系列)
日時は日本時間です。PyPI の公開時刻は、配布ファイルごとの upload-time(UTC)を換算しました。
| 日時(JST) | 出来事 | 出典 |
|---|---|---|
| 10/18 16:54 | 1.107.0rc1 を公開(rc2 は 10/20 12:17)。影響は未確認 | PyPI |
| 10/21 19:44 | 1.106.2 を公開。いまの最新の正式版 | PyPI |
| 10/21 20:39:51〜20:40:13 | 1.107.0 の8ファイル(OS・CPU 別の wheel 7つと sdist)を公開 | PyPI |
| 10/21 | GitHub に Issue #47826。題は「1.107.0 の PyPI の wheel が侵害されている」で、cook.pth と sitecustomize を挙げ、git のタグには無いとする |
第三者の報告 |
| 10/21 | Flatt が Takumi Guard の解析基盤で観測し、解析を公開。速報のため不正確な点を含みうると断っている | Flatt |
| 10/21 21:53 までに | 1.107.0 が PyPI から消える。yank ではなく削除で、誰がいつ消したかは未確認 | PyPI |
公開から削除までは、長くても約1時間13分です。1.107.0 は rc ではない正式版の番号で 1.106.2 より新しいため、版の指定がこれを許す範囲なら、pip も uv も最新の正式版として選びます。版を固定せずに pip install litellm をした環境、lock を作り直した環境、litellm を範囲指定で依存に持つパッケージを入れた環境が当てはまります。10/21 22:00 の時点で、LiteLLM の GitHub のセキュリティアドバイザリにこの件は載っていません。
3月の侵害との違い
| 2026年3月 | 2026年10月(今回) | |
|---|---|---|
| 悪性の版 | 1.82.7・1.82.8 | 1.107.0 |
| 安全な版の目安 | 1.82.6、1.83.0 以降 | 1.106.2 |
| 攻撃者・侵入経路 | TeamPCP。Trivy から連鎖して PyPI の公開用トークンを得た | 未確認 |
| 送信先 | models.litellm[.]cloud | www[.]litellm[.]dev |
| 起動のしかけ | litellm_init.pth(1.82.8) | Issue の題では cook.pth と sitecustomize(Flatt の TL;DR には無い) |
3月の経緯はLiteLLM 1.82.7/1.82.8がPyPIで侵害 — サプライチェーン攻撃で緊急アップデート推奨、その後に分かった被害の規模はLiteLLM×TeamPCP続報:434K CI/CD暴露の被害全貌とFBI警告・自システム確認コマンドにあります。同じ攻撃者かは、今回の公表の範囲では分かりません。
LiteLLM マルウェアが盗むものと、入ったあとの動き
WHAT IT DOES入ったあとの動き
盗んだ秘密を暗号化して送り、そのあとも居座る
-
入る
pip install で 1.107.0
-
集める
SSH 鍵など16種の秘密
-
暗号化
AES と RSA の2段で包む
-
送る
HTTP POST で www[.]litellm[.]dev へ
-
居座る
C2 を取り直して常駐
Flatt の解析によれば、マルウェアは次の順に動きます。
・16カテゴリの秘密を集める。挙がっているのは SSH 秘密鍵、AWS・GCP・Azure の認証情報、ブラウザに保存したパスワード、AI 開発ツールの設定、環境変数、Kubernetes のサービスアカウントトークン、LiteLLM のデータベース認証情報など
・AES-256-CBC と RSA-OAEP で暗号化し、http://www[.]litellm[.]dev/healthcheck へ HTTP POST で送る
・GitHub 上のドメイン設定ファイルから C2 のドメインを取り、遠隔でコードを動かすバックドアをデーモンとして常駐させる
16カテゴリの残り、常駐するプロセスの名前、ファイルの置き場所は未確認です。C2 は GitHub 上の設定から取り直す作りなので、www[.]litellm[.]dev を1つ止めても、送り先が差し替えられれば通信は止まりません。
盗まれうる範囲は、マルウェアが動いたときの利用者の権限で読めるもの全部と考えておくのが安全です。開発者の端末なら本人のホームディレクトリ、root で pip install する CI やコンテナならそのマシン全体になります。
| 盗まれうるもの | 攻撃者ができること |
|---|---|
| SSH 秘密鍵 | 鍵が通るサーバーや Git ホスティングに入る |
| クラウドの認証情報 | その権限でクラウドの資源を読む・作る・消す |
| Kubernetes のトークン・設定 | クラスタの API をその権限で呼ぶ |
| 環境変数(LLM の API キーなど) | 有料の API を使う。つながる先のデータを読む |
| LiteLLM の DB 認証情報 | プロキシの DB にある設定や利用の記録を読む |
| npm・PyPI・GitHub CLI のトークン | 自分のパッケージやリポジトリに次の悪性コードを入れる |
1.107.0 の LiteLLM マルウェアを入れたかの確かめ方(Python を起動しない)
疑いのある環境では、pip show litellm や python -c "import litellm" を打たないでください。Issue の題にある .pth と sitecustomize は、どちらも Python が起動のたびに自動で読み込むしかけです(Python の site モジュールの仕様)。当サイトで無害な .pth を置いた仮想環境を作ったところ、pip show と pip list を打つだけで中身が実行されました。確かめるための起動が、もう一度マルウェアを動かしかねません。以下はファイルの名前と記録だけを読みます。
リポジトリと CI のログ
依存の自動更新(Renovate・Dependabot)の PR が 1.107.0 に上げていれば、その PR の CI で入っています。リモートの全ブランチを見ます。
git fetch --all --prune
# requirements・lock・pyproject・Dockerfile から 1.107.0 の指定を探す(rc・dev 版は拾わない)
git grep -niE 'litellm(\[[^]]*\])?(==|-)1\.107\.0(-|\.tar|\.dist-info|[^-.0-9a-z]|$)' $(git for-each-ref --format='%(refname:short)' refs/remotes) -- '*requirements*.txt' '*.lock' '*pyproject.toml' '*Dockerfile*'
# Pipfile.lock は版が別の行に書かれる。==1.107.0 と出たら該当(いまのブランチだけを読む)
jq -r '.default.litellm.version, .develop.litellm.version' Pipfile.lock
CI のログは、その時間帯の実行を開いて litellm-1.107.0(pip の Successfully installed の行)か litellm==1.107.0(uv の + の行)を探します。消したブランチや使い捨てのランナーの実行は、git grep には出てきません。
インストール先とコンテナイメージ
# Python も pip も起動しない。ファイルの名前だけで探す(権限の無い場所のエラーは無視してよい)
find / -path /proc -prune -o -name 'litellm-1.107.0.dist-info' -print
find / -path /proc -prune -o -name 'cook.pth' -print
# コンテナは起動せずに中のファイル名を見る("my-app:latest" は自分のイメージ名に置き換える)
cid=$(docker create "my-app:latest" true)
docker export "$cid" | tar -t | grep -E 'litellm-1\.107\.0\.dist-info/$|(^|/)cook\.pth$'
docker rm "$cid" >/dev/null
pip や uv は、入れたパッケージの版をフォルダ名にして .venv/lib/python3.12/site-packages/ や /usr/local/lib/python3.12/site-packages/ に残します。1つ目の find は 1.107.0 のフォルダ(litellm-1.107.0.dist-info)だけを探し、出たら該当です。1.106.2 や rc2 のフォルダは出ません。uv のキャッシュ(~/.cache/uv/archive-v0/ の下)に出た場合は、そのマシンで一度取り込んだ形跡です。2つ目の find の cook.pth は Issue の題にある名前で、LiteLLM と Flatt は確認していません。置かれるとすれば同じ lib/python3.12/site-packages/ の直下です(Python の版の数字は環境で変わります)。
docker create はコンテナを作るだけで起動しないので、イメージの中の .pth は動きません。Docker を動かしているホストで find を打つと、手元にあるイメージの中身として /var/lib/docker/ の下のパスが出ることもあります。そのときはイメージ名を突き止めて、docker の3行で確かめます。
外向き通信の記録
# プロキシ・DNS のログの置き場所に合わせて、パスを置き換える
grep -rniE 'litellm\.dev\.?([^a-z0-9.-]|$)' "/var/log/squid/"
Squid のアクセスログ、BIND のクエリログ、Route 53 Resolver のクエリログ(末尾に . が付く)を模したダミーで、該当の行だけを拾い、docs.litellm.ai などの正規のドメインは拾わないことを確かめました。実際の各サービスのログでは未検証です。VPC Flow Logs には IP アドレスしか残らず、送信先の IP は公表されていないので、この方法では使えません。
結果の読み方
この確認は、入れた形跡の有無を見るもので、感染の判定ではありません。
・1.107.0 の名前や通信が見つかったら、入れた前提で次の節へ進む
・見つからなくても、安全とは言えない。pip のキャッシュはファイル名で残らず、作り直したコンテナ、消した仮想環境、保存期間を過ぎたログは確認に出てこない
・rc 版を入れた環境はこの確認に出てこない。rc の影響は未確認なので、告知が出たら確かめ直す
入れていたらやること:鍵のローテーションと環境の作り直し
替えることと、悪用されていないかを調べることは別の作業です。順に進めます。
・つなぎを切る:該当マシンの外向き通信を止める。C2 は差し替えられうるので、ドメイン1つのブロックで済ませない
・鍵を替える:感染したかもしれないマシンの外で、失効と再発行をする。新しい鍵をそのマシンに置くと、常駐したバックドアにまた渡しかねない
・作り直す:マシン・コンテナ・CI ランナーを、既知の良いイメージから作り直す。pip uninstall で消えるのはパッケージのファイルで、動いているデーモンが止まるとは限らない
・使われたかを調べる:替える前の鍵が使われた記録を、クラウドの監査ログや Git ホスティングのログで確かめる
Flatt が即座のローテーションを勧めている対象は次のとおりです。
| 対象 | 替え方の要点 |
|---|---|
| SSH・GPG・TLS の秘密鍵 | 鍵を作り直し、サーバーの登録・公開鍵・証明書を差し替える |
| AWS・GCP・Azure の認証情報 | アクセスキーやサービスアカウントの鍵を失効し、再発行する |
| Kubernetes の config・Docker の config | kubeconfig の資格情報、レジストリのトークンを作り直す |
| npm・PyPI・GitHub CLI のトークン | 失効して再発行する。この期間に覚えのない版が公開されていないかも見る |
| ブラウザに保存したパスワード | 保存していたサイトのパスワードを替える |
| AI ツール(Claude・Cursor・Copilot・Gemini・Codex)の認証 | ログアウトし、API キーは失効して再発行する |
環境変数に置いた LLM の API キーと、LiteLLM プロキシの DB のパスワードも替えます。
再発を防ぐ:LiteLLM の版の固定・ハッシュ・公開直後の版を待つ
INSTALL GATE入れる前の門
公開から3日待つ設定なら、今回の1.107.0は選ばれない
依存の解決
- 固定lock の版とハッシュ 通す1.106.2 を lock から入れる
- 待つ3日未満の版 選ばない1.107.0(公開直後)
- rcプレリリース 選ばない1.107.0rc2(--pre なし)
- 例外急ぐ修正版 通す人が確かめて個別に許可
今回の 1.107.0 は、公開から1時間あまりで消えました。公開から数日たった版だけを選ぶ設定なら、選ばれる前に消えていたことになります。
| 対策 | 書き方の例 | 今回の 1.107.0 | 限界 |
|---|---|---|---|
| 版の固定とハッシュ | litellm==1.106.2 と --require-hashes、uv.lock・poetry.lock から入れる |
lock を作り直さなければ入らない | lock を作り直した時点で新しい版を取る |
| 公開から日数を置く | pip の --uploaded-prior-to P3D(環境変数 PIP_UPLOADED_PRIOR_TO)、uv の exclude-newer = "3 days" |
選ばれない | 急ぎの修正版も遅れる。pip は upload-time を返さない索引では効かない |
| プレリリースを入れない | --pre を付けない |
正式版の番号なので止まらない | rc の扱いは今回は未確認 |
| 中継で検疫する | 私設のミラーや、Takumi Guard のような中継 | 中継の判定しだい | 中継の運用が要る |
当サイトで 2026-10-21 に試したところ、pip 26.2.2 に --uploaded-prior-to P3D を付けると、当日公開の 1.106.2 を外して 1.106.0 を選びました。uv 0.11.32 でも pyproject.toml の [tool.uv] に exclude-newer = "3 days" を書くと同じ結果で、uv.lock に exclude-newer-span = "P3D" が残ります。pip 24.0 にはこのオプションが無いので、古い pip では使えません。
日数を置くと、急ぎの修正版も同じだけ遅れます。uv の --exclude-newer-package のように個別に外す道を用意し、外すときは人が中身を確かめます。依存の自動更新で同じ待ち時間を置く設定は、Renovate・Dependabotの自動PRがマルウェアを運ぶ:違いの比較と今すぐ確認すべき安全設定で扱っています。
参照ソース
・GMO Flatt Security Blog — LiteLLM の2度目の侵害の解析 — 再侵害であること・悪性の版と安全な版・16カテゴリ・暗号化・送信先・常駐・ローテーションの対象(2026-10-21)
・BerriAI/litellm Issue #47826 — 第三者による報告。cook.pth・sitecustomize・git のタグには無いという主張
・PyPI — litellm — 各版の公開時刻、1.107.0 が消えたこと、最新が 1.106.2 であること(2026-10-21 21:53 JST に確認)
・Python documentation — site — .pth の import の行と sitecustomize が起動時に読み込まれること
・GitHub Advisory GHSA-5mg7-485q-xm76 — 3月の 1.82.7・1.82.8 の事案





