Descripción general

El servidor MCP de SearXNG presenta una vulnerabilidad SSRF en la herramienta web_url_read. Esta herramienta recupera una URL proporcionada por el invocador en el lado del servidor y convierte el contenido a Markdown. Existe un mecanismo de protección (assertUrlAllowed) que bloquea direcciones privadas, de loopback y de metadatos, pero dicho mecanismo solo se activa cuando la variable de entorno MCP_HTTP_HARDEN=true, que está desactivada por defecto. En consecuencia, en la configuración predeterminada no existe ningún filtrado de direcciones internas, y un atacante que pueda influir sobre la URL puede hacer que el servidor consulte servicios internos, el endpoint de metadatos cloud, y devuelva su contenido.

La vulnerabilidad ha sido confirmada en la versión 1.1.0 con configuración por defecto: web_url_read recuperó un centinela interno local y devolvió su contenido íntegro.

Detalles técnicos

En el fichero dist/index.js (aproximadamente líneas 90-101), web_url_read invoca fetchAndConvertToMarkdown con la URL suministrada por el invocador sin validación previa.

En dist/url-reader.js (aproximadamente líneas 44-52), la función assertUrlAllowed realiza la comprobación de IP privada y loopback, pero únicamente cuando el flag de hardening está activo.

En dist/http-security.js (aproximadamente línea 11), el valor por defecto de MCP_HTTP_HARDEN es false, lo que significa que la comprobación se omite completamente en la configuración estándar.

Además, incluso cuando el guard está habilitado, la comprobación se basa en el nombre de host literal, sin resolución DNS ni revalidación tras redirecciones. La función fetch sigue redirecciones, lo que abre la puerta a ataques de DNS rebinding. El esquema file:// sí es rechazado, por lo que el vector se limita a SSRF sobre HTTP y HTTPS.

Prueba de concepto

Validado en mcp-searxng 1.1.0 sobre MCP stdio en configuración por defecto (sin definir MCP_HTTP_HARDEN):

bash
# Herramientas disponibles: searxng_web_search, web_url_read
web_url_read({ url: "http://127.0.0.1:<puerto>/internal" })
# Resultado: el servidor recuperó el centinela interno -> SSRF: CONFIRMADO

El servidor recuperó el centinela de loopback y devolvió su contenido. Con MCP_HTTP_HARDEN=true la misma petición es bloqueada con un error de política, lo que confirma que el guard existe pero se distribuye desactivado. El mismo vector alcanza http://169.254.169.254/... en entornos cloud, exponiendo metadatos de instancia.

Impacto

En la configuración predeterminada, un atacante que pueda influir sobre la URL (por ejemplo, a través de una URL generada por un LLM o dirigida mediante inyección de prompt) puede hacer que el servidor consulte servicios HTTP exclusivamente internos y el endpoint de metadatos cloud, devolviendo su contenido al contexto del modelo para su exfiltración.

Los escenarios de riesgo incluyen:

  • Acceso a servicios internos no expuestos públicamente.
  • Recuperación de credenciales e información sensible desde el endpoint de metadatos cloud (por ejemplo, http://169.254.169.254/latest/meta-data/).
  • Exfiltración de datos al contexto del LLM mediante inyección de prompt combinada con SSRF.
  • La protección que debería prevenir este comportamiento no está habilitada por defecto, lo que convierte cualquier despliegue estándar en vulnerable.

Remediación

Se recomienda aplicar las siguientes medidas:

  1. Habilitar el filtrado de direcciones internas por defecto siguiendo el principio de fallo seguro: hacer que assertUrlAllowed se ejecute de forma incondicional y requerir una desactivación explícita solo en entornos de confianza controlada.

  2. Reforzar la comprobación para que resuelva el nombre de host y rechace:

    • Direcciones de loopback.
    • Rangos link-local y de metadatos (169.254.0.0/16).
    • El rango 0.0.0.0/8.
    • Rangos privados RFC 1918.
  3. Revalidar la dirección IP en cada salto de redirección, o anclar la conexión a la IP validada inicialmente para eliminar el riesgo de DNS rebinding.