FlawOpen

flawopen.com/AI Security/berriai-litellm-ghsa-7hp6-salt-key-session-token-privilege-escalation

● FlawOpenの対応付け: CWE-345 · CVSS 9.9 · 緊急
セキュリティ研究 · FlawOpen

LiteLLM:salt key の再利用による権限昇格(GHSA-7hp6)

LiteLLMは、保存された秘密情報とUI・CLIのセッショントークンで同じ暗号化経路を使っていました。認証済みのinternal_userは、自分が制御するIDデータをその経路に通し、proxy_adminへ昇格できました。この権限からMCP stdio経由のコマンド実行に到達します。修正では専用prefixと認証付きAES-GCMコンテキストでトークンの用途を束縛します。CVEや実環境での悪用確認は報告されていません。[1], [2]

💡 わかりやすい解説 (ELI5)

建物が、保管用の封筒を封じる印と管理者用カードの発行に同じ印を使っています。来訪者が封筒の中身に影響を与え、警備員がそれを本物のカードと取り違えます。LiteLLMの修正はセッションカードに専用の印を付け、その印を暗号学的に封印と結び付けます。[1], [2]

主要な概念と専門用語

Salt key
LiteLLMで設定する暗号鍵の材料です。この問題では用途を暗号文に結び付けず、同じ鍵経路を異なる目的に使っていました。[1], [2]
認証付き追加データ(AAD)
トークン種別のprefixなど、暗号文とともにAES-GCMが認証するデータです。変更または欠落すると認証に失敗します。[2]
internal_user と proxy_admin
LiteLLMのロールです。アドバイザリによると、認証済みinternal_userは管理ロールproxy_adminへ昇格できました。[1]
MCP stdio
ローカルプロセスを起動し、標準入力と標準出力で通信するModel Context Protocolの方式です。アドバイザリはproxy_adminがこのendpoint経由でコマンド実行できると説明しています。[1]
CWE-345
データの真正性確認が不十分な弱点です。FlawOpenが選んだ主な編集上の分類で、アドバイザリはCWE-269とCWE-441も挙げています。[1], [5], [6], [7]

フレームワーク対応

  • FlawOpenによるMITRE CWEへの概念上の対応付けです。ベンダーやCVEレコードがこの研究デモに弱点IDを割り当てたものではありません。 CWE-345

ステップ・バイ・ステップの攻撃フロー

ステップ 1

低権限アカウントがkey管理にアクセスする

アドバイザリの前提は認証済みinternal_userです。匿名アクセスは不要ですが、攻撃者はそのロールを既に持つ必要があります。[1]

ステップ 2

metadataが共通経路で暗号化される

アドバイザリによると、key metadata内の制御されたIDデータが暗号化されて返される場合があります。欠陥は、その暗号文を別種のtokenとして後で受け入れる点です。[1], [2]

ステップ 3

セッション処理が別用途の暗号文を受け入れる

修正前は値の暗号化とセッション検証が同じhelperと鍵経路を共有し、token用途を認証付きで束縛していませんでした。IDデータがproxy_adminとして解釈され得ました。[1], [2]

ステップ 4

管理権限からMCP stdioに到達する

アドバイザリによると、proxy_adminはMCP stdio endpoint経由でコマンドを実行できました。これはhost上のプロセス権限であり、モデル自体がコマンドを実行する仕組みではありません。[1]

ステップ 5

用途の束縛が再利用を拒否する

修正はlitellm_login_をAES-GCM AADとして使い、専用decoderで検証します。修正版へ更新してください。EXPERIMENTAL_UI_LOGINの無効化は機能への影響を伴う暫定策です。[1], [2], [3], [4]

根本原因の分析 (Root Cause)

BerriAIのアドバイザリGHSA-7hp6-4w63-5g45は、認証目的の取り違えを説明しています。LiteLLMは保存された秘密情報とUI/CLIセッショントークンの両方に汎用値暗号化helperを使い、セッション認証も同じ鍵経路で復号していました。認証済みinternal_userは、自分が制御するシリアライズ済みIDデータをkey metadataに含めてAPI keyを要求でき、管理経路がその値を暗号化して返しました。その暗号文をbearer tokenとして提示すると、セッション経路が復号し、偽装されたproxy_adminとして解釈する可能性がありました。このロールからMCP stdioのコマンド実行に到達できます。上流修正f7cd90fは発行と検証を変更し、litellm_login_ prefix、そのprefixに結び付いたAES-GCM AAD、専用decoderを使います。salt key自体は引き続き鍵材料です。確認できる境界は、暗号学的に認証されたトークン用途と対応decoderです。保存値の暗号文はセッショントークンとして検証されません。アドバイザリはCVSS 3.1 9.9 Criticalと評価し、1.91.0より後の版は既定で影響を受け、1.87.0〜1.90.xはEXPERIMENTAL_UI_LOGIN=trueの場合のみ影響を受けるとしています。修正版は各ブランチの1.100.4、1.101.3、1.102.2、1.103.1、1.104.0rc2です。暫定策EXPERIMENTAL_UI_LOGIN=falseは脆弱なログイン経路を無効化しますが、CLI SSOとClaude Code gateway loginも使えなくします。CVEや実環境での悪用は確認されていません。コード比較は上流修正の認証境界の変更を示すもので、exploitや完全な認証実装ではありません。[1], [2], [3], [4]

ソースコード比較:脆弱 vs 堅牢化

上流修正はセッショントークンの発行と認証で汎用helperを置き換えます。encrypt_bearer_tokenはprefixをAES-GCM AADとして認証し、decrypt_bearer_tokenは同じprefixとAADを要求します。そのため保存用暗号文をlogin tokenとして再利用できません。これは引用したcommitの抜粋で、単独で動く認証実装ではありません。 salt キーが共有されていることだけでは、用途ごとに固有のキーがあるとは証明できません。ここで確認できる分離は、認証対象のトークン型と対応するデコーダーによるものです。[2], [3]

ソース抜粋: litellm/proxy/auth/auth_checks.py と litellm/proxy/common_utils/encrypt_decrypt_utils.py — upstream commit f7cd90f の抜粋

脆弱な実装
# 修正前:保存値の暗号文もセッショントークンとして発行されていました。
return encrypt_value_helper(valid_token.model_dump_json(exclude_none=True))

# セッション認証では汎用の値 helper で復号していました。
decrypted_token = decrypt_value_helper(hashed_token, key="ui_hash_key")
堅牢化されたセキュアパッチ
# 修正後:セッショントークンには専用の型と AAD があります。
LITELLM_SESSION_TOKEN_PREFIX = "litellm_login_"
return encrypt_bearer_token(
    valid_token.model_dump_json(exclude_none=True),
    prefix=LITELLM_SESSION_TOKEN_PREFIX,
)

# 認証には用途に対応したデコーダーを使います。
decrypted_token = decrypt_bearer_token(
    hashed_token, prefix=LITELLM_SESSION_TOKEN_PREFIX
)

エンジニアリング&システム堅牢化チェックリスト

参考資料

← AI Security Directory →