最近相次いで人気ライブラリがサプライチェーン攻撃の被害を受けている。3月24日には、人気のPythonパッケージ「LiteLLM」も被害を受けた。LiteLLMは、ChatGPTやGemini、Claudeなど人気のAPIを手軽に切り替えて使えるというライブラリだ。少し前に本コラムでも使い方を紹介したばかりだったため驚いた。開発者にとってサプライチェーン攻撃は他人事ではない。そこで、LiteLLMを教訓にして安全対策を考えてみよう。
攻撃を受けたLiteLLMについて
本連載の134回目「いろいろな生成AIの意見が聞けるツールをOpenRouterを使って作ってみよう」では、OpenRouterのAPIを呼び出すのに、今回被害を受けたパッケージ「LiteLLM」を使う方法を紹介していた。LiteLLMは、本稿執筆時点でGitHubのスターが4.3万、月間ダウンロード数が9500万回を超える人気のPythonパッケージだ。
そんなLiteLLMが、3月24日にサプライチェーン攻撃に遭った。開発者のAPIキーなどの情報を盗み出すためのマルウェアが仕込まれたのだ。影響は、v1.82.7とv1.82.8で異なる。v1.82.7ではLiteLLMの特定モジュールを読み込んだ際にマルウェアが実行され、v1.82.8は.pthファイルによりPython起動時に自動実行される。それによって、SSHキーやAPIキー、環境変数などを盗み出すマルウェアが実行されてしまう。幸いにも問題がすぐに検知されたので、被害は限定的だったようだが、開発者にとって他人事ではない。
具体的には、こちらで問題の詳細が報告されている。3月23日に開発チームがGitHubで公開しているのはv1.82.6.dev1だったのに、Pythonパッケージの公開を行っているPyPIには、v1.82.7と1.82.8が公開されてしまったのだ。つまり、攻撃者が勝手に、マルウェアを含むLiteLLMの新バージョンをPyPIにリリースしてしまったのだ。現在は、PyPIからも該当バージョンが削除されている。なお、この問題のあるバージョンがPyPIに公開されていたのは、40分間から46分間だったとのことで被害は最小限に抑えられたようだ。
なお、問題のバージョンは、v1.82.7とv1.82.8だ。もし、これらのバージョンをインストールしてしまった場合は、すぐにアンインストールしよう。該当バージョンをインストールしていた場合には、APIキーやSSHキーが悪用される恐れがあるので、APIキーを再発行することや、SSHキーを更新することが必要だ。問題のバージョンがインストールされているかは、「pip show litellm」を実行することでバージョンを確認したり、Pythonパッケージの保存ディレクトリに「litellm_init.pth」というファイルがあるかどうかを調べたりすることで判定できる。
Pythonだけではないパッケージシステム全体の問題 - 人気ライブラリが続々と狙われた
なお、今回のLiteLLMの事件は、ソフトウェア産業全体の信頼を揺るがすものだ。なぜなら、今回問題にしているLiteLLMだけではなく、こうした手軽に使えるパッケージシステム自体に問題がある可能性が指摘されているからだ。もはや、公開されているパッケージを無条件に信頼することはできない時代となった。
そもそも、「サプライチェーン攻撃(Supply Chain Attack)」とは、ソフトウェアを開発する際に利用するオープンソースソフトウェア(OSS)やライブラリにマルウェアを仕込む攻撃のことだ。攻撃者は、OSSやライブラリのメンテナーになりすまし、マルウェアを仕込む。そして、そのOSSやライブラリを利用する開発者のPCにマルウェアを感染させる。結果として、攻撃者は開発者のPCに侵入し、情報を盗み出すことができるというものだ。
というのも、コーディングAIの発達により、誰でも簡単にパッケージを作成できるようになった。悪意を持った攻撃者にとっては、役立つコードを提供し続けて、信頼を得た後に、マルウェアを仕込んだパッケージを公開するという手口が容易にできるようになったのだ。
そして、誰でも自由にパッケージが公開できるというパッケージシステムの問題は、Pythonだけではない。3月31日には、JavaScript(Node.js)のパッケージシステムであるnpmでも、有名なHTTPライブラリの「axios」がソーシャルエンジニアリングに遭って、マルウェアを仕込んだ最新バージョンが公開されてしまった。
数時間後には削除されたものの、axiosは週間ダウンロード数が1億回を超える人気パッケージであり、多くのプロジェクトで利用されている。今回のLiteLLMと同様に、開発者のAPIキーなどの情報を盗み出すためのマルウェアが仕込まれていた。
axios開発者を騙してPCを乗っ取った手口だけでなく、マルウェアがインストール後に自身を自己削除する仕組みを仕込んでいる点など、非常に巧妙な手法が用いられており、筆者自身が同じような攻撃を受けたとしても、すぐに気づけるかどうか自信はない。その攻撃実態がこちらの記事にまとまっている。
わずか1週間の間に、世界中で使われている有名ライブラリが2つも攻撃を受けたことになる。こうした事件を通して見えてくるのは、これまでOSSが技術だけでなく「善意」や「信頼」によって成り立っていたということだ。
開発者が取るべき対策は?
これまで、OSSのライブラリを利用する際に気をつけるべきことは、そのライブラリのメンテナンスが今後行われるのだろうかといった技術面だけを気にしていれば良かった。しかし、今回の事件を考えると、有名だからといって全面的に安心とは言えなくなってきた。どのような対策が考えられるだろうか。
「最新」ではなく「安定」バージョンを利用する
まず、ライブラリを利用する際には、有名なライブラリであっても、最新のバージョンではなく、安定したバージョンを利用することが大切だ。最新のバージョンは、セキュリティ上の問題が含まれている可能性がある。これまでは、最新バージョンであれば安心という意識があったが、今回の事件でその意識は改めなければならない。リリースから数日間は様子を見る、あるいは脆弱性スキャナが検査をパスするのを待つといった対応が必要になるだろう。
実際、今回、axiosとLiteLLMで攻撃を受けたのは、どちらも最新バージョンとその1つ前のバージョンだった。axiosに関しては、脆弱性スキャナが公開から6分後に問題を検出することができたために被害の拡大を防ぐことができた。
そして、ライブラリをインストールする場合には、必ず、安定バージョンを指定してインストールすることを心がけたい。基本的に、pipコマンドでバージョンを指定しないと最新のバージョンがインストールされてしまう。そこで、安定バージョンを調べた上で、次のようにバージョンを指定しよう。
pip install (パッケージ名)==(バージョン番号)
なお、pipコマンドでは、「--uploaded-prior-to」オプションを指定することで、特定の日時以前のバージョンを指定してインストールすることもできる。
pip install --uploaded-prior-to=(日時) (パッケージ名)
バージョン固定を徹底する
さらに、Pythonでライブラリを開発する際には、「requirements.txt」や「pyproject.toml」などに依存パッケージを記述する必要があるが、その際に「パッケージ名 >= バージョン番号」のように特定以上のバージョンを指定するのではなく、必ず具体的なバージョン番号を指定するようにしたい。つまり、信頼できるパッケージの、信頼できるバージョンだけを利用するようにしよう。
ハッシュ値による検証も有効
そして、バージョン固定に加えて、ハッシュ値による検証も有効だ。パッケージをrequirements.txtに記述する際には、ハッシュ値も併記するようにしよう。
(パッケージ名1)==(バージョン) \
--hash=sha256:(ハッシュ値)
(パッケージ名2)==(バージョン) \
--hash=sha256:(ハッシュ値)
(パッケージ名3)==(バージョン) \
--hash=sha256:(ハッシュ値)
このようにハッシュ値を指定することで、ダウンロードしたパッケージが改ざんされていないかを確認できる。実際にインストールする際には、次のように「--require-hashes」オプションを付けてコマンドを実行する。
python -m pip install --require-hashes -r requirements.txt
ちなみに、今はまだ実験(experimental)扱いだが、依存パッケージのバージョンを固定する「pylock.toml」の利用も検討したい。JavaScriptのパッケージ管理ツールであるnpmやyarnには、package-lock.jsonやyarn.lockといったファイルがあり、これらによって依存パッケージのバージョンが固定されている。これと同様の仕組みをPythonでも実現できるのがpylock.tomlだ。既に、人気のPythonパッケージ管理ツールのuvでは、uv.lockというファイルによって依存パッケージのバージョンが固定されている。
依存ライブラリの脆弱性をチェックする
加えて、Pythonパッケージの脆弱性を調べるツール「pip-audit」も活用したい。これは、Python Packaging Authority (PyPA) が関与して開発されているツールだ。次のコマンドを実行することで、現在利用しているパッケージに脆弱性がないかを確認できる。
# pip-auditのインストール
pip install pip-audit==2.10.0
# 現在の環境をスキャンする場合
pip-audit
# requirements.txtを指定してスキャンする場合
pip-audit -r requirements.txt
ただし、このpip-auditで検出できるのは、既知の脆弱性のみであることを忘れないようにしたい。
チーム開発ではプライベートリポジトリを構築する
ある程度の規模の開発チームや組織であれば、チームで利用するパッケージを管理するプライベートリポジトリを導入することも有効だ。チーム用のプライベートリポジトリを運用することで、安全なパッケージのみをチーム内に配布することができる。一度チームで検証して安全なパッケージのみをキャッシュして配布する運用にすることで、今回のような「攻撃者が勝手に公開した最新バージョン」を誤ってエンジニアがインストールしてしまうリスクを物理的に遮断できる。
まとめ
以上、今回は、便利なパッケージシステムに潜むリスクと、その対策について考えてみた。パッケージシステムは、開発を効率化してくれる一方で、リスクもはらんでいる。今回の事件を教訓に、パッケージをインストールする際には、信頼できるパッケージの、検証済みの安定バージョンであることを確認する習慣を付けるようにしよう。
また、今回LiteLLMとaxiosで起きた一連の攻撃は、CI/CD侵害、パッケージシステムにおける認証情報の奪取、PCの乗っ取り、そして不正なパッケージの公開といった複数の攻撃手法が組み合わさった複雑な攻撃だった。こうした問題は、簡単な対策だけでは防ぐことができない。だからこそ、普段からセキュリティ意識を高め、対策ソフトの導入や、フィッシング詐欺に注意するなど、基本的なセキュリティ対策を徹底することが大切と言える。
自由型プログラマー。くじらはんどにて、プログラミングの楽しさを伝える活動をしている。代表作に、日本語プログラミング言語「なでしこ」 、テキスト音楽「サクラ」など。2001年オンラインソフト大賞入賞、2004年度未踏ユース スーパークリエータ認定、2010年 OSS貢献者章受賞。これまで50冊以上の技術書を執筆した。直近では、「大規模言語モデルを使いこなすためのプロンプトエンジニアリングの教科書(マイナビ出版)」「Pythonでつくるデスクトップアプリ(ソシム)」「実践力を身につける Pythonの教科書 第2版」「シゴトがはかどる Python自動処理の教科書(マイナビ出版)」など。

