FlawOpen

flawopen.com/Teardowns/cve-2026-14540-google-mcp-toolbox-ssrf

● CVE-2026-14540 · CVSS 8.0 · 高
セキュリティ研究 · FlawOpen

CVE-2026-14540:Google MCP Toolbox の SSRF

CVE-2026-14540 により、MCP Toolbox の HTTP リクエストは最終的なネットワーク宛先を確認せずにリダイレクトを追跡できました。1.5.0 以降へ更新してください。[1], [3]

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

郵便仕分け担当が荷物の最初の宛先だけを確認し、その後は新しい宛先を確かめず転送シールに従うような状態です。HTTP リダイレクトはそのシールに当たります。最終 IP を検証しなければ、普通の Web サイト向けのリクエストがプライベートネットワークに転送されることがあります。修正では接続時に実際の宛先を確認し、リダイレクト先も検査します。[2], [4], [7]

主要な概念と専門用語

Server-side request forgery (SSRF)
攻撃者の影響を受ける宛先へ HTTP リクエストを送るようサービスを誘導する問題です。リクエストはサーバーから発生するため、呼び出し元が到達できないネットワークにも届く可能性があります。[6]
HTTP リダイレクト
レスポンスが HTTP クライアントに別 URL への次のリクエストを指示する仕組みです。最初の URL だけを検査しても、次の宛先は制限できません。[4], [7]
DNS rebinding と TOCTOU
ホスト名は検証時と socket 接続時で異なる IP に解決されることがあります。接続時に解決後の IP を確認すれば、検査と使用の間の隙間を埋められます。[2], [7]
Generic HTTP source と tool
設定された endpoint とツール引数から HTTP リクエストを組み立てる MCP Toolbox のコンポーネントです。アドバイザリはこの経路を影響対象としています。[1], [2], [4]
CWE-918
Server-Side Request Forgery (SSRF):アプリケーションが URL や宛先を取得する際、リクエストの送信先を十分に制限していない状態です。[6]

フレームワーク対応

根本原因の分析 (Root Cause)

影響を受けるバージョンでは、generic HTTP source は timeout と transport を設定した Go http.Client を作成していましたが、宛先を考慮するリダイレクトポリシーや socket 境界での IP 制限はありませんでした。Go は既定でリダイレクトを追跡します。設定された HTTP tool はパラメーターをリクエストへ組み込むことがあるため、細工された値やリダイレクトによってリクエストが本来の宛先から外れる可能性がありました。元の URL だけを検査しても不十分です。リダイレクトで宛先が変わり、検証から接続までの間に DNS が別 IP を返す場合もあります。上流修正は SSRFGuard を追加し、CheckRedirect で禁止宛先を拒否するとともに、接続層でも解決後の IP を再確認します。プライベート、loopback、link-local、その他の非グローバルアドレスは既定で拒否されます。許可範囲やプライベートネットワークの有効化は設定例外なので、対象を厳密に絞ってください。[1], [2], [4]

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

ステップ 1

3つの条件で到達可能性を判定する

この攻撃経路には次の3条件がすべて必要です。(1) 影響を受ける0.3.0〜1.4.0の環境でgeneric HTTP source/toolを使用している。(2) 呼び出し元がその経路を利用でき、URL/パスを制御するかリダイレクトを発生させられる。(3) Toolboxのホストから宛先へルーティングできる。いずれかの条件が欠ければ、この経路ではその宛先に到達できません。宛先側の認証とアクセス制御は引き続き適用されます。[1]

ステップ 2

ツール引数が送信リクエストに影響する

設定済み HTTP tool はベース endpoint と入力値を組み合わせます。CVE の説明では、細工されたパス引数が HTTP source を別の宛先へ向ける可能性があります。MCP ユーザーまたは agent が tool を呼び出します。不可信なコンテンツが呼び出しに影響するのは、周辺のワークフローがそれを許す場合だけです。[1], [2]

ステップ 3

元の URL ではリダイレクト先を制限できない

影響を受ける client には制限付き CheckRedirect hook と宛先 IP の検査がありませんでした。レスポンスが別 URL を指すため、ベース URL や最初のリクエストだけを検査しても次のリクエストを制限できません。[1], [2]

ステップ 4

Toolbox が自身のネットワークからリクエストする

次のリクエストは Toolbox ホストから送信され、そのネットワークが許可する宛先に到達できます。そのため、MCP 呼び出し元が直接送れないリクエストを内部サービスなどが受け取る可能性があります。すべての構成でクラウド資格情報が露出することや、すべてのリダイレクトが成功することを CVE は示していません。[1]

ステップ 5

更新し、送信先境界を確認する

MCP Toolbox を 1.5.0 以降へ更新します。修正は設定された IP リテラルを検証し、リダイレクト先を確認し、接続時に許可されない解決後 IP を遮断して DNS rebinding にも対処します。必要がない限り allowPrivateNetworks は無効にし、許可範囲を狭く設定し、別レイヤーでも送信ネットワークを制御してください。[2], [3], [4]

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

これは上流 HTTP クライアント経路の要点を抜粋した比較で、ファイル全体の置き換えではありません。マージ済み修正は SSRFGuard を追加し、リダイレクト先を確認するとともに接続時に禁止された解決後 IP を拒否します。これにより、リダイレクト時だけの検証では残る DNS rebinding の隙間も塞ぎます。guard はプライベートなど非グローバルアドレスを既定で遮断します。allowPrivateNetworks、allowedIpRanges、customBlockedIpRanges は強力な設定なので、allowlist の例外は必要な範囲だけにしてください。ソースファイル:internal/sources/http/http.go。[2]

ソース抜粋: HTTP クライアントとリダイレクトポリシーの抜粋

脆弱な実装
client := http.Client{
	Timeout: duration,
	Transport: tr,
}

// CheckRedirect ポリシーがない場合、クライアントはデフォルトのポリシーで
// HTTP リダイレクトに従う。トランスポートにも SSRF 宛先のガードがない。
堅牢化されたセキュアパッチ
client := &http.Client{
	Timeout: duration,
	Transport: tr,
	CheckRedirect: func(req *http.Request, via []*http.Request) error {
		if len(via) >= 10 {
			return fmt.Errorf("stopped after 10 redirects")
		}
		hostname := req.URL.Hostname()
		if ip := net.ParseIP(hostname); ip != nil {
			if guard.IsIPBlocked(ip) {
				return fmt.Errorf("redirect to blocked IP %s denied", ip)
			}
			return nil
		}
		addrs, err := resolver.LookupHost(req.Context(), hostname)
		if err != nil {
			return fmt.Errorf("failed to resolve redirect host %s: %w", hostname, err)
		}
		for _, addr := range addrs {
			if ip := net.ParseIP(addr); ip != nil && guard.IsIPBlocked(ip) {
				return fmt.Errorf("redirect host %s resolves to blocked IP %s", hostname, addr)
			}
		}
		return nil
	},
}
// 同じ SSRFGuard をソケット接続時にも適用する。
// そのため DNS 応答によって許可済みアドレスがブロック対象に変わることはない。

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

参考資料