flawopen.com/AI Security/mcp-python-sdk-oauth-issuer-confusion
MCP Python SDK OAuthのissuer検証不備
GHSA-qx49-fqc8-xw99では、HTTP MCPサーバーが影響を受けるPython SDKのOAuthクライアントが認証情報を送信し得る宛先に影響できました。mcp 1.30.0または2.2.0へ更新し、マシン間認証プロバイダーではissuer=を設定してください。CVEは割り当てられていません。[1], [3], [8]
会社が封印した鍵を、承認済みの案内カードに記載された銀行へ郵送するとします。MCPサーバーがそのカードを渡せる状態で、あるフォールバック経路は記載先が想定した銀行か確認しませんでした。Issuer検証は、鍵を送る前にカードの識別情報と設定上の信頼する銀行を照合する仕組みです。[1], [2]
主要な概念と専門用語
MCPクライアント- Model Context Protocolを使い、MCPサーバーのツールやデータに接続するアプリケーションです。この問題はPython SDKをOAuthプロバイダー付きのHTTPクライアントとして使う場合に影響します。[1]
フレームワーク対応
ステップ・バイ・ステップの攻撃フロー
HTTP MCPクライアントがOAuth認証情報を保持
アプリケーションは影響を受けるmcpバージョンとSDKのOAuthプロバイダーを使用します。クライアントシークレット、署名鍵、または保存済みクライアント登録を保持したまま、完全には信頼できないMCPサーバーへ接続する場合があります。[1]
影響はプロバイダーと権限に依存
受信者は漏えいした認証情報やトークンを付与済み権限の範囲で利用できる可能性があります。告知では無人プロバイダーをCVSS 7.5、ユーザーがログインを開始する対話型プロバイダーを6.5と評価しています。告知によると、CVEはまだ割り当てられていません。[1]
MCP Python SDK OAuthのバージョン別対応マトリクス
| クライアント構成 | 公表された影響条件 | 必要な対応 |
|---|---|---|
mcp 1.9.1–1.29.1を使うHTTP OAuthクライアント | すべての検出経路でissuer検証と、認証情報をissuerに一貫して結び付ける処理が不足していました。 | mcp 1.30.0以降へ更新し、実際にデプロイされたバージョンを確認します。 |
mcp 2.0.0–2.1.1を使うHTTP OAuthクライアント | PRMがなく旧来のフォールバックが動く場合、または403 insufficient_scope後の追加検出で影響します。 アドバイザリのパッケージ範囲はプレリリース2.0.0a1から<2.2.0までです。そのため、影響を受ける2.0.0のプレリリース版も対象です。 | mcp 2.2.0以降へ更新し、実際にデプロイされたバージョンを確認します。 |
事前設定済み認証情報を使うClientCredentialsOAuthProviderまたはPrivateKeyJWTOAuthProvider | 影響バージョンには、認証情報を想定する認可サーバーに結び付けるissuer=設定がありませんでした。 | 更新後にissuer=を明示します。1.xで非推奨のRFC7523OAuthClientProviderから移行します。 |
| SDKで構築したサーバー、stdioクライアント、または独自トークン/ヘッダーを渡すクライアント | このアドバイザリの影響対象ではありません。 | この問題についての対応は不要です。影響を受けるHTTP OAuthクライアントも使う場合は再評価してください。 |
根本原因の分析 (Root Cause)
この信頼境界の問題には、関連する 2 つの原因がありました。影響を受ける一部の検出経路では、認可サーバーのメタデータにある issuer を MCP サーバーとは独立して期待される値と一貫して比較しておらず、保存済みまたは事前設定された資格情報も本来の issuer に結び付けられていませんでした。そのため、悪意のある、または侵害された MCP サーバーがトークン交換先を自ら管理するエンドポイントへ誘導し、クライアントが保持する OAuth 情報を受け取る可能性がありました。修正では検出前に期待する issuer を決定し、不一致を拒否して、保存済み登録をその issuer に結び付けます。無人の machine-to-machine プロバイダーでは明示的な issuer= も必要です。[1], [2]
ソースコード比較:脆弱 vs 堅牢化
修正版SDKにはissuer引数があります。マシン間認証情報を正しい認可サーバーに結び付けますが、SDK更新、古い未バインド登録の削除、漏えいした可能性のある認証情報のローテーションの代わりにはなりません。[2], [3], [8]
ソース抜粋: mcp.client.auth
import os
from mcp.client.auth import ClientCredentialsOAuthProvider
auth = ClientCredentialsOAuthProvider(
client_id=os.environ["MCP_CLIENT_ID"],
client_secret=os.environ["MCP_CLIENT_SECRET"],
)
import os
from mcp.client.auth import ClientCredentialsOAuthProvider
auth = ClientCredentialsOAuthProvider(
client_id=os.environ["MCP_CLIENT_ID"],
client_secret=os.environ["MCP_CLIENT_SECRET"],
issuer=os.environ["MCP_AUTH_ISSUER"],
)
# mcp >= 1.30.0 (1.x) または >= 2.2.0 (2.x) を使用してください。
エンジニアリング&システム堅牢化チェックリスト
- ✓HTTP MCPクライアントを棚卸しし、推移的依存関係とコンテナイメージも含めて実際の
mcpバージョンを確認する。[1] - ✓1.xクライアントは
mcp1.30.0以降、2.xクライアントは2.2.0以降へ更新し、ロックファイルと本番環境を照合する。[1], [3], [8] - ✓
ClientCredentialsOAuthProviderとPrivateKeyJWTOAuthProviderにissuer=を明示する。このオプションのない非推奨1.xRFC7523OAuthClientProviderから移行する。[1], [2] - ✓Issuerバインド導入前に保存されたOAuth登録を削除して再登録する。手動で事前登録した情報にはissuerを明示する。[1], [2]
- ✓FlawOpenの実装上の推奨事項:信頼できないMCPサーバーを認証情報が渡り得る信頼境界として扱う。ポリシーで許可されない限り、本番OAuthシークレットや署名鍵を持つクライアントを接続しない。[1]
- ✓影響を受けるクライアントが信頼できないサーバーへ接続した可能性がある場合、クライアントシークレットをローテーションし、認可サーバーでトークンを失効させる。[1]
- ✓1.xおよび2.xの検出経路、issuer不一致、PRM欠落、
403 insufficient_scope、issuerに結び付いた登録、issuer=未設定のマシン間プロバイダーを回帰テストに含めます。[2] - ✓他のクライアントを影響対象と判断する前に、このアドバイザリの範囲を確認します。SDKで構築したサーバー、stdioクライアント、独自のトークンまたはヘッダーを渡すクライアントは対象外です。[1]
参考資料
- GitHub-reviewed advisory GHSA-qx49-fqc8-xw99
- MCP Python SDK pull request #3398: Validate issuer on every discovery path
- MCP Python SDK v1.30.0 release notes
- MITRE CWE-345: Insufficient Verification of Data Authenticity
- The Hacker News: Official MCP Python SDK flaw can let malicious servers steal OAuth credentials
- Cycode disclosure: MCP Python SDK OAuth flaw
- CWE-522: Insufficiently Protected Credentials
- MCP Python SDK v2.2.0 release