フォークボムに救われた
LiteLLM 1.82.8に仕込まれたマルウェアには、Pythonの起動時に必ず実行される.pthファイルが含まれていました。SSHキー、クラウドの認証情報、暗号通貨ウォレット、CI/CDのシークレットを収集し、4096ビットのRSA鍵で暗号化したうえで、攻撃者が管理するドメインへアーカイブを送信する——そういう仕組みです。ペイロードの作りは丁寧でした。暗号化にも破綻はありませんでした。持ち出しの手口も鮮やかでした。1 この事例は、自動化されたシステムへの信頼をどう築くかを現実の失敗から考えるエージェントのセキュリティシリーズの一篇です。5
ところがこの.pthファイルは、処理を実行するためにPythonの子プロセスを生成していました。その子プロセスがまた.pthファイルを起動します。そこからさらに子プロセスが生まれ、また起動する。数秒でCPUを100%使い切り、5GB以上のメモリを食い潰す、指数関数的なフォークボムのできあがりです。2
このフォークボムはバグでした。攻撃者としては、マルウェアが目に見える形で表に出ることなど望んでいなかったはずです。正しく実装されていれば、感染したすべてのシステムで、Pythonが呼ばれるたびに静かに動き続けたでしょう。おそらく何週間も。しかし実際には、開発者たちは自分のマシンが停止寸前になっていることに気づき、調査し、認証情報を盗むコードを発見しました。PyPIは公開から46分後、両バージョンを隔離しています。1
46分で46,000件のインストール。検知の仕組みとして働いたのは、マルウェア側の実装ミスでした。
AIエージェントの依存パッケージにフォークボムが含まれていた場合、指数関数的に増えるプロセス生成が数秒でCPUを100%、メモリを数ギガバイト消費し、マシンは使い物にならなくなります。 LiteLLM 1.82.8の一件では、この偶発的なフォークボムだけが、認証情報を盗むペイロードの発覚理由でした。開発者がマシンの異常な重さに気づいて調べたのです。このバグがなければ、マルウェアはSSHキー、クラウドの認証情報、暗号通貨ウォレットを何週間も静かに抜き続け、誰にも気づかれなかったでしょう。
要点
- バグ: LiteLLM 1.82.8の認証情報窃取コードにはフォークボムのバグがあり、感染マシンが停止寸前になりました。バグがなければ、何週間も静かに動き続けたはずです。
- 穴: 静的解析も、挙動の監視も、コードレビューも、すべてこの攻撃を見逃しました。どの検知層も「他の層が捕まえるはず」と前提していたのです。実際にはどこも捕まえませんでした。3
- 曲線: 攻撃側の完成度は反復とともに上がります。
.pthを使う手法はすでに公開・文書化されました。次の攻撃者は、バグなしでこの手法を受け継ぎます。 - 運に頼らない対策: 送信先ドメインの登録日チェック、パッケージインストール時の挙動ベースライン、ファイルシステム上のカナリア、インストール環境の隔離。いずれもペイロードの出来に左右されません。
- 非対称性: 環境を選べるのは守る側です。インストール環境に盗むべき認証情報がなければ、完璧なペイロードでも収穫はゼロになります。
運が良かっただけ
ペイロードからフォークボムを取り除けば、攻撃は静かに成功します。.pthファイルはあらゆるimportより前、アプリケーションのコードより前、Pythonレベルのどんなサンドボックスよりも前に走ります。フックを差し込める場所はありません。ログにも残りません。認証情報の窃取、暗号化、送信が終わっても、Pythonのプロセスは何事もなかったように動き続けます。開発者には何も見えない。CIパイプラインにも何も見えない。セキュリティスキャナにも何も見えない——そもそもそのセキュリティスキャナ自体が攻撃の侵入経路だったのですから。3
LiteLLM 1.82.8で語るべき検知の物語は、「監視が捕まえた」ではありません。「攻撃者がバグを出荷した」です。
サプライチェーンのセキュリティが、この上に成り立っているとしたら心もとない話です。エージェントのサンドボックスは「お願い」でしかないでも書いたとおり、信頼できるコードとできないコードのあいだにあると思い込んでいる境界は、多くのチームが考えているよりはるかに穴だらけなのです。
攻撃側の完成度は上がっていく
ソフトウェアの質は反復とともに上がります。これは守る側だけでなく、攻める側にも当てはまります。TeamPCPのキャンペーンは、1週間で5つのエコシステムを直撃しました。GitHub Actions、Docker Hub、npm、Open VSX、PyPIです。4 しかも各エコシステムの侵害には、その前の侵害で収穫した認証情報が使われています。運用面の練度も高いものでした。ペイロード投入の24時間前に済ませたドメイン登録、可変な参照を狙ったタグの乗っ取り、Aqua Security側の鍵変更が不完全だった点を突いた認証情報ローテーションの回避——どれも周到です。
フォークボムは、そうした手堅い作戦のなかで唯一のミスでした。次のキャンペーンで同じ間違いは起きません。.pthファイルを使う手法はすでに公開され、CrowdStrike、Microsoft、Wiz、Palo Altoによって分析されています。3 次の攻撃者は、バグ抜きでこの手法を受け継ぐわけです。
攻撃側の能力も、防御側と同じ改善曲線をたどります。手法は公開されている。分析も公開されている。次の攻撃者は、TeamPCPが到達した地点から始めます。この曲線が自律的なシステムにとって何を意味するかは、監督なしで実際に壊れるもので掘り下げました。
検知を攻撃者のミスに頼ってはいけない
現在のサプライチェーン検知モデルは3層構造ですが、LiteLLMでは3層とも機能しませんでした。
静的解析は見逃しました。.pthファイルはPythonの正規の機能です。ペイロードは二重にbase64エンコードされ、実行時にデコードされていました。既知の悪性パターンを探すスキャナは、パターンが新しい以上、何も見つけられません。
挙動の監視も見逃しました。認証情報の窃取コードが行った通信は、正規のサービスらしい見た目のドメイン(models.litellm.cloud)へのHTTPS POSTが1回だけ。送信先ドメインを検査する仕組みで捕まえるには、そのドメインが24時間前に登録されたばかりだと知っている必要があります。送信監視でドメインの登録日まで見ている例は、ほとんどありません。
コードレビューも見逃しました。悪性バージョンはPyPIへ直接公開され、GitHubのCI/CDパイプラインは丸ごと迂回されています。レビューすべきプルリクエストは存在せず、差分を確認する機会もありませんでした。攻撃者は盗んだ公開用の認証情報で、ビルド済みパッケージをそのままアップロードしたのです。
どの検知層も、攻撃の連鎖のどこか別の部分で問題が捕まると想定していました。どこも捕まえなかった。捕まえたのはフォークボムです。
静かなマルウェアを実際に検知するもの
攻撃者のミスに頼れないなら、実装の出来に関係なく働く検知手段が必要になります。
送信リクエストのドメイン登録日チェック。 持ち出し先のドメインは、攻撃の24時間前に登録されたものでした。登録から7日未満のドメインへの送信にフラグを立てるファイアウォールのルールがあれば、これは捕まえられます。ルールは単純で、誤検知の量も扱える範囲に収まり、しかも最も一般的な持ち出しパターンを押さえられます。
Pythonプロセスの挙動ベースライン。 pip installが突然、見知らぬドメインへHTTPS POSTを投げ始めるのは異常です。パッケージのインストール中にプロセス単位でネットワーク活動を追う監視なら、ここに反応します。
ファイルシステム上のカナリア。 おとりのパスに偽のSSHキーを置き、別のおとりのパスに偽のAWS認証情報を置きます。そのうえで、これらのファイルを読むプロセスがないかを監視します。標準的なパスを舐めていく窃取コードは、必ずカナリアを読みます。正規のプロセスは読みません。持ち出しが完了する前に、カナリアが警報を鳴らしてくれるわけです。
インストール環境の隔離。 本物の認証情報に一切アクセスできない環境でpip installを実行し、その後で、インストール済みのパッケージを本番環境へコピーします。.pthファイルが発火するのはpip自身のPythonプロセス内、つまり窃取コードはインストール中に走ります。そのインストール環境に盗むべき認証情報がなければ、攻撃の収穫はゼロです。
これらはいずれも、攻撃者がミスを犯すことを前提にしていません。ペイロードの出来に関係なく機能します。完璧な攻撃でも何も持ち出せない環境を設計するというこの構造上の考え方は、デプロイと防御——エージェントの信頼のパラドックスで述べた原則と同じものです。
非対称性
防御側には、構造的に有利な点がひとつあります。環境を選べるのは守る側だ、ということです。攻撃側は、パッケージがインストールされる環境がどうであれ、その中でやりくりするしかありません。そこに認証情報がなく、ネットワークにも出られず、ファイルシステムにカナリアが仕込まれていれば、ペイロードは技術的には成功しても、運用上は失敗に終わります。
LiteLLMへの攻撃が通ったのは、インストール環境が、公開用の認証情報もSSHキーもクラウドのトークンも抱え込んだ環境そのものだったからです。フォークボムはセキュリティ設計とは無関係でした。関係したのは、発覚までの時間だけです。
次はフォークボムなどありません。それでも認証情報は、パッケージマネージャと同じ環境に置かれたままでしょう。問われるのは、次の攻撃者がバグのないペイロードを送り込んでくる前に、その環境を変えられているかどうかです。侵害されたコンポーネントが隔離の境界を越えて権限を広げられないようにエージェントのシステムを組む方法は、Ralphのエージェント設計で分析しています。
FAQ
攻撃者はなぜフォークボムをテストで見つけられなかったのですか
.pthファイルから子プロセスを生成するのは、親をブロックせずにペイロードを走らせる手段として、それ自体は妥当な実装判断です。再帰的に発火してしまうのは、.pthとPythonのsite.py初期化処理との、かなり微妙な相互作用によるものでした。単体テストでは出ず、結合テストで初めて表に出るたぐいのバグです。そしてマルウェアの作者には、現実に近い環境で結合テストを行う機会がそう多くありません。
フォークボムは意図的だった可能性はありますか
考えにくいです。フォークボムはマルウェアを即座に目立たせてしまい、攻撃者の目的とは正反対の結果を招きました。何週間も静かに動き続ける窃取コードのほうが、46分で発覚するものより桁違いに多くの認証情報を集められます。
ドメイン登録日のチェックは、大規模でも現実的ですか
現実的です。ドメインの登録日はWHOISやDNS登録日を返すAPI経由で取得できます。チェックによる遅延は1リクエストあたり数ミリ秒。新しいドメインでも既知のものであれば、たいていの組織はホワイトリストに登録して回せます。
出典
-
FutureSearch(Daniel Hnyk)、“LiteLLM Hack: Were You One of the 47,000?” 2026年3月。 ↩↩
-
isfinne ほか、“LiteLLM Supply Chain Attack,” GitHub Issue #24512、2026年3月。 ↩
-
Blake Crosley、“The Supply Chain Is the Attack Surface,” blakecrosley.com、2026年3月。 ↩↩↩
-
Kaspersky、“Trojanization of Trivy, Checkmarx, and LiteLLM Solutions,” 2026年3月。 ↩
-
Blake Crosley、“When Your Agent Becomes the Researcher,” blakecrosley.com、2026年3月。 ↩