先に要点
- AI モデルの呼び出しを一つの窓口にまとめる LiteLLM で、2026年10月21日に、認証情報を盗む悪性コードを含む 1.107.0 が PyPI と Docker に公開されました。公式の告知によると、これより前の版は安全で、GitHub 上のソースのタグ自体には悪性のファイルは入っていません。
- 影響を受けたのはごく短い時間です。PyPI は協定世界時(UTC)の 11:39〜13:23(日本時間 20:39〜22:23)、Docker の
v1.107.0・latest・main-latest・main-stableは 11:46〜14:20(日本時間 20:46〜23:20)。この間に版を固定せずに入れた、または該当のイメージを起動した場合が対象です。 - 確認は
pip show litellmで 1.107.0 が入っていないかを見ます。入っていたら、その環境は侵害されたものとして扱い、到達できた認証情報をすべて入れ替えます。最初に pip を実行してはいけません。Python を起動するたびに悪性のファイルが再実行されるためです。 - 今後に向けては、版の固定(1.106.2 以前の明示した版)、ハッシュの固定、Docker のダイジェスト固定で、数時間の混入に当たらない運用にします。
LiteLLM を自分で入れている、または社内の AI 基盤が内部で使っているかもしれない、という方向けの記事です。自分の環境が当たっていたかを確かめ、当たっていたときの復旧を一通りたどれるようにまとめました。
この記事は、LiteLLM の公式の告知(2026年10月21日公開、10月30日更新)をもとにしています(2026年10月31日に確認)。告知には調査の途中で書かれた推測が含まれ、後から不正確または不完全と分かった部分があると本人たちが明記しているため、原因の詳細は書かず、確かめられた事実と対応に絞ります。公式の告知の最新の内容を、作業の前に必ず確かめてください。
何が起きたのか:1つの版が数時間だけ配られた
まず、時系列と範囲を整理します。公式の告知から、確かめられた事実を並べます。
| 協定世界時(日本時間) | 出来事 |
|---|---|
| 11:39〜(20:39〜) | 悪性のコードを含む litellm 1.107.0(7つの wheel)が PyPI に公開された |
| 11:46〜(20:46〜) | Docker のイメージ(Docker Hub と GHCR)の同じ版とタグが、悪性の内容を指した |
| 13:23(22:23) | PyPI から 1.107.0 が削除された |
| 13:51(22:51) | GHCR の該当タグが利用できない状態になった |
| 14:20(23:20) | Docker Hub の該当タグがすべて削除または安全なものへ付け替えられた |
公式の告知によると、GitHub 上の 1.107.0 のソースのタグには悪性のファイルは入っていません。攻撃者が管理するリポジトリからビルドされた成果物が、公式の名前で配布されました。ソースを読んで安全だと判断しても、実際に入る成果物が同じとは限らない、という事例です。
悪性の成果物は、認証情報を盗み、さらに外部からコードを取り込んで実行する仕組みを持っていた、と告知は説明しています。LiteLLM の企業向けの非公開の配布(エンタープライズ版)は影響を受けていません。
同じ名前の事案は3月にもあった
LiteLLM は2026年3月にも、PyPI に悪意のある版(1.82.7 と 1.82.8)が公開される事案を起こしています(GitHub のセキュリティアドバイザリ GHSA-5mg7-485q-xm76)。告知によると、3月の後で配布の流れを強化していましたが、今回はその仕組みの別の部分が突破されました。一度対策した後でも、同じ種類の事故は起こりうると考えるのが現実的です。
自分の環境は当たっていたか:確かめる3点
公式の告知が示す、対象かどうかの条件は次のとおりです。
| 使い方 | 当たる条件 | 確かめ方 |
|---|---|---|
| pip で入れた | 上の時間帯に、版を固定せずに入れた、または更新した | pip show litellm の版が 1.107.0 でないか |
| Docker で動かす | 上の時間帯に、該当するタグ(v1.107.0・latest・main-latest・main-stable)を起動した |
起動したイメージのダイジェストが、告知にある侵害されたものと同じでないか |
| 企業向けの非公開配布 | 当たらない(影響なし) | 提供元の案内 |
確認には、次のようなコマンドが使えます(以下は筆者が例として書いたもので、公式の手順ではありません)。
# 版を確かめる(1.107.0 でなければ、この件の対象ではない)
pip show litellm
# Docker のイメージとダイジェストを一覧する
docker images --digests | grep litellm
告知は、侵害されたイメージのダイジェストを sha256:1bbcb1443bc9… で始まるものと示しています。完全な値は公式の告知で確かめて、手元のものと照らします。
ファイルの痕跡としては、告知は litellm-1.107.0.dist-info、cook.pth、sitecustomize.py の探索を挙げています。1つでも見つかれば、影響を受けた確証です。一方で、見つからなくても、無事だという証明にはならないと告知は注意しています。なお、sitecustomize.py は別の目的で置かれている場合もあるので、この名前だけで判断せず、cook.pth や版の記録と合わせて見ます(筆者の考えです)。
なぜ「入れただけ」で動くのか:.pth ファイルの仕組み
今回の混入が厄介だったのは、LiteLLM を使うコードを書いていなくても、その環境で Python を起動するだけで悪性の処理が動く形だったことです。
.pth ファイル
Python は起動のたびに、ライブラリの置き場(site-packages)にある .pth ファイルを読みます。そこに書かれた行が実行されるため、パッケージを入れただけで、次の起動から自動で動く仕組みに使えます。
この仕組みは LiteLLM に限りません。Python のパッケージを入れる行為は、そのパッケージの作者が用意したコードを、環境で動かすことだと言い換えられます。サプライチェーンの考え方は サプライチェーンとは でも整理しています(pip、サプライチェーン)。
当たっていたときの復旧:順序が大切
公式の告知は、当たった環境について次の対応を示しています。順序が大切です。
当たっていたときの復旧の流れ
- 1
- 2悪性のファイルと常駐を取り除く
シェルから、cook.pth、cook.py、sitecustomize.py と、対応する __pycache__ のファイルを、影響のあった site-packages から削除する。/tmp/remote_code_loader.lock を握っている常駐の Python を止める。
- 3固定した版で入れ直す
litellm==1.106.2 など、事故より前の明示した版で入れ直す。イメージや仮想環境は、作り直すほうがよい。
- 4盗まれたと想定して認証情報を入れ替える
外部に通信できるホストで 1.107.0 が動いたなら、情報が持ち出されたと想定する。到達できた認証情報をすべて入れ替える。
- 5クラウドの記録を調べる
AWS なら CloudTrail で、事故の時刻の前後に、インスタンスのロールによる GetCallerIdentity があったか、その後にロールの認証情報が社外から使われていないかを調べる。
入れ替える対象として、告知は次を挙げています。
| 入れ替える認証情報 | 理由 |
|---|---|
| インスタンスやタスクに付いたクラウドの権限(IAM ロール) | その環境から呼べる範囲が、そのまま盗まれうる |
| LiteLLM のプロキシのデータベースに保存したプロバイダーのキー、マスターキー、バーチャルキー | 各社の API キーが一括で盗まれうる |
DATABASE_URL のパスワード |
接続情報が環境変数に入っているため |
| そのホストのプロセスの環境変数に入っていた、あらゆるシークレット | 悪性のコードは、環境にあるものを集める |
ファイルを消しても、すでに持ち出された認証情報は有効なままです。「消した」と「安全になった」は別です。入れ替えと、クラウドの記録の確認までが復旧です。調べる材料(ログ、ファイルの時刻)は、消す前に別の場所へ控えておくと、あとで被害の範囲を判断できます(筆者の考えです)。
AI の API キーは、盗まれると他人にその料金で使われる被害にもなります。各プロバイダーの管理画面で、利用量の急な増加がないかも確かめてください。キーの扱いの基本は APIキーとOAuthの違い を参照してください(シークレット)。
これから:数時間の混入に当たらない運用
今回の混入は、公開から約2時間で PyPI から削除されました。その数時間に、たまたま版を固定せずに入れた環境だけが当たった形です。つまり、固定の運用があれば、当たる確率は大きく下がります。
版を固定する
requirements に litellm==1.106.2 のように、明示した版を書く。「最新を自動で入れる」運用をやめ、更新は自分たちの判断で行う。
ハッシュも固定する
pip には、ファイルのハッシュを指定して照合する --require-hashes があります。名前と版が同じでも、中身が違えば入りません。依存の先まで固定するにはロックファイルが要ります(uv・pip・venv・poetry の比較)。
Docker はダイジェストで固定する
latest のようなタグは、指す先が後から変わります。sha256:… のダイジェストで指定すれば、同じタグ名で別物が来ても取り込みません。イメージとコンテナの基本も参照してください。
公開直後の版を避ける
公開から日が浅い版を、すぐ取り込まない待ち期間を置く運用もあります。今回は約2時間で削除されたので、数日の待ちだけでも当たりませんでした。
開発基盤の側の固定には、GitHub Actions のロックファイル も参考になります。KEV では、2026年9月にも LiteLLM が載っており(KEVカタログとは?)、AI の呼び出し基盤は攻撃者から見て価値が高い対象になっています。
よくある質問
1.106.2 以前を使っていれば大丈夫ですか?
公式の告知は、これより前のすべての版は安全だとしています。1.106.2 に固定することを勧めています。ただし、その後に出る版については、更新のたびに公式の告知を確かめてください。
企業向けの非公開の配布を使っています。影響はありますか?
告知によると、非公開の配布元から取得している企業の顧客は影響を受けません。
影響の時間帯より前に入れた 1.106 系は、あとから 1.107.0 に変わりますか?
固定していなければ、「更新」を実行した時点で変わります。版が固定されていて、更新していなければ、変わりません。自動更新をしている環境は、更新の履歴を確かめてください。
痕跡が見つからなければ安全ですか?
告知は、見つからなくても環境がきれいだと証明できないと注意しています。時間帯に当たっていたなら、認証情報の入れ替えまで進めるのが安全です。
まとめ
- 2026年10月21日、LiteLLM の 1.107.0 が認証情報を盗む状態で PyPI と Docker に公開された。PyPI は UTC 11:39〜13:23、Docker は 11:46〜14:20。これより前の版は安全
- 確認は
pip show litellmと、Docker のダイジェストの照合。見つかれば侵害されたものとして扱う。見つからなくても無事の証明にはならない - 復旧は「pip を実行しない → 悪性のファイルと常駐を取り除く → 固定した版で入れ直す → 認証情報をすべて入れ替える → クラウドの記録を調べる」
- Python は起動のたびに .pth などを読むため、入れただけで動く。パッケージを入れることは、作者のコードを環境で動かすこと
- 今後は、版・ハッシュ・Docker のダイジェストの固定と、公開直後の版を避ける待ち期間で、数時間の混入に当たらない運用にする