CyberFix Note
脆弱性・CVE解説

LiteLLMのMCP認証バイパスCVE-2026-59822。偽のAuthorizationヘッダが空のUserAPIKeyAuth()に化ける機構

対象の目安: LiteLLMやMCPサーバーを社内で運用する開発基盤担当と情報システム担当 / 実務

ソウ攻撃・脆弱性リサーチ担当
・ 約55分で読めます
LiteLLMのMCP認証バイパスCVE-2026-59822。偽のAuthorizationヘッダが空のUserAPIKeyAuth()に化ける機構

社内でLLMの呼び出しを1か所に集めるAIゲートウェイは、モデルのAPIキーだけを持っているわけではありません。Model Context Protocol(MCP)のゲートウェイ機能を有効にしていれば、GitHubやSlackや社内APIへ接続するための資格情報も同じ場所に集まります。その入口の認証が、キー検証で弾かれたはずのAuthorizationヘッダで素通りしていたというのが、BerriAIのLiteLLMに割り当てられたCVE-2026-59822です。

NVDの説明は次の内容です。1.84.0より前のLiteLLMのMCP Streamable HTTPエンドポイントで、偽造したAuthorizationヘッダがOAuth2パススルー用のフォールバック経路を起動し、失敗したLiteLLMキーの検証が空の UserAPIKeyAuth() オブジェクトに置き換えられることで、有効なLiteLLMキーなしにMCPのツールへ到達できました。修正は1.84.0です。CISAは2026年9月2日、実際の悪用の証拠にもとづいてこの脆弱性をKnown Exploited Vulnerabilities(KEV)カタログへ追加しています。

この記事は、LiteLLMやMCPサーバーを社内で立てている開発基盤担当と情報システム担当に向けて、GitHub Security Advisory、NVD、CVEレコード、CISAのKEVカタログ、LiteLLMの修正コミットとリリースノートという一次情報から、機構、影響の見極め方、暫定策、更新後の後始末を整理します。攻撃を再現する手順は扱いません。確認や設定変更は自組織が管理する環境に限って行い、他者の環境への試行は不正アクセス禁止法などの関連法令に触れます。記述は執筆時点(2026年9月6日)に確認できた範囲に限ります。

一次資料でそろえた事実

まず、参照できる値を並べます。GitHub Security Advisoryの識別子はGHSA-7488-6r32-c95qで、GitHub Advisory Database上のsummaryは「LiteLLM: MCP Authentication Bypass via OAuth2 Passthrough Fallback」、severityはhighです。影響を受ける範囲はpipパッケージlitellmの1.84.0未満、修正版は1.84.0以上です。NVDが生成したCPEの照合条件も cpe:2.3:a:litellm:litellm:* のversionEndExcludingが1.84.0で、同じ区切りになっています。

項目
CVECVE-2026-59822
GHSAGHSA-7488-6r32-c95q
影響を受ける版litellm 1.84.0 未満
修正版1.84.0(2026年5月14日公開)
CWECWE-287 Improper Authentication / CWE-306 Missing Authentication for Critical Function
CVSS v4.08.8 HIGH(CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:L/VA:N/SC:N/SI:N/SA:N、GitHub付与)
CVSS v3.18.2 HIGH(CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N、NVD一次評価)
KEV dateAdded / dueDate2026-09-02 / 2026-09-16
KEV forensicTriageNo
KEV knownRansomwareCampaignUseUnknown
SSVC(CISA)Exploitation: active、Automatable: yes、Technical Impact: partial

CVSSの2つの値は、評価者も版も違います。v4.0の8.8はGitHub Security Advisoryのソース(security-advisories@github.com)がSecondaryとして付けたもので、v3.1の8.2はNVD(nvd@nist.gov)がPrimaryとして付けたものです。どちらもVI(またはI)をLowに置いている点が共通しています。読み出し寄りの影響として評価された、ということです。この点は後述のSSVCのTechnical Impactがpartialであることとも整合します。

公表日については、参照する資料で値が異なります。NVDのpublishedは2026-07-08T20:16:57で、lastModifiedは2026-09-03T13:05:59、vulnStatusはAnalyzedです。GitHub側のアドバイザリページに埋め込まれた日時はこれより前を指しており、単一の公表日として断定できる値がありません。この記事では、確実に一致している修正版のリリース日(2026年5月14日)とKEV追加日(2026年9月2日)を時間軸の基準として使います。報告者としてはGHSAのクレジット欄にyaarasの名前が載っています。

日本側の状況も確認しておきます。JVNDBのMyJVN検索でLiteLLMを検索した結果は、2026年9月6日時点で該当エントリなしでした。JPCERT/CCやIPAによるLiteLLM固有の注意喚起も見当たりません。国内の窓口経由の情報を待つ運用にしていると、この種のOSS由来の脆弱性は拾えないことがあります。

GHSA-7488-6r32-c95qのImpactは「LiteLLM's MCP Streamable HTTP endpoint could allow an unauthenticated attacker to establish an authenticated MCP session using an arbitrary Bearer token.(LiteLLMのMCP Streamable HTTPエンドポイントは、未認証の攻撃者が任意のBearerトークンを使って認証済みのMCPセッションを確立することを許しうる)」「An attacker could use this to list and call configured MCP tools and access connected services exposed through MCP.(攻撃者はこれを使って、設定済みのMCPツールを列挙して呼び出し、MCP経由で公開されている接続先サービスへアクセスできる)」と記載しています。Patched versionsは1.84.0、severityはhighで、この画面のCWE欄は「No CWEs」です。CWE-287とCWE-306は、GitHubがCNAとして登録したCVEレコードのproblemTypesに記載があり、NVDもそこからSecondaryとして取り込んでいます(GitHub Advisory Database側の一覧画面に表示されるのはCWE-287だけです)。Workaroundsの原文は「If upgrading is not immediately possible, disable MCP routes or block access to /mcp/ and related MCP endpoints at your reverse proxy or API gateway.」です。

NVDのCVE-2026-59822は、published 2026-07-08T20:16:57.683、lastModified 2026-09-03T13:05:59.573、vulnStatus Analyzedです。metricsにはcvssMetricV40(security-advisories@github.com、Secondary、baseScore 8.8 HIGH)とcvssMetricV31(nvd@nist.gov、Primary、baseScore 8.2 HIGH)が記録されています。weaknessesはsecurity-advisories@github.comをsourceとするSecondaryのCWE-287とCWE-306です。cisaExploitAddは2026-09-02、cisaActionDueは2026-09-16です。参照リンクには修正コミット、Pull Request #26463、v1.84.0のリリース、GHSA、KEVカタログ、そしてWiz Researchのブログが含まれます。

失敗したキー検証が空のUserAPIKeyAuth()に置き換わる機構

修正はコミット73869f0faf7d11ee21adcb5f91b8c33a340b6c2c(Pull Request #26463)で入りました。変更されたのは litellm/proxy/_experimental/mcp_server/auth/user_api_key_auth_mcp.py とそのテストです。コミットメッセージとリリースノートに、直された内容が2つ書かれています。

1つ目がCVE本文に対応する経路です。MCPリクエストの認証処理は、まずLiteLLM専用ヘッダである x-litellm-api-key を見ます。これが無く、標準の Authorization ヘッダだけがある場合、その値をまずLiteLLMの仮想キーとして検証します。ここで401や403になったとき、修正前の実装は「これはLiteLLM宛のキーではなく、上流のMCPサーバー向けのOAuth2トークンをパススルーしているのだろう」と解釈し、例外を捕まえて空の UserAPIKeyAuth() を返していました。このフォールバックはOAuth2認証を必要とする上流MCPサーバーへの対応として追加されたものでしたが、対象サーバーの auth_type 設定に関係なく発火しました。結果として、検証に失敗したという事実が、権限を絞る方向ではなく身元を消す方向へ倒れます。

この経路が成立する条件も押さえておきます。捕捉していたのは401と403だけで、それ以外のコードはそのまま伝播します。たとえばDBを接続していない構成では、仮想キーの検証が no_db_connection のコード400で失敗するため、フォールバックには入らずリクエストは拒否されます。素通りが起きるのは、認証バックエンドが無効なキーに対して401か403を返す構成です。

2つ目は同じ修正で直った公開ルート判定です。修正前は ".well-known" in str(request.url) という書き方で、URL全体に対する部分一致でした。str(request.url) にはクエリ文字列が含まれるため、任意のMCPルートに ?.well-known を付けるだけで公開ルート扱いになりました。修正後は request.url.path.startswith("/.well-known/") に変わり、パスの前方一致だけを見るようになっています。CVE-2026-59822の説明文が記載しているのはOAuth2フォールバック側だけですが、同じコミットでこちらも塞がれています。

要点だけを概念として書き直すと、変更の方向は次のようになります。実際の差分ではなく、判断の流れを示すための再構成です。

# 修正前の判断(概念): LiteLLMキーの検証に失敗したら匿名セッションへ読み替えていた
try:
    return validate_litellm_key(request)
except (HTTPException, ProxyException):
    return UserAPIKeyAuth()   # 身元が空のまま先へ進む

# 修正後の判断(概念): 対象MCPサーバーがすべて auth_type=oauth2 のときだけフォールバックする
try:
    return validate_litellm_key(request)
except (HTTPException, ProxyException):
    if _target_servers_use_oauth2(target_servers):
        return UserAPIKeyAuth()
    raise

修正で新設されたヘルパーは2つです。_extract_target_server_names_from_path/mcp/{server_name}/{server_name}/mcp の形だけを解決し、それ以外の形は空リストを返します。_target_servers_use_oauth2 は、対象となるサーバーがすべて auth_type == oauth2 のときにだけTrueを返します。対象が空、名前が解決できない、oauth2以外のサーバーが1つでも混ざる、のいずれでもフォールバックは動かず、そのまま認証エラーになります。x-mcp-servers ヘッダで対象が明示されている場合はそちらが優先され、明示的な空リストも同じくfail closedとして扱われます。

ProxyException のコードの扱いについては、経緯を分けて書いておきます。73869f0はHTTPExceptionとProxyExceptionの捕捉を1つにまとめる際に int(e.code) を導入しました。ProxyExceptioncode を文字列へ正規化するため、code=None で渡された場合は int("None") がValueErrorになり、認証エラーが未処理の500へ書き換わります。この回帰は同じPull Requestの後続コミット0a4640fで、整数と文字列の両方の形と比較する書き方に直されました。修正コミットを1つだけ読んで判断すると、この部分の挙動を取り違えます。

コミット73869f0のメッセージは、直した2点を次のように説明しています。(1) 公開ルート判定が ".well-known" in str(request.url) というURL全体への部分一致だったため、クエリ文字列やホスト名や深いパスセグメントにマーカーを紛れ込ませることで任意のMCPルートで認証を回避できた。判定は request.url.path.startswith("/.well-known/") に置き換えた。(2) OAuth2パススルーのフォールバックが user_api_key_auth の401および403をすべて捕捉して匿名の UserAPIKeyAuth() に置き換えていたため、対象サーバーの auth_type 設定に関係なく発火し、でたらめな Authorization ヘッダで失敗したLiteLLM認証を匿名セッションに交換できた。フォールバックは、リクエストが対象とするMCPサーバーがすべて運用者によって auth_type=oauth2 に設定されている場合のみ動作するようになった。変更ファイルは litellm/proxy/_experimental/mcp_server/auth/user_api_key_auth_mcp.py とテストです。

後続コミット0a4640fのメッセージは「Greptile flagged a regression introduced in the previous commit's merged exception handler」と書き出し、ProxyException.__init__codestr(code) で正規化するため code=None が文字列 "None" になり、int(...) での変換がValueErrorとなって認証エラーが未処理の500へ書き換わる、と説明しています。修正は整数と文字列の両方の形と比較する形で、code=None のケースの回帰テストが追加されています。

v1.84.0のリリースノートのImportant Behavior Changesには「MCP public-route detection no longer matches query strings; OAuth2 fallback no longer fail-opens」という項目があり、「MCPRequestHandler.process_mcp_request checks request.url.path.startswith("/.well-known/") instead of ".well-known" in str(request.url). Query-string smuggling like ?.well-known is rejected. When an Authorization header fails LiteLLM-key validation, the handler no longer treats the failure as "OAuth2 passthrough" and returns an empty UserAPIKeyAuth().」と記載されています。Restore prior behaviorの欄はNoneで、以前の挙動へ戻す設定は用意されていません。

匿名セッションがどのMCPサーバーまで届くのか

身元が空のセッションが作れたとして、そこから何ができるかは構成によって変わります。Pull Request #26463の本文は、この点について具体的に書いています。get_allowed_mcp_serversallow_all_keys=True に設定されたサーバーを無条件に和集合していたため、未認証の呼び出し元がそれらのサーバーでツールを完全に使える状態になった、という記述です。

allow_all_keys はLiteLLMのドキュメントで「サーバーを、キーやチームのMCP権限にそのサーバーが列挙されていない場合でも、すべてのLiteLLM APIキーから利用可能にする」設定と定義されています。運用の都合で立てた社内向けMCPサーバーにこの設定を付けていると、身元が空のセッションからも同じ扱いで見えることになります。

権限モデルの既定値も見ておきます。LiteLLMのMCP権限は、キー、チーム、エンドユーザー、エージェント、内部ユーザー、組織の6つの層の積集合で決まります。組織は上限として働きます。ドキュメントは、どの層にもリストが無い場合について「If no level has a list, the request can access every MCP server (open by default).(どの層にもリストが無ければ、そのリクエストはすべてのMCPサーバーへアクセスできる。既定はオープン)」と明記しています。ただしこれは現行版のドキュメントが正規のキーについて説明している既定値です。脆弱版で作られた身元の空なセッションにこの記述がそのまま当てはまるかどうかは、一次資料からは確認できませんでした。Pull Requestが影響として書いているのは allow_all_keys=True のサーバーが和集合されるところまでで、その範囲を超えて全サーバーへ届いたとする一次情報は見当たりません。権限を絞る設定を明示的に入れていない環境ほど到達範囲が広がるという話は、正規のキーが漏れた場合の被害範囲の議論として読むほうが実態に合います。

到達先として想定されるのは、そのゲートウェイに束ねている接続先のうち、上の条件に当てはまるものです。GitHub、Atlassian、Slack、Linear、社内の業務APIなどをMCPサーバーとして登録している構成であれば、ツールの列挙と呼び出しがそこへ届きます。読み出し系のツールしか登録していなければ、影響は情報の閲覧に留まります。イシューの作成、メッセージの送信、チケットの状態変更といった書き込み系が含まれていれば、影響の性質が変わります。NVDのCVSS v3.1が完全性への影響をLowと評価している点は、平均的な構成を見た評価であって、自組織の構成での影響とは別に考える必要があります。

構成を確認するときに見る場所も挙げておきます。LiteLLMのMCPゲートウェイは、config.yamlの mcp_servers ブロックにサーバーごとの接続先、トランスポート、auth_typeauth_value を書く形で設定します。auth_type に指定できる値はnone、api_key、bearer_token、basic、authorization、token、oauth2、oauth2_token_exchange、oauth2_id_jag、true_passthrough、aws_sigv4などです。今回のフォールバックが本来対象としていたのはoauth2系の設定を持つサーバーで、修正後はその条件を満たす場合にだけ動きます。裏を返せば、oauth2を1つも使っていない構成でも、修正前は同じフォールバックが発火していたことになります。

MCPという仕組みそのものが持つ攻撃面については、次の記事で整理しています。

あわせて読みたい

MCPサーバーのセキュリティ。AIエージェントとツール接続の信頼境界

LiteLLMのMCP Permission Managementのページは、MCPサーバーへのアクセス権をキー、チーム、エンドユーザー、エージェント、内部ユーザー、組織の各層で定義し、実効的な権限をそれらの積集合として決めると説明しています。組織レベルの設定は上限として働きます。どの層にもリストが無い場合は「the request can access every MCP server (open by default)」と記載されています。運用の推奨姿勢として require_key_mcp_access_defined: true を挙げ、「Turning this on is the recommended posture.」と書いています。すべてのMCPサーバーへのアクセスを拒否するセンチネル値として no-mcp-servers があり、ツール単位の制御として mcp_tool_permissions(server_idをキーにツール名のリストを持つ)が用意されています。

KEVのdueDateとBOD 26-04の是正期限を分けて読む

CISAは2026年9月2日、7件の脆弱性をKEVカタログへ追加しました。この7件は是正期限で2つに分かれています。

CVEベンダー / 製品dueDateforensicTriage
CVE-2026-9586Sangoma / Switchvox2026-09-05Yes
CVE-2026-49869Kestra / Kestra OSS2026-09-05Yes
CVE-2026-82329JFrog / Artifactory2026-09-05Yes
CVE-2026-83548SonicWall / SMA10002026-09-05Yes
CVE-2026-83549SonicWall / SMA10002026-09-05Yes
CVE-2026-48710Kludex / Starlette2026-09-16No
CVE-2026-59822BerriAI / LiteLLM2026-09-16No

KEVのdueDateだけを見ると、3日側の5件はいずれもTechnical Impactがtotal、14日側の2件はpartialです。ただしBOD 26-04の是正期限は、この1つの変数で決まるものではありません。ディレクティブは期限を決める変数として資産の公開状況(Publicly Exposed)、KEV収録、攻撃の自動化可能性(Automatable)、悪用後の技術的影響(Technical Impact)の4つを挙げ、期限はCVEごとではなく資産ごとに決まると定めています。KEVのエントリに載るdueDateは1つのCVEにつき1つの値なので、資産の公開状況の判定はそこに含まれていません。

Table 1: Remediation Timelinesの行を当てはめます。CVE-2026-59822はKEV収録がYes、Automatableがyes、Technical Impactがpartialです。この組み合わせで資産が公開されている場合(行2)の期限は3日、公開されていない場合(行10)は14日です。KEVに載っている2026-09-16は後者に対応する値であり、インターネットから到達できるLiteLLMを持っている組織にとっての期限ではありません。KEVのrequiredActionも「Stakeholders are responsible for evaluating each asset's internet exposure and ensuring adherence to BOD 26-04 patching guidelines.(各資産のインターネット露出を評価し、BOD 26-04の適用を確かめる責任は利用側にある)」と書いています。

partialという評価は「軽い」という意味でもありません。BOD 26-04の枠組みでは、攻撃がソフトウェアの挙動に対する完全な制御を与えるかどうかが分かれ目です。CVE-2026-59822で得られるのは、MCPゲートウェイの匿名セッションであって、LiteLLMプロセスやホストの掌握ではありません。CVSSでも完全性への影響がLowに置かれていることと整合します。totalとpartialの差が効くのは、3日側にforensic triageが付くかどうかという別の軸です。

BOD 26-04が拘束するのは米国の連邦文民行政機関で、日本の組織を法的に拘束するものではありません。日付の使いどころは別にあります。CISAが実際の悪用を確認したうえで収録した事実と、自動化可能と判断した事実の2つは、社内で優先度を上げるための客観的な根拠になります。逆に、KEVの14日という値を緊急度を下げる材料として使うのは筋が通りません。BOD 26-04の考え方に沿えば、外部から到達できるLiteLLMは3日側に入ります。社内説明では、KEVのdueDateより先に自組織の到達性の判定を置きます。KEVとEPSSを日々の優先度付けへ組み込む方法は、次の記事で整理しています。

あわせて読みたい

脆弱性対応の優先順位付け。CVSSだけに頼らないEPSSとCISA KEVの使い方

KEVカタログのJSONフィードは、執筆時点でcatalogVersion 2026.09.04、count 1695です。CVE-2026-59822のエントリは、vendorProjectがBerriAI、productがLiteLLM、vulnerabilityNameが「BerriAI LiteLLM Improper Authentication Vulnerability」、dateAddedが2026-09-02、dueDateが2026-09-16、knownRansomwareCampaignUseがUnknown、forensicTriageがNo、cwesがCWE-287とCWE-306です。shortDescriptionは「BerriAI LiteLLM contains an improper authentication vulnerability in the MCP Streamable HTTP endpoint that could allow an unauthenticated attacker to establish an authenticated MCP session using an arbitrary Bearer token.」で、requiredActionはベンダーの指示に従った緩和策の適用と、BOD 26-04およびForensics Triage Requirementsへの準拠を求める内容です。なお、KEVカタログでBerriAI LiteLLMのエントリは3件目で、先行するのはCVE-2026-42208(SQLインジェクション、2026-05-08追加)とCVE-2026-42271(コマンドインジェクション、2026-06-08追加)です。

BOD 26-04(2026年6月10日発出)は、是正の緊急度をPublicly Exposed、In the KEV、Automatable by Adversary、Technical Impactの4つで決めると定め、16行のTable 1: Remediation Timelinesを掲げています。KEV収録済みかつAutomatableがYesの行は、Publicly ExposedがYesならTechnical Impactがtotalで「3 days & forensic triage」、partialで「3 days」、Publicly ExposedがNoならtotalもpartialも「14 days」です。「For each asset detected to contain an instance of a CVE ID, the vulnerability shall be remediated ... within the timeline defined in Table 1」と資産単位での適用を明示し、期限は状況で動くもので「one valid mitigation is to remove the system from the internet; that action changes the value of "Publicly Exposed" from Yes to No」とも書いています。同ディレクティブはBOD 19-02とBOD 22-01を失効させています。

悪用の観測について確認できること

一次資料として確定できる悪用の事実は、CISAがKEVへ収録したことと、SSVCのExploitationがactiveと記録されていることです。CISAは9月2日の告知でも、追加の根拠を実際の悪用の証拠(evidence of active exploitation)としています。

これに加えて、NVDがCVE-2026-59822の参照(Third Party Advisory)として収録しているのが、Wiz Researchが2026年8月27日に公開したハニーポットの観測記事です。この記事は本脆弱性の発見元としてWiz Researchを挙げ、トークン検証が失敗したときに要求を拒否するのではなく制限のない空の UserAPIKeyAuth() オブジェクトを返す、と機構を説明しています。そのうえで、自社のハニーポットで悪用を観測したとし、1文字のトークンを使ってモデル列挙エンドポイントを探索するリクエストを挙げています。ただし記事に掲載されているそのリクエストは GET /v1/modelsAuthorization: Bearer x を付けたもので、CVE-2026-59822の脆弱な処理が置かれているMCP Streamable HTTPのハンドラを通る経路ではありません。悪用を観測したというWizの記述と、掲載されているリクエストの例は、別のものとして読む必要があります。

読むときの前提を2つ添えます。1つ目は、これがハニーポット環境での観測であり、実運用環境での被害確認ではないことです。悪用の開始時期、被害件数、露出台数を示す一次情報は執筆時点で確認できませんでした。2つ目は、ランサムウェアとの関係を断定できないことです。同じ記事はランサムウェアグループとの関連付けについて外部の研究者による指摘として触れていますが、対象は複数の脆弱性を組み合わせた連鎖であって、CVE-2026-59822単体の話とは限りません。CISAのKEVもknownRansomwareCampaignUseをUnknownとしています。

観測の位置づけをもう1段整理します。CISAがExploitationをactiveと記録してKEVへ収録したことと、Automatableをyesと判定したことは、CISAが自ら公開している値です。社内で優先度を説明する根拠には、この2つを使います。ハニーポットの観測は、AIインフラ全般が自動探索の対象になっている状況を示す材料としては読めますが、掲載されているリクエストの例が当該CVEの経路を通らない以上、この脆弱性の実証やAutomatable判定の直接の証拠としては使えません。標的を選んだ攻撃が起きているかどうかも、公開されている資料からは判断できません。

Wiz Researchが2026年8月27日に公開したAIインフラのハニーポット観測記事は、「Wiz Research discovered an authentication flaw in LiteLLM's MCP Gateway (CVE-2026-59822).」と発見を報告し、機構を「The vulnerability sits in the OAuth2 header handling: when token validation fails, rather than rejecting the request, the server returns an empty UserAPIKeyAuth() object with no restrictions.」と説明しています。「Any Bearer token (even just a single character, e.g., x) grants full MCP access.」および「We observed exploitation of this vulnerability in our honeypots, with requests using single-character tokens to probe model enumeration endpoints.」という記述があり、90日分のテレメトリでAIインフラに対する継続的な攻撃活動を観測したとしています。掲載されているリクエストの例は GET /v1/models HTTP/1.1Authorization: Bearer x で、MCP Streamable HTTPのパスではありません。同記事はCVE-2026-42271とStarletteのCVE-2026-48710の連鎖による未認証のコード実行、暗号資産の採掘、プロンプトインジェクション、稼働中プロセスのメモリからのマスターキー抽出にも触れています。NVDはこの記事をCVE-2026-59822の参照(Third Party Advisory)として収録しています。

同じ時期にKEVへ収録されたStarletteのCVE-2026-48710は、LiteLLMを含む下流のフレームワークに影響しうる別の脆弱性です。AIゲートウェイを運用している場合は、こちらの該当も別途確認する必要があります。

あわせて読みたい

StarletteのHostヘッダ検証不備CVE-2026-48710。request.url.pathとルーティングのずれが認可を迂回する

自組織が該当するかを確かめる手順

確認は自組織が管理する環境に限って行います。他者が運用するエンドポイントへの試行は、たとえ確認目的でも不正アクセス禁止法などに触れます。

  1. 1

    稼働中の版を確認する

    リポジトリのrequirements.txtやHelmのvaluesではなく、実際に動いているプロセスの版を見ます。pipで入れているなら pip show litellm、コンテナならデプロイ済みイメージのタグ、LiteLLM ProxyならUIのバージョン表示です。1.84.0未満であれば該当します。ステージングと本番で版が違う構成では両方を確認します。
  2. 2

    MCPゲートウェイを使っているかを確認する

    config.yamlの mcp_servers ブロック、管理UIのMCP Servers、REST APIの /v1/mcp/server のいずれかで、MCPサーバーを登録しているかを見ます。MCP機能を有効にしていない環境では、この脆弱性の経路は成立しません。ただし1.84.0未満には別の認証バイパス(CVE-2026-49468)も含まれるため、更新の判断は別に行います。
  3. 3

    MCP系エンドポイントの到達範囲を確認する

    対象は /mcp、/mcp/{server_name}、/{server_name}/mcp、そしてRESTの /mcp-rest/tools/list と /mcp-rest/tools/call です。前段のリバースプロキシやロードバランサのアクセス制御が実際にどう効いているかを、設定ファイルの読み合わせだけでなく、自組織の管理下にある位置から実際のリクエストを投げて確かめます。インターネットから到達できるのか、社内のどのセグメントから到達できるのかを書き出します。
  4. 4

    権限設定の緩い箇所を洗い出す

    allow_all_keys: true を設定しているサーバーと、MCP権限リストを持たないキーやチームを一覧します。前者は身元が空のセッションから到達しうる候補として一次資料で確認できるものです。後者は、正規のキーが持つ到達範囲がドキュメントの言う既定オープンになっていないかの確認です。あわせて require_key_mcp_access_defined の設定値を確認します。
  5. 5

    到達可能だった期間を決める

    デプロイ履歴から、1.84.0未満の版を稼働させていた期間と、その間の外部到達性を突き合わせます。この期間が、後のログ確認と資格情報ローテーションの対象範囲になります。

版番号だけを見て更新すると外す点

更新そのものは1.84.0以上へ上げるだけですが、LiteLLMには版の扱いで引っかかりやすい点が3つあります。

1つ目が命名規則の変更です。v1.84.0からLiteLLMのバージョン表記はPEP 440に従うようになり、安定版から -stable サフィックスが外れました。このリリースのDockerタグは litellm:1.84.0 であって litellm:1.84.0-stable ではありません。実際、GitHubのタグ一覧で -stable を含む最新はv1.83.14-stable.patch.3であり、1.84.0以降に -stable 付きのタグはありません。Helmのvalues、requirements.txt、Renovateの更新ルールなどで -stable を前提にピン留めしていると、更新がそこで止まります。

種別旧表記新表記(v1.84.0以降)
安定版vX.Y.Z-stablevX.Y.Z
安定版のパッチvX.Y.Z-stable.patch.NvX.Y.Z.postN
リリース候補vX.Y.ZrcN
開発版vX.Y.ZdevN

リリースノートは、すべてのDockerタグがプレフィックス無しとv付きの両方で公開され(litellm:1.84.0litellm:v1.84.0 は同じイメージを指す)、これは命名の変更だけでリリースの頻度や安定性の保証やイメージの中身は変わらない、と明記しています。

2つ目がサポート範囲です。LiteLLMは2026年6月20日のブログで、直近4本の安定マイナーラインのみをアクティブにサポートする方針を示し、6月29日から適用しています。新しいラインがおよそ週に1本出るため、1ラインあたりの対象期間はおよそ1か月です。執筆時点でPyPI上のlitellmの最新は1.99.0、GitHubの最新リリースタグはv1.99.1です。つまり1.84.0へ上げるだけでは、すでにサポート対象外のラインに乗ることになります。更新先は、リリースノートで現行のサポート対象4ラインを確認してから選びます。

3つ目が1.84.0に含まれる破壊的変更です。リリースノートのImportant Behavior Changesには、パススルーエンドポイントが既定で auth: true になること、api_basebase_url のクライアント指定が制限され資格情報が除去されること、マスターキーでのリクエストがハッシュではなくエイリアスを伝播するようになることなどが並びます。MCP関連では、LiteLLM_MCPUserCredentials.credential_b64 への書き込みが encrypt_value_helper を経由するようになり、OAuthメタデータの探索がSSRFガードに従うようになり、static_headers が呼び出し側の extra_headers より優先されるようになりました。更新の前にこの節を読み、社内のクライアント実装が依存していないかを確認します。

LiteLLMのversion supportのブログは2026年6月20日付で、2026年6月29日から適用されました。原文は「Today the four supported lines are 1.89.x, 1.88.x, 1.87.x, and 1.86.x. Everything 1.85.x and earlier has reached end of life」「With a new line about every week, that works out to roughly a month of coverage per line」です。掲載されているライン名は執筆時点のものではなくブログ公開時点の例であり、現行のサポート対象はリリースノートで確認する必要があります。同ブログは「for rare high-severity issues we'll use our judgment and may patch outside the window(まれな高深刻度の問題については判断のうえ窓の外でもパッチする場合がある)」とも書いています。CVE-2026-59822について公式が案内しているのは1.84.0以上への更新で、1.83.x系へのバックポートの有無は確認できませんでした。

更新できない間の暫定策

更新までに時間がかかる場合の手当ては、公式が案内している範囲に絞ります。GHSAのWorkaroundsが示しているのは、MCPルートを無効化するか、リバースプロキシやAPIゲートウェイで /mcp/ と関連するMCPエンドポイントへのアクセスを遮断する、という2つです。

構成側で締められる箇所もあります。公開範囲の制御としては、サーバー単位の available_on_public_internet を落とす方法と、general_settings.mcp_internal_ip_ranges を自組織の実際のレンジに合わせる方法があります。後者の既定値はRFC1918のプライベートアドレス範囲(10.0.0.0/8、172.16.0.0/12、192.168.0.0/16)にループバック(127.0.0.0/8)を加えたもので、実際の到達経路がプロキシ経由になっている環境では判定が期待どおりにならないことがあります。権限側では、require_key_mcp_access_defined: true を有効にして権限リストを持たないキーを弾く、allow_all_keys: true を棚卸しする、no-mcp-servers センチネルで明示的に全拒否にする、といった手が使えます。

ネットワーク側の手当ても並行します。管理用のポートを公開レンジから外すこと、コンテナイメージのタグを固定して :latest を使わないことは、LiteLLMの本番運用ドキュメントが挙げている項目です。

遮断を選ぶ場合は、副作用の確認を先に行います。/.well-known/ 配下はOAuthのメタデータ探索に使われる経路で、ここを一律に止めると、正規のMCP利用側でも認可サーバーの情報取得が失敗することがあります。止める範囲と、その間に業務側で使えなくなる機能を、先に洗い出しておきます。MCP機能を止めている間、社内のエージェントやツール連携がどう振る舞うかも確認しておくと、問い合わせ対応の量が変わります。

暫定策は修正の代わりにはなりません。GHSAの記述も「すぐに更新できない場合」という条件付きです。遮断や設定変更を入れた場合でも、更新の計画は同時に進めます。設定変更の内容と実施時刻を記録しておくと、更新後にどれを戻すかの判断が楽になります。

LiteLLMのExposing MCPs on the Public Internetのページは、MCPサーバーを外部へ公開するかどうかをサーバー単位の available_on_public_internet で制御し、内部と外部の判定を general_settings.mcp_internal_ip_ranges で行うと説明しています。mcp_internal_ip_ranges を空にしたときに使われる既定のレンジは 10.0.0.0/8、172.16.0.0/12、192.168.0.0/16、127.0.0.0/8 で、自組織の実際のネットワークレンジに合わせて設定します。判定はレジストリ、ツール一覧、ツール呼び出し、動的ルート、OAuthエンドポイントに及ぶと記載されています。

LiteLLMのProxy Production Setupのページは、Kubernetesの構成例のイメージ指定に「pin a version, do not use :latest(バージョンを固定し、:latestを使わない)」と注記しています。マスターキーは LITELLM_MASTER_KEY="sk-<long-random-value>" の形で sk- から始まる値を環境変数に置くこと、salt keyについては「Do not change it after adding a model; it encrypts your LLM API key credentials, and changing it makes them unreadable.(モデルを追加した後は変更しないこと。LLMのAPIキーの資格情報を暗号化しており、変更すると読めなくなる)」と記載しています。

注意

遮断ルールをパスの前方一致だけで書くと取りこぼします。LiteLLMのMCPエンドポイントは /mcp/mcp/{server_name} のほかに /{server_name}/mcp という形も持ち、後者は先頭がサーバー名です。RESTの /mcp-rest/tools/list/mcp-rest/tools/call も別の前置きになります。同じ修正コミットでは、URLの部分一致で公開ルートを判定していた別の経路も塞がれています(CVE-2026-59822の本体はOAuth2フォールバック側の欠陥です)。遮断側で同じ種類の見落としをしないよう、実際のリクエストで到達可否を確かめてください。

接続先サービスの資格情報をローテーションする

1.84.0以上へ上げて終わりにできない理由は、MCPゲートウェイの役割にあります。この機械は、接続先サービスの資格情報を集約する場所です。身元が空のセッションからツールが呼べた期間があったなら、その期間にゲートウェイ経由で使われた可能性のある資格情報は、正当性が確認できないものとして扱うのが安全側です。

対象を整理すると次のようになります。

対象保管場所措置
MCPサーバーごとの静的な資格情報config.yamlの auth_value(api_key、bearer_token、basic、authorization、tokenなど)上流サービス側で新規発行し、旧値を失効させる
OAuth2系のトークンとクライアントシークレットoauth2、oauth2_token_exchange、true_passthrough などの設定と関連ストアクライアントシークレットの再発行と、発行済みトークンの失効
ユーザースコープのMCP資格情報DBの LiteLLM_MCPUserCredentials(1.84.0で encrypt_value_helper 経由の暗号化が入った)利用者ごとの再接続と旧資格情報の失効
LiteLLMのマスターキーと仮想キー環境変数とDBマスターキーの入れ替えと、疑わしい期間に発行された仮想キーの失効

順番は、影響の大きいものから決めます。書き込み権限を持つもの、課金につながるもの、データの持ち出しに使えるものを先に回します。読み出し専用のトークンは後回しにしても構いませんが、対象から外さずに一覧には載せておきます。

ローテーションで抜けやすいのが、上流側での失効です。新しいトークンを発行してconfigを差し替えても、古いトークンが上流サービスで有効なままなら、漏れていた場合の効果がありません。GitHubのPersonal Access Token、Atlassian、Slackなどは、それぞれの管理画面で旧トークンを失効させるところまで行います。あわせて、その上流側の監査ログを同じ期間で確認します。

LiteLLM自身の鍵についても注意点があります。本番運用ドキュメントは、マスターキーを sk- で始まる値として環境変数に置き、シークレットマネージャで管理してローテーションすることを推奨しています。一方でsalt keyについては、DBを使う構成では設定したうえで、モデルを追加した後には変更しないよう書かれています。salt keyを変えると保存済みの暗号化値が読めなくなるためです。マスターキーのローテーションとsalt keyの扱いを混同しないようにします。

資格情報を構成ファイルや環境変数でどう扱うかという設計の話は、次の記事で整理しています。

あわせて読みたい

シークレット管理の実務。APIキー・認証情報をハードコードせず、Vaultやマネージドサービスで守りローテーションする

MCP経由で到達しうるツールを棚卸しする

資格情報の次は、そのゲートウェイが公開しているツールの一覧です。この作業は今回の後始末であると同時に、次に同じ種類の認証不備が出たときの影響評価表にもなります。

手順は4つです。まず、登録済みのMCPサーバーを一覧します。config.yamlの mcp_servers、管理UIのMCP Servers、REST APIの /v1/mcp/server のいずれからでも取れます。次に、各サーバーが公開しているツールを列挙します。3つ目に、列挙したツールを、読み出しだけのものと、削除、送信、課金、権限変更のように取り消しの効かない操作を含むものに分けます。4つ目に、後者へのアクセスを mcp_tool_permissions でツール単位に絞れないかを検討します。

mcp_tool_permissions を使う場合の落とし穴がひとつあります。この設定はserver_idをキーにしてツール名のリストを持ちますが、config由来のサーバーIDはサーバー名と接続設定から導出されます。接続設定を変えるとIDが変わり、既存のキーやチームに設定した権限が対象を見失います。運用で設定変更が入る前提なら、server_id を明示してピン留めしておきます。

トランスポートの種類も影響の重さに関わります。stdioトランスポートで動かしているMCPサーバーは、プロキシのホスト上でプロセスとして起動します。同じLiteLLMのCVE-2026-42271は、まさにこのstdio設定をリクエストボディで受け付けていた点が問題になり、コマンド実行に至ったものでした。stdioで動かしているサーバーがある構成では、そのホスト上で何が起動しうるかを別途確認します。

棚卸しの結果は、サーバー名、トランスポート、auth_type、公開ツールの一覧、破壊的操作の有無、allow_all_keys の設定値、接続先サービスと資格情報の種類、という列を持つ表として残します。次に認証まわりの脆弱性が出たとき、影響範囲の見積もりがこの表を読むだけで済みます。

この棚卸しには、登録したままになっているサーバーを外すという効果もあります。検証のために追加したMCPサーバーが、資格情報を持ったまま本番の設定に残っている状態は珍しくありません。使っていないサーバーは、権限を絞るより先に登録そのものを削除し、上流側の資格情報も失効させます。ゲートウェイに束ねる接続先の数は、そのまま認証不備が出たときの影響範囲になります。

アクセスログで痕跡を探すときの見方

最初に押さえる性質があります。脆弱な版では、x-litellm-api-key が無く Authorization ヘッダだけがあるリクエストについて、キー検証の失敗が匿名セッションへ読み替えられていました。この条件に当てはまるリクエストは、LiteLLM側に認証エラーとして残りません。認証失敗のログが無いことは、試行が無かったことの証明にはなりません。なお、すべての認証失敗が消えるわけではなく、この条件に当てはまらない経路のエラーは通常どおり記録されます。

調査の主軸は、LiteLLMの前段に置いているリバースプロキシやロードバランサのアクセスログです。見る対象を挙げます。

  • MCP系パスへのリクエストと応答コード。/mcp/mcp/{server_name}/{server_name}/mcp/mcp-rest/tools/list/mcp-rest/tools/call への200応答を、送信元IPと時系列で並べます。
  • 想定外の送信元IP。社内のクライアントやCIランナー以外からのアクセスがあるかを見ます。
  • クエリ文字列に .well-known を含むMCPルートへのリクエスト。公開ルート判定の取りこぼし経路にあたるため、正規の利用では現れにくい形です。
  • Authorizationヘッダの値。通常のアクセスログには残りませんが、記録している環境では、極端に短いBearer値や、発行済みの仮想キーと突き合わない値を探します。Wizのハニーポット観測でも1文字のトークンによる探索が記録されています(ただし公開されている例はMCP系パスへのものではありません)。

LiteLLM側のログについては期待を絞ります。MCPツールの呼び出しがどのテーブルへどう記録されるかは公式ドキュメントに明記がなく、spend logsに必ず残ると前提を置くことはできません。実際に自環境で何が記録されているかを、正常なツール呼び出しを1件行って確かめてから調査に使います。

もうひとつ必要なのが、接続先サービス側の監査ログとの突き合わせです。MCPの仕様書も、トークンパススルーのリスクとして「下流のリソースサーバーのログには、実際にトークンを転送しているMCPサーバーではなく、別の送信元から別のアイデンティティで来たように見えるリクエストが記録されうる」と指摘しています。上流のログに呼び出し元がどう見えるかは、そのMCPサーバーへどの資格情報でつないでいるかによって変わり、LiteLLMの製品仕様として一律に決まるものではありません。自環境で正常なツール呼び出しを1件行い、上流側にどう記録されるかを先に確かめたうえで、時刻とツール名と操作対象で寄せる作業に入ります。GitHubやSlackの監査ログを、該当期間について同じ粒度で並べます。

記録が残っていなかった場合は、次に備える形に切り替えます。前段のプロキシで、リクエストパス、クエリ文字列、応答コード、送信元IP、Hostヘッダに相当する値を記録する設定へ変更し、保持期間を決めます。MCPゲートウェイのように多数の接続先を束ねる機械では、その1台のログが調査の起点になります。

CVE-2026-59822への対応と確認

  • 稼働中のLiteLLMの版を実環境で確認し、1.84.0以上であることを確かめた
  • 更新先の版を、リリースノートで現行のサポート対象4ラインを確認したうえで選んだ
  • Dockerタグやピン留め設定に -stable サフィックスが残っていないかを確認し、PEP 440の新表記へ直した
  • 1.84.0のImportant Behavior Changes(パススルーの既定auth、api_baseの制限、static_headersの優先など)を読み、社内クライアントへの影響を確認した
  • すぐに更新できない期間について、MCPルートの無効化または前段での /mcp/ と関連エンドポイントの遮断を検討し、/.well-known/ を止めた場合の副作用を確認した
  • available_on_public_internet、mcp_internal_ip_ranges、require_key_mcp_access_defined、allow_all_keys の設定値を棚卸しした
  • config.yamlの auth_value に置いた資格情報と、OAuth2系のトークンおよびクライアントシークレットを一覧し、書き込み権限を持つものから順に再発行した
  • 上流サービス(GitHub、Atlassian、Slackなど)の管理画面で旧トークンを失効させ、その期間の監査ログを確認した
  • LiteLLMのマスターキーと、疑わしい期間に発行された仮想キーを入れ替えた。salt keyは変更対象から外して扱った
  • 登録済みMCPサーバーと公開ツールを一覧し、破壊的操作を含むツールを区別したうえで mcp_tool_permissions での絞り込みを検討した
  • config由来のサーバーIDを server_id の明示でピン留めし、接続設定の変更で権限が外れない状態にした
  • 前段プロキシのアクセスログでMCP系パスへの200応答と送信元IPを確認し、記録が不足していた項目についてログ設定を見直した

トークンパススルーを禁じたMCP仕様に立ち返る

今回の欠陥を機構として言い直すと、認証が失敗したときに何を返すかという設計の問題でした。MCPの仕様書は、この領域について明確な規範を置いています。2025-11-25版のSecurity Best Practicesは、トークンパススルーを「MCPサーバーが、そのトークンがMCPサーバーへ適切に発行されたものかを検証せずにMCPクライアントから受け取り、下流のAPIへそのまま渡す」アンチパターンと定義し、認可の仕様で明示的に禁止されているとしています。緩和策として書かれているのは「MCP servers MUST NOT accept any tokens that were not explicitly issued for the MCP server.(MCPサーバーは、そのMCPサーバーのために明示的に発行されたものではないトークンを受け入れてはならない)」という1文です。

LiteLLMの実装が倒れたのは、その一歩先でした。自分宛の検証に失敗したという結果を、上流向けのトークンらしいという推定に読み替え、権限を落とすのではなく身元を空にする方向へ進めていました。認証の性質は、成功したときに何を渡すかよりも、失敗したときに何を返すかで決まります。フォールバック経路を書くときは、その経路が「誰でもない利用者」を作り出していないかを見る必要があります。修正後の実装が、対象サーバーが解決できない場合も対象が空の場合もfail closedに倒したのは、この点への回答です。

同じ仕様書は、セッションの扱いについても「MCP servers that implement authorization MUST verify all inbound requests. MCP Servers MUST NOT use sessions for authentication.」と定めています。この節が想定している攻撃は、発行済みのセッションIDを盗んだり推測したりして再利用するもので、無効なBearerトークンから空の認証主体を新しく作る今回の欠陥とは機構が違います。ただし、受け取ったリクエストを毎回検証するという前段の要求は、どちらにも同じように効きます。

もうひとつ、LiteLLM側の事情も見ておきます。1.84.0は本件だけを直したリリースではありません。同じ版でCVE-2026-49468(Hostヘッダインジェクションによる認証バイパス)も修正されています。認証層が request.url.path で実効ルートを決めていたため、細工したHostヘッダによって、認証層が評価するルートとFastAPIが実際にディスパッチするルートがずれうるというものでした。さらに遡ると、1.83.0では /config/update が管理者ロールを検査していなかったCVE-2026-35029が修正されています。こちらは認証済みの利用者がプロキシ設定と環境変数を書き換えられるという内容で、CVSSはv4で8.7、v3.1で8.8です。KEVには収録されていません。

LiteLLMのKEV収録は今回で3件目です。1件目のCVE-2026-42208はSQLインジェクション、2件目のCVE-2026-42271はMCPプレビュー用エンドポイントでのコマンド実行でした。同じ製品の同じ領域で認証と入力処理の問題が続いている状況は、この種のAIゲートウェイをインターネットへ直接向けるかどうかという配置の判断に効きます。BOD 26-04が是正期限の最初の変数に資産の公開状況を置いているのも、そこが緊急度を最も大きく動かすためです。社外のクライアントから使う要件があるとしても、認証を1層だけに任せる構成にする必然性は多くありません。

AIを組み込んだ基盤に固有の攻撃面については、次の記事で整理しています。

あわせて読みたい

プロンプトインジェクションとは。AIエージェント時代の新しい攻撃と防御

MCP Specification 2025-11-25のSecurity Best Practicesは、Token Passthroughの節で「"Token passthrough" is an anti-pattern where an MCP server accepts tokens from an MCP client without validating that the tokens were properly issued to the MCP server and passes them through to the downstream API.」と定義し、「Token passthrough is explicitly forbidden in the authorization specification」と述べています。リスクとして、Security Control Circumvention(下流のリソースサーバーが行うレート制限や検証といった制御の回避)、Accountability and Audit Trail Issues(下流のログに別の送信元と別のアイデンティティから来たように見えるリクエストが残ること)、Trust Boundary Issues、Future Compatibility Riskの4つを挙げています。緩和策は「MCP servers MUST NOT accept any tokens that were not explicitly issued for the MCP server.」です。Session Hijackingの節には「MCP servers that implement authorization MUST verify all inbound requests. MCP Servers MUST NOT use sessions for authentication.」と記載されています。

出典・参考

この記事をシェア

関連する記事

脆弱性・CVE解説

StarletteのHostヘッダ検証不備CVE-2026-48710。request.url.pathとルーティングのずれが認可を迂回する

Starletteの通称BadHost(CVE-2026-48710)を一次情報で整理します。Hostヘッダを検証せずにURLを再構築していたため、request.url.pathがルーティングの実パスと食い違い、パス前方一致の認可ミドルウェアが迂回されます。KEV追加の事実、影響範囲、1.0.1の修正内容、暫定回避策、ログの見方をまとめます。