はじめに
2026年10月21日、AI ゲートウェイとして広く使われている LiteLLM の公式版 1.107.0 に、資格情報を盗むコードが入った状態で配られました。PyPI では 11時39分〜13時23分(UTC・日本時間 20時39分〜22時23分)、公式の Docker イメージでは 11時46分〜14時20分(UTC・日本時間 20時46分〜23時20分)。合わせて最大約 2 時間 40 分です。Wiz は ClickPy のデータから、この版のダウンロードを約 49,000 回としています。
厄介なのは、入っていたコードが Python の起動フックで動く作りだったことです。アプリが LiteLLM を import しなくても、その環境で Python を起動するだけで動きます。pip も Python なので、pip uninstall で消そうとした瞬間にもう一度動きます。
この記事のゴールは、読み終えたときに次の 3 つが分かっていることです。LLM の呼び出しを束ねる「関所」が汚染されると、社会のどこに何が効くのか。1.107.0 を入れてしまった環境は、なぜ「戻す」だけでは足りず、鍵ごと入れ替える必要があるのか。そして、個人開発者と組織の側で、それぞれ何をすればよいのか。 自分の環境が対象かどうかの確かめ方は第 9 節に短くまとめています。
- 対象は 1.107.0 を pip などで入れた環境と、該当の Docker タグを該当時間帯に pull・起動した環境。LiteLLM は「それより前の版はすべて安全」としている。GitHub の v1.107.0 のタグ自体も無害で、汚染された版は偽のリポジトリ
Berri-AI/litellmから作られていた - 入れた環境では、外への通信ができたなら盗まれた前提で動く。版を戻すだけでは足りず、環境を作り直し、その環境から届いた資格情報をすべてローテーション(失効と再発行)する
- 侵入の起点は、5月に公開リポジトリへ誤ってコミットされ、失効されないまま残っていた 1 本の鍵だった。ログとトークンの設計、鍵の失効の徹底で防げる種類の事件でもある
LiteLLM は 10月21日の初報で、「Claude Code が応答の本文にユーザーの GitHub CLI の OAuth トークンを埋め込む場面があり、応答本文をログに残す設定だと、そのトークンが LiteLLM のログに残りうる」と説明し、攻撃者は社内の LiteLLM のログからトークンを得たとの見立てを示しました。報道の多くはこの説明を伝えています。
ところが LiteLLM は 10月23日、調査を終えたとして確定版の経緯を公開し、「最初のトークンは別のサービスから来ていた」と書きました。起点は、社内で試していた別のツール(LiteLLM Agent Platform)のマスターキーです。初報の記事には「調査中に書いたもので、一部の想定は不正確または不完全だった」との注記が付きました。詳しくは第 4 節で扱います。
Claude Code のふるまいについての説明は、どちらも LiteLLM の説明です。2026年10月31日時点で、Anthropic の公式な発表やコメントは、同社のニュースページ、Claude Code の変更履歴、Claude Code の GitHub のセキュリティアドバイザリを確認したかぎり見当たりません。Cloud Security Alliance(CSA)の 10月23日のノートも、確認した報道の範囲で Anthropic のコメントはなかったとしています。
🧭 1. LiteLLM とは ── LLM の呼び出しを束ねる「関所」
何をするソフトか
LiteLLM は、BerriAI が開発するオープンソースの Python ライブラリ兼プロキシサーバーです。OpenAI、Anthropic、Google、AWS Bedrock、Azure など、仕様の違う 100 以上の LLM の API を、OpenAI 互換の 1 つの書き方で呼べるようにします。使い方は大きく 2 つあります。
- SDK として:アプリの中で
litellm.completion(...)のように呼び、裏でモデルごとの API に変換する - プロキシ(AI ゲートウェイ)として:社内に 1 台のサーバーとして立て、各アプリや開発者はそこに向けて LLM を呼ぶ。ゲートウェイが本物の API キーを持ち、利用者には別の「仮想キー」を配る
チャットボット"] --> G B["開発者の
コーディングエージェント"] --> G C["CI の
テスト"] --> G G["LiteLLM プロキシ
(AI ゲートウェイ)"] --> P1["OpenAI"] G --> P2["Anthropic"] G --> P3["AWS Bedrock
など"] G --- D[("データベース
鍵・利用ログ")]
組織で LLM を使いはじめると、「どのチームが、どのモデルに、いくら使ったか」を管理したくなります。予算の上限、モデルの切り替え、障害時の別モデルへの振り替え、利用ログ。これを各アプリに書くのではなく、ゲートウェイ 1 か所でやる。LiteLLM はその定番の 1 つで、Socket の推計では週に約 2,300 万回ダウンロードされています(Help Net Security の報道による)。
何を預かっているか
ゲートウェイは便利な分、たくさんの秘密を 1 か所に集めます。
| 預かるもの | 中身 | 漏れたときの意味 |
|---|---|---|
| 上流の API キー | OpenAI・Anthropic などの本物の鍵 | 他人の課金で LLM を使われる |
| マスターキー・仮想キー | 管理者用の鍵と、利用者に配る鍵 | 管理画面の乗っ取り・設定の改ざん |
| データベースの接続情報 | DATABASE_URL のパスワード |
鍵や利用ログの一括の持ち出し |
| クラウドの権限 | 動いているサーバーの IAM ロールなど | そのクラウドの中での横展開 |
| 利用ログ(設定しだい) | プロンプトと応答の本文 | 本文に紛れ込んだ秘密の流出 |
最後の行が今回の初報で注目された点です。LiteLLM は既定ではプロンプトと応答の本文をログに残しません。store_prompts_in_spend_logs を有効にしたときだけ残ります。ただ、デバッグやコストの分析のために有効にする運用は珍しくありません。そしてコーディングエージェントの通信の本文には、エージェントが読んだファイルやコマンドの出力が入ります。そこにトークンが映り込めば、ログが「意図しない鍵の保管庫」になります。
さらに LiteLLM は、ゲートウェイとしてだけでなく、ほかの AI ツールの依存ライブラリとしても入っています。エージェントのフレームワークや MCP サーバー、評価ツールを入れたら、知らないうちに LiteLLM も入っていた、ということが起こりえます。3月の事件のときに LiteLLM 自身が、推移的な依存(依存の依存)として入った場合も対象になると書いています。
🐍 2. Python の起動フック ── import しなくても動く仕組み
Python が起動するときに読むもの
Python は、スクリプトを実行する前に site というモジュールを自動で読み込み、ライブラリの置き場所(site-packages)を整えます。このとき 2 種類のファイルを処理します。
.pthファイル:site-packagesに置かれた名前.pthは、本来「探索パスに追加するディレクトリ」を 1 行ずつ書くためのファイルです。ただし互換性のために、importで始まる行はそのまま実行される、という仕様がありますsitecustomize:パスを整えたあと、Python はsitecustomizeという名前のモジュールをimportしようとします。管理者がその環境全体の初期設定を書くための仕組みです
Python のドキュメントは、これらの実行行は「あるモジュールが実際に使われるかどうかに関係なく、Python の起動のたびに必ず実行される」と明記しています。つまり、site-packages に .pth を 1 つ置ければ、その環境で Python を起動するすべてのプロセスに、任意のコードを差し込めます。
(pip も含む)"] --> T["site モジュールが
site-packages を走査"] T --> P[".pth の import 行を
その場で実行"] P --> C["sitecustomize を
import"] C --> M["ここでやっと
本来のスクリプト"]
1.107.0 に入っていた 3 つのファイル
汚染された 7 種類の wheel(OS と CPU ごとの配布ファイル)には、本来の litellm ディレクトリの外に置かれる 3 つのファイル、cook.pth・cook.py・sitecustomize.py が入っていました。pip はこれを site-packages の直下に展開します。Microsoft と Wiz の解析によると、役割は次の 2 系統です。
cook.pth→cook.py:.pthの 1 行がcookを読み込み、暗号化して埋め込まれた収集プログラムを展開して実行する。ブラウザの保存パスワードと Cookie、AWS・Azure・Google Cloud の認証情報とメタデータサービス、SSH・GPG の鍵、シェルの履歴、AI のコーディングツールや IDE の設定、環境変数、そして LiteLLM プロキシのデータベースに入っている上流の API キーを集め、暗号化して偽のドメインwww.litellm.devに送るsitecustomize.py:Linux と macOS 向けに、GitHub 上のファイルを 1 時間ごとに見に行き、そこに書かれたサーバーから追加の Python コードを取ってきて実行する仕組み。調査の時点でそのファイルは空で、追加のコードが実行された確認はありません。GitHub はこのリポジトリを削除しています
送り先の www.litellm.dev は、公式の litellm.ai とは無関係の、似せたドメインです。CSA によると 10月13日に登録されていました。Wiz は、.pth と sitecustomize.py を同時に使う手口は「実際の攻撃で記録された初めての例とみられる」としています。
PyPI に上がる Python パッケージには 2 つの形があります。wheel(.whl)はビルド済みの配布ファイルで、pip は中身をほぼそのまま展開します。sdist はソースコードの形で、入れる側でビルドします。今回は 7 つの wheel すべてに 3 つのファイルが入っていました。sdist にはファイル自体は入っておらず、ビルドの設定に 1 行が足されていた、と第一発見者の issue は報告しています。
「pip で消す」が危ない理由
pip も Python のプログラムです。汚染された環境で pip show や pip uninstall を打つと、起動の時点で cook.pth が動きます。Microsoft は、Windows の観測例で「関係のない別のライブラリを入れるための、ごく普通の Python の起動」で収集プログラムが動いた、と報告しています。LiteLLM も Microsoft も、汚染が疑われる環境の中で Python や pip を起動しないこと、調べるならシェルや外の安全な環境から見ることを勧めています。
また、3 つのファイルは litellm のディレクトリの外にあるので、litellm のフォルダを消しても残ります。Microsoft が「消すより作り直すほうが確実」と書いているのはこのためです。
Python 3.15 では、.pth の import 行が非推奨になりました。代わりに、起動時に呼ぶ関数を パッケージ.モジュール:関数 の形で宣言する .start ファイルが加わっています(PEP 829)。ドキュメントによると、.pth の import 行は 3.18 と 3.19 では黙って無視され、3.20 では警告が出る予定です。起動時にコードを動かす仕組み自体は残りますが、「パスの設定ファイルに紛れた 1 行がコードとして動く」という分かりにくさは、段階的に減っていきます。
🔑 3. GitHub CLI のトークンと、リリースの流れ
GitHub CLI の OAuth トークンとは
GitHub CLI(gh コマンド)は、ターミナルから GitHub の操作をするための公式ツールです。gh auth login でブラウザからログインすると、gh は OAuth トークンを受け取って保存し、以後はそのトークンで API を呼びます。GitHub のマニュアルによると、このトークンに必要な最低限の権限(スコープ)は repo・read:org・gist です。repo は、その人が触れるすべてのリポジトリの読み書きを意味します。
このトークンには、次の性質があります。
- ログインした本人の権限をまるごと持つ:組織のオーナーがログインすれば、オーナーの権限で動く
- 2 要素認証の「後」に発行される:LiteLLM の確定版によると、GitHub CLI のトークンは、組織やリポジトリの重要な操作で求められる再認証の流れの対象外だった
- 見分けやすい形をしている:GitHub のトークンは種類ごとに接頭辞が付き、OAuth のアクセストークンは
gho_で始まる。秘密の検出ツールが見つけやすいように設計されている
AI のコーディングエージェントにリポジトリの操作をさせるとき、エージェントは多くの場合、開発者のこの gh のログインをそのまま使います。便利な一方で、エージェントが動く場所に、本人と同じ権限の鍵があるということでもあります。
公式版はどう作られ、どう配られるか
LiteLLM の初報によると、3月の事件のあと、リリースの流れは次のように固められていました。
ブランチとタグを切る"] --> B["② 結合テストで
候補を検証"] B --> C["③ 非公開リポジトリの
ワークフローでビルド"] C --> D["④ ビルド物を
試験環境で再検証"] D --> E["⑤ 専用アカウントの
承認で公開"] E --> F["PyPI と
Docker に署名付きで"]
公開の承認は、オフィスの特定の端末に紐づいた専用アカウントでしかできない設計でした。ただ、事件の直前の月曜日(10月19日)、顧客向けの修正版を毎日出すために、任意の 2 人のエンジニアで起動と承認ができるよう一時的に緩めていました。
ここで大事なのは、ビルドの手順が正規のままでも、「どのリポジトリのコードをビルドするか」を書き換えられれば、正規の署名が付いた汚染版ができてしまうことです。Datadog によると、ビルドの来歴(provenance)には偽のリポジトリが正直に記録されていました。来歴を確かめる側がいれば気づけた、ということでもあります。
PyPI の Trusted Publishing は、長く使える API トークンを CI に置かず、GitHub Actions などの実行ごとに短命の資格情報を発行して公開する仕組みです。LiteLLM も使っていました。ただし、これで確かめられるのは「決められたワークフローから公開された」ことまでで、「そのワークフローが正しいコードをビルドした」ことではありません。今回はワークフロー自体が書き換えられていました。
🗓️ 4. 何が起きたか ── 5月の鍵から、10月21日の 2 時間 40 分まで
確定版の経緯
LiteLLM が 10月23日に公開した確定版の経緯を、時系列で並べます。時刻は UTC です。
別ツールのマスターキーが
公開リポジトリに"] --> B["10月10日
そのキーで API を呼び
オーナーの gh トークン取得"] B --> C["10月10日・12日
捨てブランチの CI で
保守者 2 人のトークン"] C --> D["10月21日 10時08分
ブランチ保護を外し
ビルド元を偽リポへ"] D --> E["11時11分
盗んだトークンで
本番公開を承認"] E --> F["11時39分〜
PyPI と Docker に
汚染版が公開"] F --> G["12時06分
第三者が issue で
発見を報告"] G --> H["13時23分 PyPI
14時20分 Docker
から取り下げ"]
- 5月27日:LiteLLM が社内で試していた LiteLLM Agent Platform(クラウド上のエージェントに GitHub のプルリクエストを出させる実験的なツール)のマスターキーを含む設定ファイルが、公開リポジトリに誤ってコミットされた。すぐに気づいて履歴を上書きしたが、キーの失効は行われなかった
- 10月10日:攻撃者がこのキーで Agent Platform の API を呼び、登録されていた設定から、GitHub の組織オーナーの GitHub CLI トークンを取り出した。このトークンはサービス用のアカウントではなく、権限も絞られていなかった
- 10月10日・12日:オーナーのトークンで、使い捨てのブランチに CI のワークフローを足し、リポジトリに設定された秘密を外へ送らせた。こうして保守者 2 人分の GitHub CLI トークンを得て、実行記録は消した。Socket はこの 10月10日の実行を独自に見つけ、侵害の期間は少なくとも 11 日あったと指摘している
- 10月21日 10時08分:リリース用のリポジトリへの変更は、まずブランチ保護に拒否された。5 秒後、オーナーのトークンで保護を外して押し込み、ビルド元を偽のリポジトリ
Berri-AI/litellm(本物はBerriAI/litellm。ハイフン 1 つの違い)に向けた - 11時11分:2 人目のトークンで本番公開の承認を通した
- 11時39分〜11時40分:7 つの wheel が PyPI に、11時46分に Docker Hub と GHCR のイメージが公開された
- 11時53分:3 人目のトークンで、本番と試験の実行記録を削除した
- 12時06分:第三者(Upwind の研究チーム)が GitHub の issue #47826 で汚染を報告。LiteLLM は確定版で、公開から 20 分以内に見つけたとしてこの報告者に謝意を示している
- 13時23分までに PyPI が 1.107.0 を隔離、13時51分までに GHCR、14時20分に Docker Hub のタグ(
v1.107.0・latest・main-latest・main-stable)を削除または安全なイメージへ付け替えた
GitHub 上の公式の v1.107.0 のタグには、悪いファイルは入っていません。汚染された配布物は、偽のリポジトリのコミットから作られていました。LiteLLM の非公開レジストリから入れている Enterprise の顧客は影響を受けていない、と LiteLLM は説明しています。
盗まれた鍵の連鎖
| 鍵 | どう取られたか | 何に使われたか |
|---|---|---|
| Agent Platform のマスターキー | 5月に公開リポジトリへ誤コミット・失効されず | Agent Platform の API を読む |
| オーナーの gh トークン | 10月10日に Agent Platform の API が返した | 保護の解除・ビルド元の変更・痕跡の消去 |
| 保守者 2 の gh トークン | CI の秘密 GH_TOKEN を捨てブランチで外へ |
本番公開の承認 |
| 保守者 3 の gh トークン | 別リポジトリの CI の秘密を同じ手口で | 実行記録の削除 |
初報の説明と、Claude Code のこと
10月21日の初報で LiteLLM は、トークンの出どころを次のように説明していました。「調査の結果、Claude Code がユーザーの GitHub CLI の OAuth トークンを応答の本文に埋め込む特定の状況を確認した。応答本文がログに残る状況では、これらのトークンが LiteLLM のログに現れうる」。そのうえで、インターネットに公開されていた社内の LiteLLM に見慣れないユーザーが作られており、攻撃者はそこからログ経由でトークンを得たとみている、と書きました。The Next Web などの報道はこの説明を見出しにし、CSA は「ゲートウェイのログが資格情報の保管庫になる」という観点でノートを出しています。
10月23日の確定版は、この点を改めました。「初報では、トークンは社内の LiteLLM のログから取られたと疑っていた。リクエストのログを見ると、最初のトークンは別のサービスから来ていた」。つまり、今回の侵入の経路は、Claude Code の応答がログに残ったことではなく、失効されなかったマスターキーから始まっています。
整理すると、次のようになります。
- 侵入の経路(確定版):公開リポジトリに漏れたマスターキー → Agent Platform の API → オーナーの gh トークン → CI の秘密 → 保守者のトークン
- Claude Code のふるまい(初報の LiteLLM の説明):特定の状況で応答本文にトークンが入ることがある、という観察。確定版はこれを侵入の経路としては挙げておらず、観察そのものを撤回するとも書いていない。どんな条件で起きるのかは公開されていない
- LiteLLM の再発防止策(10月30日):Claude Code を原因としては挙げていない。「エンジニアに Claude Code のようなツールを使うなとは言わない」としたうえで、開発者の端末にあるものは、そこで動くエージェントがすべて読めると考える、だから日常の作業に使うアカウントの権限を絞る、という方針を示した(第 11 節)
- Anthropic の見解:10月31日時点で公式の発表・コメントは見当たらない
このため本記事では、Claude Code の件を「この事件の原因」としては扱いません。ただ、コーディングエージェントの通信を本文ごと残すゲートウェイは、そこに映り込んだ秘密を抱えるという指摘は、事件の原因とは別に成り立つ設計上の論点です。第 10 節で扱います。
🌐 5. 社会的影響 ── 関所が汚染されると何が起きるか
1 か所に集めた鍵が、まとめて狙われる
AI ゲートウェイは、組織の LLM 利用の関所です。多くのアプリと開発者の通信がそこを通り、上流の鍵がそこに集まります。管理の面ではこれが正解で、鍵を各アプリにばらまくより、1 か所で守るほうが安全です。ただし、その 1 か所が汚染されたときの被害は、集めた分だけ大きくなります。
今回の収集プログラムは、まさにそこを狙っていました。プロキシのデータベースに接続できる環境では、上流の API キーを収める表を直接読みに行く作りでした(Wiz・CSA)。普通の情報窃取マルウェアがブラウザやクラウドの鍵を狙うのに加えて、ゲートウェイが預かる鍵の束を狙う。AI の基盤を狙った攻撃として作られていたことが分かります。
被害はゲートウェイの外にも広がる
起動フックで動くので、影響はゲートウェイのサーバーに限りません。Microsoft は対象として、開発者の PC、CI/CD のビルド用マシン、テスト環境、コンテナを挙げています。
| 入っていた場所 | 起きうること | 社会への広がり |
|---|---|---|
| AI ゲートウェイのサーバー | 上流の鍵・DB・クラウド権限の流出 | 組織の LLM 利用全体の不正利用 |
| CI/CD のビルド用マシン | リポジトリや配布用の鍵の流出 | 次のサプライチェーン攻撃の足場 |
| 開発者の PC | ブラウザのセッション・SSH 鍵の流出 | 社内システムへの侵入口 |
| 依存として入った AI ツール | 利用者の知らない場所での実行 | 影響範囲の把握そのものが難しくなる |
CI のマシンから盗まれた鍵が次の配布物の改ざんに使われれば、被害は連鎖します。今回の LiteLLM 自身が、まさに「CI の秘密を盗まれて配布物を作られた」側でした。
盗まれた鍵は、数時間で使われた
Wiz は、窃取から約 4 時間半後の 16時20分〜17時01分(UTC)に、攻撃者が CI のマシンや Kubernetes のノードから盗んだ AWS の権限を試していたのを観測しています。権限の確認(sts:GetCallerIdentity)のあと、Amazon Bedrock で使えるモデルの一覧を取得していました。Wiz はこれを LLMjacking(盗んだクラウドの権限で、他人の課金で生成 AI を使う、または転売する手口)と整合すると見ています。一部の環境では IAM のユーザーやロールの列挙もありました。
AI の基盤から盗んだ鍵で、AI の計算資源を盗む。CSA はこれを「AI の基盤が、盗みの出どころであり、標的でもある」と表現しています。
同じプロジェクトで今年 2 回目
LiteLLM は 2026年3月24日にも、1.82.7 と 1.82.8 が約 40 分間 PyPI で配られる事件に遭っています。このときは CI のセキュリティ検査に使っていた Trivy が先に侵害され、そこから公開の資格情報が盗まれた、と LiteLLM は説明しました。Help Net Security によると、Hudson Rock はこの 3月の事件で盗まれた 153GB のデータを分析し、2,488 の企業ドメインに結びつけています。
10月の事件との関係について、Socket は「暗号化の鍵、送り出しの方法、裏口の作りがすべて違い、2 つを結びつける証拠はない」とし、Datadog も記事の公開時点で関連は確認されていないとしています。LiteLLM 自身も 10月30日の再発防止策で、3月は「CI の中で動いた依存ツールが鍵を盗んだ」、10月は「組織オーナーのトークンを握られた」と、入り口がまったく違う攻撃だったと整理しています(第 11 節)。同一の攻撃者とは言えません。ただ、広く使われ、高価な鍵を預かる AI の基盤は、繰り返し狙われるということは言えます。3月の教訓で固めたリリースの流れが、別の場所に残っていた古い鍵から崩されたのが今回です。
⚠️ 6. 対応しないとどうなるか
「盗まれた前提」で考える理由
LiteLLM は、1.107.0 が外へ通信できるホストに一度でも入ったなら、送信は成功したと見なせとしています。送信が成功したときに書かれる目印のファイルはありますが、目印がないことは安全の証明になりません。コンテナの再起動や一時ファイルの掃除で消えるからです。
放置した場合に起きうることを、一次の観測と照らして並べます。
- 盗まれた鍵がそのまま使われ続ける:AWS の権限は窃取から 4 時間半で試されていた。上流の LLM の鍵なら、他人の課金で大量に使われる。請求が届くまで気づかないこともある
- 裏口が残る:Linux と macOS では、
sitecustomize.pyが 1 時間ごとに指示を取りに行く。調査の時点では指示は空だったが、攻撃者が中身を書き換えれば、新しい版を配らなくても別のコードを動かせる仕組みだった(Microsoft は「再び武装できる」と表現) - 次の侵入の足場になる:CI のマシンや開発者の PC から取られた GitHub やパッケージ配布の鍵は、自分たちのソフトの配布物を汚す道具になる。LiteLLM の件そのものが、その実例だった
- 鍵を変えても、セッションが生きている:Microsoft は、パスワードや鍵を変えても、発行済みのトークンやアプリのセッションがすぐに無効になるとは限らないとして、セッションの失効まで行うよう求めている
「漏れた鍵は失効させる」の重み
今回の起点そのものが、放置の帰結を示しています。5月27日に漏れたマスターキーは、コミットの履歴を上書きしただけで、失効されませんでした。それが 4 か月半後の 10月10日に使われ、10月21日の汚染版につながりました。LiteLLM 自身が確定版で「漏れた可能性のある鍵をローテーションしないことのリスクを、強く示す事件になった」と書いています。
公開リポジトリに一度でも載った鍵は、履歴を消しても、すでに誰かが複製しているかもしれません。消すのではなく、無効にする。これが今回の一番の教訓です。
🔄 7. なぜ作り直しとローテーションが必要か ── 戻すだけでは足りない理由
版を戻しても、2 つのものが残る
脆弱性の修正なら「新しい版に更新すれば穴が閉じる」で済みます。今回は違います。1.107.0 は穴のある版ではなく、悪いコードそのものでした。版を 1.106.2 に戻しても、次の 2 つが残ります。
- 環境に残ったファイルとプロセス:3 つのファイルは
litellmの外にある。pipで版を戻すと、そのpipの起動でまた動く。Linux と macOS では、裏で動き続けるプロセスが残っていることがある - すでに盗まれた鍵:送り出された鍵は、こちらの環境をどれだけきれいにしても、攻撃者の手元にある。無効にしないかぎり使える
だから対応は、環境を作り直すことと、その環境から届いた鍵をすべて失効させて新しくすることの 2 本立てになります。
作り直しとローテーションで何が変わるか
- 環境を安全な版(1.106.2 など)でゼロから作り直せば、起動フックと裏で動くプロセスはなくなる。以後、Python を起動しても悪いコードは動かない
- 鍵を失効させれば、攻撃者の手元の鍵はただの文字列になる。上流の LLM の不正利用、クラウドへの侵入、GitHub への書き込みの経路が閉じる
- Docker のイメージをタグではなくダイジェスト(中身のハッシュ)で指定し直せば、タグが付け替えられても同じ中身を取り続けられる
- 鍵がすでに使われた後の被害:不正な課金、作られた IAM ユーザーや鍵、書き換えられた設定は、ログで探して個別に戻す必要がある。LiteLLM は CloudTrail で、導入した時刻の前後のロールの
GetCallerIdentityと、自社の外からの利用を探すよう勧めている - 鍵の棚卸しの漏れ:そのホストから「届いた」鍵が対象。そのプロセスの環境変数だけでなく、同じホストのほかのプロセスの環境変数、マウントされた秘密、ブラウザのセッションまで含む
- ログに残った秘密:1.107.0 を入れていなくても、ゲートウェイが応答本文を残す設定なら、ログに映り込んだトークンは別の経路で漏れうる(第 10 節)
🏢 8. 二層の対応 ── 個人開発者と組織
1.107.0 を入れた環境があった場合の対応を、個人と組織に分けて並べます。
| 項目 | 個人開発者 | 組織(AI 基盤・情シス) |
|---|---|---|
| 対象の洗い出し | 自分の PC・venv・Docker を確認 | 全端末・CI・ミラー・イメージ・ロックファイル |
| 封じ込め | その環境で Python を起動しない | ホストの隔離・外向き通信の遮断・自動再起動の停止 |
| 作り直し | venv とイメージを 1.106.2 などで再作成 | 検証済みの成果物から再構築・ダイジェスト固定 |
| 鍵の入れ替え | LLM の鍵・GitHub・クラウド・SSH・ブラウザ | 上流の鍵・マスター/仮想キー・DB・IAM・CI の秘密 |
| 被害の確認 | 各社の請求と利用履歴を見る | CloudTrail 等で鍵の外部利用と IAM の変更を追う |
| 報告と共有 | 依存先の作者に知らせる | 委託先・顧客への連絡・必要なら当局へ |
個人の層:手元の鍵を守る
個人開発者にとって大事なのは、鍵の入れ替えを、安全な別の端末から行うことです。汚染された PC のブラウザでパスワードを変えれば、新しいパスワードもまた盗まれかねません。入れ替える順番は、被害が大きく、すぐ使われるものからです。LLM の API キー(課金に直結)、GitHub のトークンとセッション(gh auth logout のうえで GitHub の設定画面から失効)、クラウドの認証情報、SSH 鍵、ブラウザに保存したパスワードの順が目安になります。
組織の層:関所を「最重要の基盤」として扱う
組織にとっての論点は、AI ゲートウェイをどの重さで扱うかです。CSA は、ゲートウェイが仲介するものの価値から、最も重要な基盤(tier zero)として扱うべきだとしています。段階的な展開、来歴の確認、実行時の ID の分離、外向き通信の許可リスト。最後の 1 つがあれば、10月13日に登録されたばかりの送り先への通信は止まっていた可能性が高い、と CSA は書いています。
委託先や SaaS が LiteLLM を使っているかどうかも確認の対象です。自社で入れていなくても、自社の LLM の鍵を預けた先のゲートウェイが汚染されていれば、鍵は漏れています。
🔍 9. 自分の環境の確かめ方(短く)
LiteLLM の説明による対象の条件は次のとおりです。
- 10月21日 11時39分〜13時23分(UTC)に、版を固定せずに
pip install litellmした、またはlitellm==1.107.0を入れた - 10月21日 11時46分〜14時20分(UTC)に、Docker のイメージ
v1.107.0・latest・main-latest・main-stableを使った(GHCR は 13時51分まで)
時間帯の外に入れた 1.106.2 以前の版は対象外です。2026年10月31日時点の PyPI の最新の安定版は 1.106.6(10月28日公開)で、次の系列の候補版 1.108.0rc1(10月29日)も出ています。1.107.0 は「取り下げ(yank)」ではなく PyPI から削除されていて、版の一覧にもありません。GitHub の Advisory Database も、悪性コードの項目 GHSA-92x9-889m-jgmw(3月の 1.82.7・1.82.8 と同じ項目)の対象に 1.107.0 を加えています。
Docker のイメージを署名で確かめている場合は、もう 1 点あります。LiteLLM は、イメージの署名に使う cosign の秘密鍵も漏れた可能性があるとして、10月23日に鍵を入れ替えました。新しい鍵で署名した最初のリリースは 10月24日の v1.103.8・v1.104.6・v1.105.4・v1.106.3 です。汚染された 1.107.0 のイメージにも、古い鍵による正しい署名が付いています。古い鍵の署名を信じてよいのは 10月21日より前に公開されたイメージだけで、署名が通ることは安全の証明になりません。新しい公開鍵の指紋と確かめ方は、LiteLLM の初報の「Image signing key rotation」(10月30日に追記)にあります。
確かめるときは、汚染が疑われる環境の中で python や pip を打たないのが原則です。代わりに、ファイルを直接探します。
# venv や site-packages を、シェルの検索で探す(Python は起動しない)
find / -name "litellm-1.107.0.dist-info" -o -name "cook.pth" 2>/dev/null
見つかれば対象です。見つからなくても、それで安全とは言い切れない、と LiteLLM は注意しています。CI の実行ログに litellm-1.107.0 の文字列がないか、requirements.txt やロックファイルに版の固定がなかったかもあわせて見ます。見つかったあとの手順(ファイルの削除、プロセスの停止、作り直し、鍵の入れ替え)は、LiteLLM の初報の「What to do if you are affected」と Microsoft の記事の「Mitigation and protection guidance」に沿って進めてください。
🧱 10. ログ設計とトークン設計で防げる
今回の事件は、新しい技術の未知の穴ではなく、鍵とログの扱い方の積み重ねで起きています。裏を返せば、設計で防げる部分が大きい事件です。
短命・最小権限"] --> X["攻撃の連鎖を
途中で断つ"] L["ログを絞る
本文は残さない"] --> X V["配布物を確かめる
来歴とダイジェスト"] --> X E["外向き通信を絞る
許可リスト"] --> X
鍵を絞る
- 漏れた鍵は、消すのではなく失効させる:今回の起点。公開リポジトリへのコミットに気づいたら、履歴の書き換えより先に失効
- エージェントには、本人の鍵をそのまま渡さない:GitHub CLI のトークンは本人の権限をまるごと持つ。エージェントやツールには、対象のリポジトリと操作に絞った fine-grained のトークンや、短命のトークンを使う。組織オーナーの資格情報を、エージェントが動く端末に置かない(CSA)
ghのトークンに寿命を付ける:GitHub は事件と同じ 10月21日(UTC 16時43分。この告知は LiteLLM の件には触れていない)、GitHub CLI v2.103.0 以降で期限付き・自動更新の OAuth トークンを公開プレビューにした。gh auth login --expiringで使え、漏れたアクセストークンは「無期限ではなく数時間で使えなくなる」。将来は新規ログインの既定にする予定という。トークンを一度取り出して別のツールに保存する使い方は期限切れで壊れるので、gh auth tokenで毎回取り直す- 一時的に広げた権限には期限を付ける:今回は事件の 2 日前に承認の条件を緩めていた。オーナーのトークンがあれば結局外せたので、これが決定打だったとは言えないが、期限と見直しのない権限の拡大は穴になる
ログを絞る
- 応答本文をログに残さないのを既定にする:LiteLLM は既定で本文を残さない。
store_prompts_in_spend_logsを有効にするのは、期間と目的を決めた例外にする。コールバックで外部の監視ツールに送る経路にはturn_off_message_loggingがある - 残すなら、保存の前に秘密を検出して伏せる:GitHub のトークンは
gho_やghp_などの接頭辞で見分けられるように作られている。保存とコールバックの前に検出と伏せ字の段を入れる - ログを秘密の保管庫と同じ重さで守る:ログは鍵の保管庫より広い範囲の人が読め、長く保存され、外部のツールに複製されやすい(CSA)。管理画面をインターネットに出さない
配布物を確かめる
- 版とハッシュで固定する:
pip install litellmのように版を固定しない導入や、latestのような動くタグの追従は、汚染の時間帯にそのまま当たる。ロックファイルにハッシュを書き、コンテナはダイジェストで指定する。GitHub Actions の lockfile の記事で書いた「タグは動く、SHA は動かない」と同じ考え方 - 新しい版はすぐ本番に入れない:今回の汚染版の公開期間は約 2 時間。新しい版を数日寝かせてから社内のミラーに入れる運用なら、取り込む前に騒ぎを知ることができた
- 来歴を見る:ビルドの来歴には偽のリポジトリが記録されていた。来歴を検証する仕組みがあれば、ハイフン 1 つ違いのビルド元は異常として浮かぶ
🛠️ 11. LiteLLM の再発防止策 ── 10月30日の公表
LiteLLM は 10月23日の確定版で「何を学び、何を変えるかは来週に」と書いていました。その答えが、10月30日にセキュリティ責任者・CEO・CTO の連名で出た「What we are changing after October 21」です。
3月の対策は、なぜ効かなかったか
公表の中心にあるのは、外から見ると同じ「公式の経路から悪い版が出た」事件が、入り口のまったく違う 2 つの攻撃だったという整理です。
| 2026年3月 | 2026年10月 | |
|---|---|---|
| 入り口 | CI の中で動いた依存ツール(Trivy)の侵害 | 社内の実験的なサービスの、漏れた管理用 API キー |
| 攻撃者が握ったもの | CI の環境変数にあった配布用の固定の鍵 | 組織オーナーの GitHub トークンと、そこから盗んだ追加のトークン |
| リリースの流れ | 使われず、盗んだ鍵で直接公開 | 正規の流れのまま、偽のソースをビルド・署名・公開 |
| 配布物の見た目 | 署名なし・流れの外で公開 | 正しい署名と、正しい Trusted Publishing の来歴つき |
3月のあと、LiteLLM はリリースの流れを作り直していました。段ごとの分離、検証と公開のリポジトリの分割、Trusted Publishing、cosign による署名、上書きできないタグ、GitHub Actions の固定、プルリクエストごとの検査。これらは「設計どおりに動き、被害を大きく減らした(既存のタグは上書きできなかった)」としつつ、組織オーナーには、どんなパイプラインの対策も効かない。オーナーがパイプラインの持ち主だからだと書いています。
署名と来歴が証明するのは「その配布物が自分たちのパイプラインから出た」ことまでです。1.107.0 は実際にパイプラインから出ていました。第 3 節で書いた Trusted Publishing の限界を、当事者が同じ言葉で認めた形です。
何を変えるか
対策は、事件の要因に沿って 3 つに分かれています。
- ID と権限:日常の作業に使うアカウントは組織オーナーにしない。オーナーの作業は専用のアカウントで行い、そのアカウントでは OAuth アプリの許可も API も
ghも使わない。オーナーのアカウントでトークンを使った操作があれば警告を出す。エージェントの利用は止めず、「開発者の端末にあるものは、そこで動くエージェントがすべて読める」前提で、一般のアカウントにはオーナーや管理者の権限を持たせない。社内の実験的なサービスは、ID を確かめるプロキシの後ろに置き、インターネットに出さない - 資格情報:すべてのリポジトリで secret scanning と push protection を有効にする。秘密の検出は自動でチケットを起こし、失効を確かめるまでチケットを閉じない。自動化は人のトークンではなく、GitHub App か、範囲を絞った期限付きのトークンで動かす。リポジトリの秘密は、保護されたブランチのワークフローしか読めない環境へ移す(オーナー以外のトークンが盗まれる場面に備える対策で、今回のリリース自体は止められなかったとしている)
- 検知と対応:GitHub の監査ログを Splunk に流して警告を出す(完了)。GitHub の外で動く検証役が、公開されたすべての wheel・sdist・イメージを取得して
BerriAI/litellmのタグと中身を比べ、違えば人に知らせ、自動で取り下げる
新しい版が公開"] --> B["GitHub の外の検証役が
配布物を取得"] B --> C["BerriAI/litellm の
同じタグと中身を比較"] C -->|一致| D["そのまま"] C -->|不一致| E["人に警告し
自動で取り下げ"]
事件と直接は関係しない強化として、依存とビルド用イメージを Chainguard の供給元から取る(3月型の攻撃への備え)、HackerOne による脆弱性の受付、Trail of Bits によるコードの堅牢化、重大な脆弱性の修正を先に配る非公開レジストリ(10月27日に発表。「リリースの安全の境界ではない」と明記)も挙げています。
期日つきの 25 項目
公表には 25 項目の約束が、状態と期日つきで並んでいます。LiteLLM は「完了したら表をその場で更新し、守れなかったときもそう書く」としています。10月30日時点の内訳は次のとおりです。
| 期日 | 項目数 | 主な中身 |
|---|---|---|
| 完了 | 3 | 承認は事務所の特定の端末に紐づいた専用アカウントだけ・専用のオーナーアカウント・監査ログの Splunk 連携 |
| 2026年11月15日 | 5 | オーナーのトークン利用の警告・一般ユーザーを管理者にしない方針・HackerOne・非公開レジストリ |
| 2026年11月30日 | 8 | 全リポジトリの secret scanning・失効のチケット化・社内サービスのプロキシ化・攻撃者の操作への警告 |
| 2026年12月31日 | 7 | サードパーティの OAuth アプリの制限・回避者なしのルールセット・公開後の検証役と自動取り下げ |
| 2027年1月31日 | 2 | 人のトークンを使う自動化の作り直し・秘密を保護ブランチ限定の環境へ |
完了済みの 1 項目めは、第 3 節で触れた、事件の 2 日前に一時的に緩めていた承認の条件にあたります。緩める前と同じ「事務所の端末に紐づいた専用アカウントだけ」の形です。公開後の検証役は、第 10 節で書いた「来歴を見る」を、配布する側が自分で常に回す仕組みといえます。
🔧 技術者の所感
この欄は筆者の意見です。まず事実から。このサイトの運用では、AI のコーディングエージェントと GitHub CLI を使っています。LiteLLM は使っておらず、1.107.0 の影響は受けていません。ただ、エージェントが gh のログインを使ってリポジトリを操作するという構図そのものは、このサイトの作業環境と同じです。ゲートウェイを使っていなくても、エージェントが動く端末に、自分と同じ権限の鍵がある。今回の事件で一番身につまされたのはそこでした。
ここからも筆者の意見です。今回の侵入の起点は、AI でもゼロデイでもなく、「漏れた鍵を失効させなかった」という、昔からある 1 つの抜けでした。組み込みの世界でいえば、量産前に消すはずだったデバッグ用の鍵が、出荷後のファームに残っていたようなものです。消したつもりの履歴より、無効にしたかどうか。チェックリストに 1 行足せば防げる種類の話なので、かえって自分の手元を見直すきっかけになりました。
一方で、前向きに受け止めた点もあります。公開から 30 分足らずで第三者が issue を立てて解析を共有し、Wiz、Microsoft、Socket、Datadog、CSA がそれぞれ数日のうちに一次の分析を出し、LiteLLM は 2 日後に初報の誤りを自分で認めて確定版を出しました。誤りを消さずに注記を付けて残したのも、検証する側にはありがたいやり方です。10月30日の再発防止策も、「3月の対策はなぜ効かなかったか」から書き起こし、25 項目に期日を付けて、守れなかったらそう書くと約束しています。読む側が後から答え合わせできる形で出したことを評価したいです。Python も 3.15 で .pth の実行行を非推奨にしました。見つける側、直す側、言語そのものが、それぞれ前に進んでいます。
最後に、初報の「Claude Code が応答にトークンを埋め込む」という説明について。確定版では侵入の経路ではなくなりましたが、エージェントの通信を本文ごと残せば、そこに映った秘密も残る、という指摘は筆者にとっても有益でした。ログは「便利だから全部残す」から「何を残さないかを決める」へ。AI の基盤を設計する側の常識が、ひとつ更新された事件だと思います。
✅ まとめ
- 何が起きたか:2026年10月21日、AI ゲートウェイ LiteLLM の公式版 1.107.0 が、PyPI で約 1 時間 43 分、Docker で約 2 時間 33 分、情報窃取コード入りで配られた。Wiz の集計で約 49,000 ダウンロード
- なぜ重いか:Python の起動フックで動くので、import しなくても、pip を打つだけでも動く。ゲートウェイが預かる上流の鍵の束まで狙う作りで、盗まれた AWS の権限は 4 時間半で試された
- 起点は何か:LiteLLM の確定版によると、5月に公開リポジトリへ漏れて失効されなかったマスターキー。Claude Code の応答がログに残ったという初報の説明は、確定版で侵入の経路から外れた。Anthropic の公式コメントは 10月31日時点で見当たらない
- LiteLLM は何を変えるか:10月30日に再発防止策を公表。日常のアカウントを組織オーナーにしない、オーナーのアカウントからはトークンも
ghも使わない、漏れた鍵は失効を確かめるまでチケットを閉じない、公開後の配布物をタグと突き合わせる検証役を GitHub の外に置く。25 項目に期日を付け、完了したら表を更新するとしている - 何をすればよいか:1.107.0 を入れた環境は、作り直しと、届いた鍵のすべての入れ替え。入れていない人も、版とダイジェストの固定、ログの本文を残さない設定、エージェントに渡すトークンの絞り込みで、次の事件への備えになる
よくある質問(FAQ)
Q. LiteLLM を使っていますが、1.106.2 以前の版です。何かする必要はありますか?
A. 1.107.0 を入れていなければ、今回の汚染版の影響はありません。LiteLLM は 1.107.0 より前の版はすべて安全としています。ただし、版を固定せずに pip install litellm を自動で回している環境は、10月21日の時間帯に 1.107.0 を取っていないか、CI のログで確かめてください。
Q. GitHub にある v1.107.0 のソースからビルドした場合はどうですか?
A. LiteLLM によると、公式の v1.107.0 のタグには悪いファイルは入っていません。汚染された配布物は、偽のリポジトリ Berri-AI/litellm のコミットから作られていました。PyPI の wheel と、該当時間帯の公式 Docker イメージが対象です。
Q. 1.107.0 を入れてしまいました。pip uninstall litellm すれば大丈夫ですか?
A. いいえ。pip 自体が Python なので、起動した時点で悪いコードがもう一度動きます。また、3 つのファイルは litellm のディレクトリの外にあるので、アンインストールでは残ります。環境を作り直し、その環境から届いた鍵を安全な別の端末からすべて入れ替えてください。
Q. Claude Code を使っていると、トークンが漏れるのですか?
A. LiteLLM は 10月21日の初報で「特定の状況で Claude Code が応答本文に GitHub CLI のトークンを埋め込むことを確認した」と説明しましたが、どんな条件かは公開していません。10月23日の確定版では、今回の侵入は別のサービスに漏れたマスターキーから始まったとしています。10月30日の再発防止策でも Claude Code を原因とはしておらず、「開発者の端末にあるものはエージェントが読める前提で、アカウントの権限を絞る」という方針です。Anthropic の公式コメントは 10月31日時点で見当たりません。どのエージェントでも、通信の本文をログに残すゲートウェイを経由する場合は、ログに秘密が映り込む前提で、本文を残さない設定にしておくのが安全です。
Q. Docker で latest を使っていました。対象ですか?
A. 10月21日 11時46分〜14時20分(UTC。日本時間 20時46分〜23時20分)に latest・main-latest・main-stable・v1.107.0 を pull して起動した環境は対象です(GHCR は 13時51分まで)。それ以外の時間に取ったものは、安全なイメージに付け替え済みです。今後はタグではなくダイジェストで指定するのがおすすめです。
Q. 3月の LiteLLM の事件と同じ攻撃者ですか?
A. 分かっていません。Socket は、暗号化の鍵や送り出しの方法、裏口の作りがすべて違い、結びつける証拠はないとしています。Datadog も関連は確認されていないとしています。共通しているのは、広く使われる AI の基盤のリリースの経路が狙われたことです。
Q. LiteLLM は、同じことが起きないように何を変えるのですか?
A. 10月30日に再発防止策を公表しています。日常の作業に使うアカウントを組織オーナーにしないこと、オーナーのアカウントからトークンや gh を使わないこと、漏れた鍵は失効を確かめるまで対応を閉じないこと、公開した配布物を GitHub の外でタグと突き合わせ、違えば自動で取り下げることなどです。25 項目に 2027年1月末までの期日が付いていて、3 項目は 10月30日時点で完了しています。
Q. 自分は LiteLLM を直接入れていません。関係ありますか?
A. 依存の依存として入っていることがあります。エージェントのフレームワークや MCP サーバー、評価ツールなどを入れた環境で、site-packages に litellm-1.107.0.dist-info がないか、シェルの検索で確かめてください。
関連記事
- GitHub Actions に lockfile|actions.lock でタグすり替えを防ぎ依存を SHA 固定 — 「タグは動く、SHA は動かない」。CI の依存を固定する考え方
- 日本企業はどこから破られたのか|2025〜2026年の侵入口とAI時代の守り方 — 委託先経由の被害と、AI エージェントをめぐる攻防の全体像
- PHP に重大な RCE 2件|8.4.27 などへ今夜更新・自分のサーバーの確かめ方 — 同じ 10月21日の出来事。こちらは「更新すれば穴が閉じる」型の対応
参考
- LiteLLM「Contained: Oct 21, 2026 LiteLLM release v1.107.0 Compromised」(初報・10月23日に注記)
- LiteLLM「The attack chain behind the v1.107.0 LiteLLM release」(確定版・10月23日)
- LiteLLM「What we are changing after October 21」(再発防止策・10月30日)
- BerriAI/litellm issue #47826(第一報)
- GitHub Changelog: GitHub CLI: Opt in to expiring, auto-refreshing OAuth tokens
- Microsoft Security Blog: Inside the LiteLLM 1.107.0 supply chain compromise
- Wiz: LiteLLM Compromised, Steals Credentials
- Socket: New Evidence Shows LiteLLM Secret-Stealing Workflows Ran 11 Days Before Supply Chain Attack
- CSA research note: LiteLLM 1.107.0: When Model-Gateway Logs Become the Credential Store(PDF)
- Python ドキュメント: site — Site-specific configuration hook