2026年10月21日、LLMの呼び出しをまとめるOSSのLiteLLMで、配布工程が乗っ取られ、認証情報を盗むコードを含む1.107.0がPyPIとDockerで合わせて約2時間40分配られました。この記事では、汚染された版・タグ・時間帯、Pythonを起動せずに痕跡を探すコマンド、1.106.2への固定と鍵の入れ替えの順序を整理します。あわせて「LiteLLM 脆弱性」で確認しておくべき、CISAの悪用済みカタログに載ったCVE 3件と修正版も一覧にしました。内容は2026年10月23日時点の公開情報にもとづきます。
まとめ:1.107.0を入れた環境は侵害前提、1.106.2固定と鍵の総入れ替え
10月21日20時39分〜22時23分(日本時間)にバージョン指定なしでpip installした環境と、20時46分〜23時20分にDockerのlatest・main-latest・main-stable・v1.107.0のイメージを起動した環境は、鍵が盗まれた前提で扱います。痕跡が見つからなくても安全の証明にはなりません。
対応は、Pythonを起動せずに不正ファイルを消す、常駐プロセスを止める、1.106.2に固定して作り直す、ホストから届いたすべての鍵を入れ替える、の順です。1.107.0に触れていない環境でも、1.83.14より古い版はCISAが悪用を確認したCVEを含むため、同じ機会に1.106.2へ上げましょう。鍵を集める部品の露出と版をまとめて棚卸しするなら、脆弱性診断・セキュリティ診断が使えます。LiteLLM自体の仕組みはLiteLLMとは?複数LLMを1つのAPIで呼ぶProxyの構築手順で扱っています。
10月21日の1.107.0侵害で汚染された版・Dockerタグと公開されていた時間帯
LiteLLM公式のインシデント報告は、配布工程の侵害で、認証情報を盗み遠隔実行の道具を読み込むマルウェアが1.107.0に入ったと説明しています。それ以前の版は安全とされます。
PyPIの7つのwheelとDocker Hub・GHCRの4タグが汚染された時間帯
報告の時刻はUTCで、日本時間では夜にあたります。国内では夜間のCIや自動更新で取り込んだかが分かれ目です。
| 配布先 | 汚染された対象 | 期間(日本時間) |
|---|---|---|
| PyPI | 1.107.0の全7wheel | 20:39〜22:23 |
| Docker Hub | v1.107.0と動くタグ3種 | 20:46〜23:20 |
| GHCR | 同じ4タグ×3イメージ | 20:46〜22:51 |
動くタグ3種はlatest・main-latest・main-stableで、GHCRはlitellm・litellm-database・litellm-non_rootの3イメージが対象です。PyPIの最新版は10月23日時点で1.106.2(侵害の約1時間前に公開)で、1.107.0は消えています。Docker Hubのlatestとmain-stableは、同日17時50分(UTC)にv1.106.2と同じダイジェスト(sha256:7294b90f…)へ付け替えられました。
GitHubのタグは無害、似た名前のBerri-AIから組まれた成果物
GitHubのv1.107.0タグのソースに不正なファイルはありません。攻撃者は正規のBerriAI/litellmではなく、ハイフンを足しただけのBerri-AI/litellmという別リポジトリを読み込むよう配布用のワークフローを書き換え、そこから組んだ成果物に署名して公開しました。
「GitHubのソースを読んで問題が無かった」は判断材料になりません。不正な部分は配布されたwheelとイメージの中だけにあります(GitHub Issue 47826)。
3月の1.82.7・1.82.8との違いと、署名・不変タグを越えられた経路
LiteLLMの侵害は2026年で2度目です。3月24日の事案では1.82.7と1.82.8がPyPIに約40分公開され、CIで使っていたTrivyの侵害が起点とみられました。公式Dockerイメージは依存を固定していたため無事でした。スキャナ自体が入口になった例なので、TrivyのCI設定でも取得元の版を固定します。
3月のあと、LiteLLMはCI/CD v2で、配布用リポジトリの分離、PyPIのTrusted Publishing、Dockerの不変タグ、cosignによる署名を入れていました。今回はその上で破られています。バックポートのため配布権限を2人へ広げていたところへ、開発者3人分のGitHub CLIの認証情報が使われ、組織オーナーの権限でブランチ保護を外されました。
公式は、インターネットに公開していた社内のLiteLLMで見覚えのないアカウントが見つかり、応答本文を記録したログからGitHub CLIのOAuthトークンを拾われたとみています。Claude Codeが応答本文にこのトークンを含める場面も確認したとしていますが、社内環境への侵入経路は「最近修正された脆弱性」と推測するにとどまり、確定していません。
混入したcook.pthとsitecustomize.pyが盗む認証情報と常駐の仕組み
ペイロードの中身は、Upwindの調査チームがIssue 47826に静的解析の結果として載せています。対応の判断に関わる部分だけを抜き出しました。
importしなくても起動のたびに動く.pthとsitecustomizeの仕掛け
1.107.0の各wheelには、site-packagesの直下に置かれるcook.pth(12バイト)・cook.py・sitecustomize.pyの3ファイルが追加されていました。Pythonのsiteモジュールの仕様では、site-packagesにある.pthファイルのうちimportで始まる行は起動時に実行され、sitecustomizeも起動時に自動でimportされます。
LiteLLMをimportしていなくても、Pythonを起動するだけで動くということです。pipもPythonで動くため、汚染された環境で入れ直そうとすると、その瞬間にもう一度実行されます。公式が「pip installから始めるな」と書く理由です。
sitecustomize.pyは常駐プロセスを作り、1時間ごとにGitHub上の指示ファイルを読みます。ドメインが書かれていれば、そこから受け取ったコードを実行する作りです。指示ファイルは10月20日から空で休止中ですが、1回のコミットで再開できます。
Proxyのデータベースに保存した上流のAPIキーまで持ち出す窃取対象
cook.pyは外部の指示を待たず、起動直後に一度だけ集めて送ります。実務で影響の大きい順に並べました。
- 環境変数DATABASE_URLがあれば、LiteLLM ProxyのDBから上流プロバイダーのAPIキーとモデル設定の表を抜き出す
- AWSのインスタンスやECSタスクのロール認証情報(STSのGetCallerIdentityで有効性まで確かめる)、GCPとAzureのメタデータ
- 読み取れるすべてのプロセスの環境変数(/proc/*/environ)とKubernetesのサービスアカウントトークン
- SSH鍵、.env、.npmrc・.pypirc・.git-credentialsなど開発ツールの認証情報、AIツールの設定と鍵
- ブラウザに保存されたパスワードとCookie、TLS・GPGの秘密鍵
集めたデータはAES-256で暗号化され、litellm.dev(10月13日に登録。正規のドメインはlitellm.ai)へ送られ、通信を記録していても復号できません。DBの表まで抜く動きは、各社のAPIキーを1か所に集めるAIゲートウェイ構成を狙ったものです。
影響確認:Pythonを起動せずに版・ファイル・Dockerダイジェストを調べる手順
確認はシェルだけで行います。痕跡が見つかれば侵害は確定しますが、見つからなくても潔白の証明にはなりません。
site-packagesの不正ファイル・常駐の印・ロックファイルを調べるコマンド
Pythonを起動せずに不正ファイルと常駐の印を探します。仮想環境やCIのランナーごとに実行してください。
# 不正ファイルとdist-infoを探す(Pythonは起動しない)
find / -xdev \( -name 'litellm-1.107.0.dist-info' -o -name 'cook.pth' \
-o -name 'cook.py' -o -path '*site-packages/sitecustomize.py' \) 2>/dev/null
# 常駐ローダーのロックと、送信成功時だけ作られる印
ls -la /tmp/remote_code_loader.lock /tmp/.pc_once_72129118c59f5636c0bb 2>/dev/null
# 環境変数PRIVCOLLECT_ACTIVEを持つプロセス
grep -la PRIVCOLLECT_ACTIVE /proc/[0-9]*/environ 2>/dev/null
# ロックファイルに1.107.0が書かれていないか
grep -rn -E 'litellm.{0,12}1\.107\.0' uv.lock poetry.lock requirements*.txt 2>/dev/null
sitecustomize.pyはOSが別の場所に同梱している場合があるため、site-packages内のものだけを拾います。.pc_onceで始まる印は送信成功時だけ書かれるので、見つかれば流出は確定です。
コンテナのイメージダイジェストを汚染値sha256:1bbcb144と照合する手順
Dockerはタグ名でなくダイジェストで判定します。汚染されたイメージインデックスは、litellmがsha256:1bbcb1443bc9…、litellm-databaseがc00f9d92c427…、litellm-non_rootが7b00e91cd2fe…で始まります。
# ホストに残っているLiteLLMイメージのダイジェスト
docker image ls --digests | grep -i litellm
# Kubernetesで動いている(動いた)Podのイメージダイジェスト
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{" "}{.status.containerStatuses[*].imageID}{"\n"}{end}' \
| grep -i -E 'litellm.*(1bbcb144|c00f9d92|7b00e91c)'
10月21日の夜にPodが再起動していれば、汚染イメージを取得した可能性があります。イメージを消していても、デプロイ履歴に起動時刻とダイジェストが残っていないかを確かめます。
CIのジョブや推移的な依存で1.107.0が入った経路の洗い出し
エージェント用のフレームワークやMCPサーバーが、依存としてLiteLLMを引き込む構成もあります。見落としやすいのはCIです。該当時間帯に依存を解決し直したジョブはログにlitellm-1.107.0の文字列が残り、ランナーが使い捨てでも、渡したシークレットは窃取の対象だったと考えます。
侵害時の復旧:ファイル削除から1.106.2固定、鍵の入れ替えまでの順序
手順は公式報告とIssue 47826の推奨に沿います。
pip installより先に行うファイル削除と常駐プロセス停止の4工程
- シェルから、影響を受けたすべてのsite-packagesのcook.pth・cook.py・sitecustomize.pyと、__pycache__内のcook*.pyc・sitecustomize*.pycを削除する
- /tmp/remote_code_loader.lockを握っている常駐のpythonプロセスを止める
- litellm==1.106.2に固定して入れ直す。仮想環境やイメージは作り直すほうがよい
- 外へ通信できるホストに1.107.0が入っていたなら、送信は成功したものとして鍵を入れ替える
常駐プロセスは fuser /tmp/remote_code_loader.lock でPIDを出して止めます。固定はハッシュ付きのロックで行うと、同じ版番号で中身だけ差し替えられても気づけます(uvでのPython環境とロックの管理)。Dockerは litellm/litellm:v1.106.2@sha256:7294b90f868c5c38c99b83021c7ba46f9b439e95f8e32964c925c7d2563a03f7 のようにダイジェストまで書きます。
IAMロール・プロバイダーキー・マスターキー・DB接続の入れ替え範囲
対象は「そのホストから届いたすべて」です。Proxyのホストなら少なくとも次の5種類になります。
| 入れ替える対象 | 盗まれる経路 | 入れ替えの要点 |
|---|---|---|
| 上流のAPIキー | DBの表を抜く | 各社で失効し登録し直す |
| マスターキー・仮想キー | 環境変数とDB | 新しい鍵で起動し再発行 |
| DBのパスワード | DATABASE_URL | DB側で変え接続を差し替え |
| IAMロール | メタデータ | セッション失効と権限見直し |
| 他プロセスの秘密 | 全プロセスの環境変数 | 同居サービスの鍵も対象 |
鍵を環境変数に直接書く構成は窃取に最も弱い形です。入れ替えのついでにAWS Secrets Managerのローテーション設定のような仕組みへ移すと、次の事案での作業が減ります。
CloudTrailのGetCallerIdentityで外部からの鍵の使用を確かめる
ペイロードは盗んだAWSの認証情報をSTSのGetCallerIdentityで確かめてから送ります。公式が求めているのは、この呼び出しと、外部からのロール認証情報の利用をCloudTrailで確認することです。lookup-eventsで直近90日の管理イベントを引けます。
# 10月21日11:30〜翌日(UTC)のGetCallerIdentityを一覧(リージョンごとに実行)
aws cloudtrail lookup-events --region ap-northeast-1 \
--lookup-attributes AttributeKey=EventName,AttributeValue=GetCallerIdentity \
--start-time 2026-10-21T11:30:00Z --end-time 2026-10-23T00:00:00Z \
--query 'Events[].[EventTime,Username,CloudTrailEvent]' --output text \
| grep -o -E '"sourceIPAddress":"[^"]+"|"userName":"[^"]+"' | sort | uniq -c
送信元IPが自社のNATなどで説明できなければ、認証情報は外で使われています。STSの記録は呼び出したエンドポイントのリージョンに残るため、us-east-1も含めて実行します。
「LiteLLM 脆弱性」で押さえるCVE:KEV掲載3件と1.83系以降の修正版
1.107.0の件はCVEではなく、悪意ある配布物としてOSVのMAL-2026-2144に記録されています(3月の2版と同じIDに追記)。古い版のまま動くProxyには、本体のCVEのほうが危険です。
CISAが悪用を確認したSQLインジェクション・コマンド実行・認証回避
CISAのKEVカタログ(10月21日版)には、LiteLLMの項目が3件あります。影響版と修正版はGitHub勧告DBの値です。
| CVE | 内容 | CVSS | 影響版 | 修正版 | KEV追加 |
|---|---|---|---|---|---|
| CVE-2026-42208 | APIキー照合のSQLインジェクション(認証不要) | 9.8 | 1.81.16〜1.83.6 | 1.83.7 | 5月8日 |
| CVE-2026-42271 | MCPの接続テストAPIでのコマンド実行 | 8.8 | 1.74.2〜1.83.6 | 1.83.7 | 6月8日 |
| CVE-2026-59822 | MCPのOAuth2転送の代替経路で認証回避 | High | 1.84.0未満 | 1.84.0 | 9月2日 |
CVE-2026-42208は、Authorizationヘッダに細工した値を送るだけで、仮想キーと上流のAPIキーが入ったDBを読めます。公開したProxyが1.83.7未満なら、1.107.0の件と同じ扱いで鍵を入れ替えます。
権限昇格・テンプレート注入など1.83.14未満に残る高深刻度の穴と修正版
KEV外の高深刻度の勧告も、修正版は1.83系に集中しています。仮想キーを社内に配る構成では、利用者が管理者になれる種類が効きます。
- CVE-2026-37004:/prompts/testのテンプレート注入で認証なしにOSコマンド実行(9.8、1.83.7で修正)
- CVE-2026-35029:/config/updateに管理者権限の確認が無く設定変更からRCE(High、1.83.0で修正)
- CVE-2026-47102:/user/updateで自分のロールをproxy_adminへ変更(8.8、1.83.10で修正)
- CVE-2026-47101:権限外のルートに届くAPIキーを発行(8.8、1.83.14で修正)
- CVE-2026-84377:リクエスト本文の検証不足によるSSRFと鍵の持ち出し(6.5、系列ごとに修正。1.96系は1.96.2)
10月23日にOSVで照会したところ、1.106.2に該当する勧告は0件でした。古い系列のバックポート版を追うより、1.106.2へ上げるほうが確認は少なく済みます。
10月27日に公表予定の未公開の脆弱性とOSS版の利用者が備える準備
公式報告によれば、有償版の非公開レジストリでは、10月27日に公表予定の脆弱性を直した版が先行配布されています。OSS版の利用者には、公表日まで内容も修正版も分かりません。外部に公開しているProxyは公表直後に上げる前提で、検証環境と手順を今のうちに用意します。追跡先はGitHubのセキュリティ勧告ページです。
判断:LiteLLMを使い続ける条件と、自前のProxy運用をやめる場面
半年で2度の配布物侵害と、KEV入りのCVE 3件。それでも今回の侵害は、版を固定していた利用者には届いていません。続けるかどうかは製品より自社の運用で決まります。
版とダイジェストの固定・ログ本文の無効化を満たせるなら利用を継続
次の3条件を満たせるなら、使い続けて構いません。1つ目は、PyPIはハッシュ付きのロック、Dockerはダイジェストで固定し、latestのような動くタグを本番で使わないことです。今回、署名とタグの不変化は守りになりませんでした。攻撃者が正規の工程で署名し、動くタグを書き換えたからです。
2つ目は、新しい版を公開から数日寝かせて入れることです。今回のPyPI公開は約1時間40分で、数日待てば取り込まずに済みました。3つ目は、ログに応答本文を残さないことです。公式のログ設定でturn_off_message_loggingをtrueにすると、ログ連携先には利用量などのメタデータだけが送られます。LiteLLM社自身が、ログ経由でトークンを拾われた可能性を挙げています。
社外公開のProxyを少人数で抱える組織が運用を外へ出す判断基準
Proxyを外部に公開していて、勧告を週単位で追う担当者がいないなら、自前運用は過剰な負担です。GitHub勧告DBでは2026年4月から9月まで毎月LiteLLMの勧告が出ており、4月・5月・7月・8月にはHigh以上が含まれます。
この場合は、Proxyを社内ネットワークの内側へ下げる、マネージドなAIゲートウェイへ移す、保守ごと外部へ委託する、のいずれかを選びます。選び方はAIゲートウェイとは?役割と導入判断にまとめました。どれを選んでも、APIキーを集めるホストは本番DBと同じ水準で守る対象です。
LiteLLM 1.107.0侵害と脆弱性対応でよくある質問と回答
今回の事案と、LiteLLMの脆弱性対応で出てきやすい疑問に、10月23日時点の一次情報の範囲で答えます。
1.107.0を入れていなければ対応は不要ですか?
1.107.0の件に限れば不要です。公式は1.107.0より前の版を安全とし、Issue 47826でも1.106.2を含む直近11版のwheelに異常は無いとされました。ただし1.83.14より古い版なら、KEVに載ったSQLインジェクションなど別の穴が残るので、1.106.2への更新は済ませてください。
Dockerイメージを使っていれば3月と同じく安全でしたか?
今回は違います。3月はPyPIだけが汚染され、公式Dockerイメージは無事でした。10月はDocker HubとGHCRのv1.107.0と動くタグ3種が汚染イメージを指していました。日本時間の10月21日20時46分〜23時20分にこれらのタグで起動したコンテナは侵害されたものとして扱います。ダイジェストで固定していた環境は影響を受けていません。
Windowsの開発端末に入れた場合も被害はありますか?
あります。Issue 47826の解析では、Windowsでは常駐ローダーの起動に失敗する一方、cook.pyによる窃取はそのまま動く仕組みです。開発端末にはブラウザの保存パスワードやクラウドCLIの認証情報、AIツールの鍵が集まりやすく、サーバーより被害が広がる場合もあります。該当期間に入れたなら端末の鍵もすべて入れ替えます。
最新版は1.107.1などに上がっていますか?
10月23日時点のPyPIの最新版は1.106.2で、それより新しい版はありません。一部の記事にある「1.107.1以上へ更新」は、PyPI上に該当する版が存在しません。公式の推奨も1.106.2かそれ以前の明示的な版への固定です。1.107系の次の版は、公式報告の更新を確かめてから入れてください。
痕跡が見つからなければ鍵の入れ替えは省けますか?
省けません。送信成功の印は/tmpに書かれるため、コンテナの破棄や/tmpの掃除で消えます。公式とIssueがどちらも求めているのは、外部へ通信できるホストに1.107.0が入っていたなら送信は成功したものとして扱うことです。インストール記録かダイジェストで利用が分かった時点で、痕跡の有無にかかわらず入れ替えます。
関連記事
- サプライチェーン攻撃とは?起点別3類型と最新事例・対策の優先順位:配布工程を狙う攻撃の全体像です。
- OSV-Scannerの使い方|インストール・コマンド・GitHub Actions設定とTrivyとの違い:MAL-2026-2144のような記録をロックファイルから照合できます。
- Shai-Hulud(シャイ・フルード)とは?npmサプライチェーン攻撃の全体像と影響確認と対策:開発者の認証情報を連鎖的に奪う同種の攻撃です。
- socket.devとは?npm/PyPIのサプライチェーン攻撃を防ぐ仕組みと料金:不審な配布物を取り込む前に止める手段です。
- SHA Pinningとは?GitHub ActionsをコミットSHAで固定する方法:CIの側で参照先を固定する考え方です。