0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LiteLLM公式パッチ後も、fastapi固定でRCEの穴が残っていた

0
Posted at

はじめに

litellm を 1.83.7 に上げたから、報告されている重大 CVE はもう塞がっている」——2026年4月にそう思って安心した人は少なくないはずです。しかし実際には、そこから 約2ヶ月間 別の穴が残っていました。

原因は litellm 自身のバグではなく、依存パッケージの固定バージョンが別の脆弱性を静かに引きずり込んでいた ことでした。今回はその連鎖を、一次情報とバージョン履歴を追いながら整理します(結論だけ知りたい方は「今すぐ確認すべきこと」まで飛んでください)。

TL;DR

  • litellm に重大 CVE が 2 件見つかり、いずれも 2026年4月13日リリースの 1.83.7 で修正済み(SQL インジェクション CVSS 9.3・コマンドインジェクション CVSS 8.7)
  • しかし 1.83.7 の時点でも litellm は fastapi==0.124.4 を固定しており、これが依存する Starlette は 脆弱バージョン 0.50.0 に解決されたままだった
  • Starlette 側の「BadHost」(CVE-2026-48710・Host ヘッダー認証バイパス)と組み合わさると、無認証 RCE の連鎖が成立しうる(Horizon3.ai の分析では組み合わせ CVSS 10.0)
  • この fastapi ピンが実際に外れたのは 2026年6月6日リリースの 1.88.0。つまり CVE 修正から約54日間、pip install --upgrade litellm だけでは Starlette の脆弱バージョンを引きずったままだった
  • 今 1.88.0 未満で運用している環境は同じ状態にある可能性がある。対策は pip show litellm / fastapi / starlette の実バージョン確認から

CVSS9.3の認証前SQLインジェクション(CVE-2026-42208)

litellm Proxy の API キー検証パスに、認証が確定する に実行される SQL クエリが存在し、Bearer トークンの値がパラメータ化されずにそのまま LiteLLM_VerificationToken テーブルへのクエリに連結される問題が報告されました(GHSA-r75f-5x8p-qvmc)。認証前に到達できるため、プロキシのポートに到達できる HTTP クライアントであれば攻撃が成立します。

このクラスの脆弱性は、一般的には次のような「文字列連結でクエリを組み立てる」パターンで発生します(litellm の実装そのものではなく、典型的な脆弱パターンの例示です)。

# 脆弱なパターンの典型例(文字列連結でSQLを組み立てる)
def verify_token(bearer_token: str, db):
    query = f"SELECT * FROM LiteLLM_VerificationToken WHERE token = '{bearer_token}'"
    return db.execute(query)

# 対策: パラメータ化クエリ
def verify_token_safe(bearer_token: str, db):
    query = "SELECT * FROM LiteLLM_VerificationToken WHERE token = %s"
    return db.execute(query, (bearer_token,))

影響範囲は v1.81.16 以上 v1.83.7 未満。抽出できたデータの中身も深刻で、1 行の認証情報レコードに OpenAI の組織キー・Anthropic のワークスペース管理者権限キー・AWS Bedrock の IAM 認証情報がまとめて入っているケースがあり、単なる Web アプリの SQLi というよりクラウドアカウント侵害に近い被害規模になり得ると指摘されています。

CVSS8.7のMCP経由コマンドインジェクション(CVE-2026-42271)

もう一件は、MCP サーバーを保存する前にプレビュー確認するための 2 つのエンドポイント(POST /mcp-rest/test/connectionPOST /mcp-rest/test/tools/list)が原因でした(GHSA-v4p8-mg3p-g94g)。

これらのエンドポイントは stdio トランスポート用の command / args / env を含む MCP サーバー設定をリクエストボディでそのまま受け取り、接続テストのために プロキシのホスト上でサブプロセスとして実行 していました。しかもロールチェックがなく有効な API キーさえあれば通ってしまうため、権限の低い内部ユーザーキーの持ち主でも任意コマンドを実行できる状態でした。影響範囲は 1.74.21.83.6

修正までのタイムライン

日付 CVE 出来事
2026-04-13 CVE-2026-42208 / CVE-2026-42271 litellm 1.83.7 リリース。両CVEを修正
2026-04-25頃 CVE-2026-42208 GitHub Security Advisory 公開
2026-04-26 16:17 UTC CVE-2026-42208 公開から約36時間7分で初回悪用試行を検知(Sysdig)
2026-05-08 CVE-2026-42208 CISA KEVカタログに追加、連邦機関に5/11までのパッチ適用を義務化
2026-05-21 (参考)CVE-2026-48710 Starlette 1.0.1 リリース(BadHost修正)
2026-05-22 (参考)CVE-2026-48710 BadHost 一般公開・詳細開示
2026-05-27 litellm Issue #28993 提起(fastapiピンがStarlette修正版の解決を阻害)
2026-06-06 (参考)CVE-2026-48710 litellm 1.88.0 リリース。fastapiピンをようやく解除(fastapi>=0.136.3,<1.0 / starlette>=1.0.1,<2.0
2026-06-08 CVE-2026-42271 CISA KEVカタログに追加(本番環境での悪用を確認)

litellm 自身の 2 件の CVE は 1.83.7 で確実に修正されています。ここまでは「パッチを当てれば終わり」に見えます。

本当の脅威はここから — StarletteのBadHostとの連鎖

litellm の 2 件の CVE とは別に、litellm を含む ASGI エコシステム全体を揺るがした脆弱性が CVE-2026-48710「BadHost」 です。FastAPI・Starlette・vLLM・litellm・MCP サーバー・パスベース認証ミドルウェアを使う Python ASGI アプリ全般に影響し、Starlette のリード開発者 Marcelo Trylesinski 氏のブログによれば、Starlette は月間 3.25 億ダウンロード規模(前年の月間 5,700 万から急増)というエコシステムの土台に位置します。

問題の中身はシンプルです。ASGI のルーティングはリクエストの生パスを見て動作するのに対し、request.url は HTTP の Host ヘッダーから再構築されます。この 2 つが食い違うケースを検証していなかったため、Host ヘッダーに /?# を混ぜ込むと request.url.path を実際にルーティングされたパスとズラすことができました。

その結果、request.url(生パスではなく)を見て認可判定するミドルウェアやエンドポイントは丸ごとバイパスされます。実証例として、保護された /admin への通常アクセスは 403 Forbidden で弾かれますが、Host ヘッダーを foo? に変えるだけで同じリクエストが 200 OK になる、というものが報告されています。

この脆弱性は OSTIF(Open Source Technology Improvement Fund)が助成した vLLM の監査の中で、ドイツのセキュリティ企業 X41 D-Sec が 2026年1月に発見したものです。修正版の Starlette 1.0.1 がリリースされたのは 5月21日、一般公開はその翌日の 5月22日で、運用者にはパッチ適用の猶予がほぼありませんでした。

セキュリティ企業 Horizon3.ai は、この BadHost(CVE-2026-48710)と litellm のコマンドインジェクション(CVE-2026-42271)を連鎖させることで、ネットワーク到達可能な任意のホストから無認証の RCE に到達できることを実証しており、組み合わせた場合の CVSS スコアは 10.0 と報告されています。

1.83.7に上げても、約2ヶ月は終わっていなかった — fastapiピンの罠

ここが今回いちばん見落としやすいポイントです。CVE を修正した 1.83.7(4月13日)以降も、それに続く v1.83.14-stable.patch.* シリーズや v1.86.1v1.87.0 に至るまで、litellm は fastapi==0.124.4完全一致で固定 し続けていました。

そして fastapi==0.124.4starlette>=0.40.0,<0.51.0 に依存します。つまり pip の依存解決の結果、Starlette は BadHost の影響を受ける 0.50.0 に落ち着いてしまう のです。修正版の 1.0.1 系列は、この上限指定のせいでそもそも解決候補に入りません。

この矛盾は 2026年5月27日、litellm の Issue #28993「fastapi==0.124.4 pin blocks starlette CVE-2026-48710 (BadHost)」として報告されています。litellm のコードベースには from starlette import の参照が約 68 箇所あり、しかもその多くが proxy/auth/*proxy/middleware/* に集中しています。まさに BadHost が狙う認可判定の実装そのものです。

fastapi を 0.124 から 0.136 系へ上げるには複数回の破壊的変更をまたぐ必要があり、それに伴って Starlette も 0.50 から 1.0 という大きなメジャーバージョンアップになるため、68箇所のインポートを新しい API に対して個別に検証する必要がありました。コンテナスキャナーが当時の litellm イメージを軒並み critical 判定にしていたのも、この構造が原因です。

このピンがようやく解除されたのは 2026年6月6日リリースの 1.88.0fastapi>=0.136.3,<1.0 / starlette>=1.0.1,<2.0)。つまり CVE番号としては 1.83.7 で「解決」していても、実行環境の Starlette が実際に安全なバージョンになるまでには、そこからさらに約54日を要した ことになります。「CVE番号を潰した」ことと「脆弱性クラスが実行環境から消えた」ことはイコールではない、という典型例です。

現在の litellm(1.88.0 以降・執筆時点の最新系列を含む)はこのピンが解消済みのため、最新版にきちんと追従していれば影響はありません。問題は 1.83.71.87.x の間でアップグレードを止めてしまっている環境 です。「重大 CVE のパッチは当てたから安心」と判断して、それ以降のマイナーアップデートを追っていないケースは意外と多いはずです。

今すぐ確認すべきこと

まず、自分の環境の実バージョンを確認しましょう。

pip show litellm
pip show fastapi
pip show starlette

litellm1.83.7 以上(重大CVE対応済み)でも、starlette1.0.1 未満なら BadHost の影響範囲に入っている可能性があります。特に 1.83.71.87.x に留まっている環境は要注意です。次のスクリプトで機械的にチェックできます。

from importlib.metadata import version
from packaging.version import Version

SAFE_VERSIONS = {
    "litellm": Version("1.83.7"),
    "starlette": Version("1.0.1"),
}

for pkg, safe in SAFE_VERSIONS.items():
    try:
        current = Version(version(pkg))
    except Exception:
        print(f"[skip] {pkg} is not installed")
        continue
    status = "OK" if current >= safe else "VULNERABLE"
    print(f"{pkg}: installed={current} required>={safe} -> {status}")

starletteVULNERABLE と出た場合の対策は次のとおりです。

  • 第一選択: litellm を 1.88.0 以上へアップグレードする(fastapiピンが解除済みで、依存解決だけで Starlette も安全なバージョンになる)
  • 何らかの事情で litellm のアップグレードがすぐできない場合は、pip install "starlette>=1.0.1" を litellm のインストール後に個別実行し、依存解決の警告や実際の動作崩れがないか検証環境で確認する(暫定回避策)
  • 恒久対応が取れるまでの間、リバースプロキシや API ゲートウェイ側で Host ヘッダーのバリデーション(許可リスト以外を拒否)を追加し、BadHost の悪用パターンを止める
  • MCP のテストエンドポイント(/mcp-rest/test/connection 等)を外部公開している構成であれば、アクセスを内部ネットワークのみに制限する

著者視点の発見ポイント

今回リサーチしていちばん印象に残ったのは、CVE 単体のニュースだけを追っていると気づけない「依存解決の副作用」でした。litellm の 2 件の CVE 自体は 1.83.7 で確実に直っています。しかし「アップグレードしたから安全」という判断は、そのアップグレードが依存パッケージの固定バージョンによって無効化されていないかまで見て初めて成立します。

これは litellm 固有の問題というより、厳格なバージョン固定(==)を採用しているあらゆる依存関係で起こり得るパターン です。パッチノートの CVE 番号だけでなく、実際にインストールされた推移的依存のバージョンまで確認する習慣が、今回のようなケースを防ぐ最後の砦になります。

まとめ

  • litellm の SQL インジェクション(CVSS9.3)とコマンドインジェクション(CVSS8.7)は 2026年4月13日リリースの 1.83.7 で修正済み
  • しかし fastapi のバージョン固定により、そこから 1.87.x までは Starlette が脆弱版 0.50.0 に解決されたままで、BadHost(CVE-2026-48710)経由の認証バイパスが残っていた
  • BadHost とコマンドインジェクションの連鎖は無認証 RCE に到達しうる(Horizon3.ai の分析で組み合わせ CVSS 10.0)
  • fastapi のピンが解除され根本的に解決したのは 2026年6月6日リリースの 1.88.0。それ以前のバージョンに留まっている環境は今も対象になり得る
  • pip show litellm / fastapi / starlette で実バージョンを確認し、Starlette が 1.0.1 未満なら litellm を 1.88.0 以上へアップグレードする

参考リンク

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?