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,原本发往普通网站的请求可能被转入内网。修复会在连接时检查实际目标,也会检查重定向目标。[2], [4], [7]

核心概念与专有名词

Server-side request forgery (SSRF)
攻击者诱使服务向受其影响的目标发送 HTTP 请求。请求从服务器发出,因此可到达请求发起方无法访问的网络。[6]
HTTP 重定向
响应可以要求 HTTP 客户端向另一个 URL 发送后续请求。只检查初始 URL 并不能限制后续请求的目标。[4], [7]
DNS rebinding 与 TOCTOU
主机名在验证时可能解析到一个地址,在打开 socket 时却解析到另一个地址。连接时再次检查解析出的 IP,可以弥补检查与使用之间的时间差。[2], [7]
Generic HTTP source 与 tool
MCP Toolbox 的组件根据配置的 endpoint 和工具参数构造 HTTP 请求。安全公告指出这些组件路径受影响。[1], [2], [4]
CWE-918
Server-Side Request Forgery (SSRF):应用获取 URL 或访问目标时,没有充分限制请求可以前往的位置。[6]

框架映射

根本原因剖析 (Root Cause)

受影响版本中的 generic HTTP source 创建 Go http.Client 时设置了 timeout 和 transport,但没有按目标限制重定向,也没有在 socket 边界检查 IP。Go 默认会跟随重定向。配置的 HTTP 工具可能把参数放入请求,因此经过构造的值或重定向能够使请求偏离预期目标。只检查原始 URL 并不够:重定向会改变目标,而且 DNS 可能在验证与连接之间返回不同 IP。上游修复增加 SSRFGuard,在 CheckRedirect 中拒绝被阻止的目标,并在连接层再次检查解析出的 IP。私有、loopback、link-local 及其他非全局地址默认被阻止;放行地址范围或私有网络属于配置例外,必须严格收窄。[1], [2], [4]

攻击执行流程分解

步骤 1

用三个条件判断实际可达性

这条攻击链需要同时满足三项条件:(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 是工具调用者;不可信内容只有在周边工作流允许时才能影响该调用。[1], [2]

步骤 3

初始 URL 无法约束重定向

受影响的客户端缺少限制性 CheckRedirect hook,也不检查目标 IP。响应可以指向另一个 URL,因此只检查基础 URL 或第一个请求无法限制后续请求。[1], [2]

步骤 4

Toolbox 从自身网络发出请求

后续请求由 Toolbox 主机发出,可访问该主机网络允许的目标。因此,内部服务或其他可达 endpoint 可能收到 MCP 调用者无法直接发出的请求。该 CVE 并未证明每种部署都会泄露云凭据,也未证明每次重定向都会成功。[1]

步骤 5

升级并验证出站边界

将 MCP Toolbox 升级到 1.5.0 或更高版本。修复会验证配置中的字面 IP、检查重定向目标,并在连接时阻止不允许的解析 IP,也可应对 DNS rebinding。除非确有需要,否则保持 allowPrivateNetworks 关闭;严格限制显式放行范围,并另行实施出站网络策略。[2], [3], [4]

源代码对比:漏洞与安全实现

这是对上游 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 也会在建立 socket 连接时执行,
// 因此 DNS 响应无法把允许的地址替换成被阻止的地址。

工程与系统安全加固清单

参考来源