FlawOpen

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

● CVE-2026-14540 · CVSS 8.0 · Alta
Investigación · FlawOpen

CVE-2026-14540: SSRF en Google MCP Toolbox

CVE-2026-14540 permitía que las solicitudes HTTP de MCP Toolbox siguieran redirecciones sin comprobar el destino de red final. Actualiza a 1.5.0 o posterior.[1], [3]

💡 Explicación en Lenguaje Sencillo (ELI5)

Una sala de correo comprueba la primera dirección de un paquete y luego sigue cualquier etiqueta de reenvío sin verificar el nuevo destino. Una redirección HTTP es esa etiqueta: sin validar la IP final, una solicitud dirigida a un sitio normal puede acabar en una red privada. La corrección comprueba el destino real al conectar y también revisa los destinos de las redirecciones.[2], [4], [7]

Conceptos Clave y Términos

Server-side request forgery (SSRF)
Se induce a un servicio a realizar una solicitud HTTP a un destino influido por el atacante. Como la solicitud parte del servidor, puede alcanzar redes a las que el solicitante no llega.[6]
Redirección HTTP
Una respuesta puede indicar al cliente HTTP que haga otra solicitud a una URL distinta. Comprobar solo la URL inicial no limita el destino de esa solicitud posterior.[4], [7]
DNS rebinding y TOCTOU
Un nombre de host puede resolverse a una dirección durante la validación y a otra cuando se abre el socket. Comprobar la IP resuelta al conectar cierra esa brecha entre comprobación y uso.[2], [7]
Generic HTTP source y tool
Componentes de MCP Toolbox que construyen solicitudes HTTP a partir de endpoints configurados y parámetros de herramientas. El aviso identifica esta ruta como afectada.[1], [2], [4]
CWE-918
Server-Side Request Forgery (SSRF): la aplicación obtiene una URL o destino sin controlar suficientemente a dónde puede dirigirse la solicitud.[6]

Mapeos de marcos

Análisis de Causa Raíz

En las versiones afectadas, la generic HTTP source creaba un Go http.Client con timeout y transporte, pero sin una política de redirección que comprobara el destino ni una restricción de IP en el socket. Go seguía redirecciones de forma predeterminada. Como las herramientas HTTP configuradas pueden incorporar parámetros a las solicitudes, un valor manipulado o una redirección podía apartar la llamada del destino previsto. Comprobar solo la URL original no basta: una redirección cambia el destino y DNS puede devolver otra IP entre la validación y la conexión. La corrección upstream añade SSRFGuard, rechaza destinos bloqueados en CheckRedirect y vuelve a comprobar la IP resuelta en la capa de conexión. Las direcciones privadas, loopback, link-local y otras no globales se bloquean por defecto; permitir rangos o redes privadas son excepciones de configuración que deben limitarse estrictamente.[1], [2], [4]

Flujo de Ataque Paso a Paso

Paso 1

Aplica la prueba de alcance de tres condiciones

Esta cadena requiere las tres condiciones: (1) una implementación afectada, de la versión 0.3.0 a la 1.4.0, usa generic HTTP source/tool; (2) un usuario puede invocar esa ruta y controlar la URL o la ruta, o provocar una redirección; y (3) el host de Toolbox puede enrutar al destino. Si falta alguna condición, esta cadena no puede alcanzar ese destino por esta ruta. Siguen aplicándose la autenticación y los controles de acceso del propio destino.[1]

Paso 2

Un argumento de herramienta influye en una solicitud saliente

Una HTTP tool configurada combina su endpoint base con valores de entrada. La descripción del CVE indica que parámetros de ruta manipulados pueden redirigir la HTTP source a otro destino. Un usuario o agente MCP invoca la herramienta; contenido no confiable solo influye en esa llamada si el flujo circundante lo permite.[1], [2]

Paso 3

La URL inicial no restringe las redirecciones

El cliente afectado no tenía un hook restrictivo CheckRedirect ni validación de la IP de destino. Una respuesta puede señalar otra URL, por lo que comprobar solo la base o la primera solicitud no limita la siguiente.[1], [2]

Paso 4

El Toolbox solicita desde su propia red

La siguiente solicitud parte del host de Toolbox y alcanza destinos permitidos por la red de ese host. Así, servicios internos u otros endpoints accesibles pueden recibir solicitudes que el usuario MCP no podría realizar directamente. El CVE no demuestra que todas las implementaciones expongan credenciales cloud ni que todas las redirecciones funcionen.[1]

Paso 5

Actualiza y verifica los límites de salida

Actualiza MCP Toolbox a 1.5.0 o posterior. La corrección valida IP literales configuradas, comprueba destinos de redirección y bloquea IP resueltas no permitidas al conectar, lo que también aborda DNS rebinding. Mantén allowPrivateNetworks desactivado salvo necesidad; limita los rangos permitidos y aplica una política de salida como capa independiente.[2], [3], [4]

Código Fuente: Vulnerable vs. Seguro

Esta comparación se centra en la ruta upstream del cliente HTTP; no sustituye el archivo completo. La corrección incorporada añade SSRFGuard: comprueba destinos de redirección y rechaza IP resueltas bloqueadas al conectar, cerrando la brecha de DNS rebinding que quedaría si solo se resolviera durante la redirección. El guard bloquea por defecto las direcciones privadas y otras no globales. allowPrivateNetworks, allowedIpRanges y customBlockedIpRanges son controles potentes; limita cada excepción de allowlist al rango estrictamente necesario. El archivo de origen es internal/sources/http/http.go.[2]

Fragmento de origen: Fragmento del cliente HTTP y la política de redirecciones

IMPLEMENTACIÓN VULNERABLE
client := http.Client{
	Timeout: duration,
	Transport: tr,
}

// Sin una política CheckRedirect, el cliente sigue redirecciones HTTP con
// la política predeterminada. El transporte tampoco restringe destinos de SSRF.
PARCHE SEGURO Y ROBUSTO
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
	},
}
// El mismo SSRFGuard también se aplica al abrir el socket,
// para impedir que una respuesta DNS cambie una dirección permitida por otra bloqueada.

Lista de Verificación de Seguridad para Ingeniería

Fuentes