En esta página
En julio de 2026, un investigador de seguridad apuntó un escáner hecho a medida a todos los MCP servers que pudo encontrar en la internet pública. Confirmó 640 servidores en producción, auditó dinámicamente 414 de ellos y encontró 68 vulnerabilidades reportables: inyección SQL, inyección en plantillas de prompt, path traversal y SSRF dirigido directamente a los servicios de metadatos de la nube.
La cifra que debería detenerte: el 91,8% de los servidores auditados no tenía ninguna autenticación OAuth.
Si desarrollas o ejecutas un MCP server de web scraping, este es tu problema más que el de nadie. El trabajo entero de una herramienta de scraping consiste en recibir una URL y descargarla. Cuando esa URL la elige un modelo de lenguaje, y ese modelo puede verse influido por el contenido de las páginas que lee, has construido una máquina de server-side request forgery y le has entregado el volante a un atacante.
Tabla de contenidos
- El estado de la seguridad de los MCP servers en 2026
- Por qué los servidores de scraping son el peor caso
- Anatomía de un CVE real
- La escalera de bypass: seis formas en que falla una comprobación de URL
- Una lista de defensas que aguanta
- Cómo lo implementa CrawlForge
- Si eres usuario y no desarrollador
El estado de la seguridad de los MCP servers en 2026
El estudio es Exposed by Design: A Dynamic Security Assessment of Internet-Facing MCP Servers at Scale (Nicolás Padilla, arXiv:2608.00150, presentado el 31 de julio de 2026). Es la primera evaluación dinámica del comportamiento de MCP servers reales, en lugar de una lectura estática del código fuente.
El método fue descubrimiento pasivo a través de once fuentes de datos —registros de transparencia de certificados, GitHub, npm, PyPI, HuggingFace, Smithery, Censys, FOFA, Shodan y otras— seguido de pruebas activas con Corvus, un framework de 34 módulos de test que cubre 10 clases de vulnerabilidad específicas de MCP.
Lo que encontró a lo largo de cuatro rondas de medición:
| Hallazgo | Cifra |
|---|---|
| Instancias de MCP server detectables en la internet pública | Más de 21.000 |
| Servidores en producción confirmados | 640 |
| Servidores auditados dinámicamente | 414 |
| Vulnerabilidades reportables encontradas | 68 |
| Servidores auditados sin autenticación OAuth | 91,8% |
| Instancias de herramienta que exponen ejecución de shell sin control de acceso | 687 |
| Servidores confirmados que desaparecieron en tres días | 41,6% |
Esa última fila es la que la gente pasa por alto, y probablemente sea la más reveladora. Cuatro de cada diez servidores desaparecieron entre rondas de medición consecutivas: la firma de software que se despliega directamente a internet sin revisión de seguridad y luego se retira.
Por qué los servidores de scraping son el peor caso
La mayoría de los consejos sobre SSRF asumen una aplicación web en la que el atacante tiene que encontrar algún parámetro oscuro que se descargue del lado del servidor. Un MCP server de scraping invierte eso por completo: descargar una URL suministrada por el atacante es la función anunciada.
Hay tres propiedades que se acumulan de mala manera:
La URL la controla el modelo. Tu esquema de herramienta dice url: string. El modelo lo rellena. Nada en el protocolo distingue una URL que escribió la persona usuaria de otra que se inventó el modelo.
El modelo lee texto no confiable. Esta es la parte que convierte una propiedad de diseño en un exploit. Tu agente descarga una página; esa página contiene texto que instruye al modelo a descargar http://169.254.169.254/latest/meta-data/iam/security-credentials/; el modelo obedece. Eso es inyección de prompt convertida directamente en SSRF, y la petición se origina dentro de tu red con las credenciales que lleve tu instancia.
La salida vuelve directa al contexto del modelo. Un SSRF clásico es ciego: a menudo no puedes ver la respuesta. Aquí, el cuerpo de la respuesta se devuelve al modelo como salida de herramienta, y de ahí pasa a la conversación, a los logs y potencialmente a la siguiente llamada de herramienta. La exfiltración viene de serie.
Los endpoints de metadatos de la nube son el objetivo evidente porque no requieren autenticación por diseño y viven en una dirección fija y bien conocida en todos los grandes proveedores. Pero la misma primitiva alcanza paneles de administración internos, Redis en localhost, servidores de la API de Kubernetes y cualquier otra cosa que confiara en el perímetro de red.
Anatomía de un CVE real
CVE-2026-65056 (publicado el 21 de julio de 2026, CWE-918, puntuación base CVSS 4.0 de 8,3 HIGH) describe esto de principio a fin en un paquete real. El software afectado es mcp-webresearch en la versión 0.1.7 e inferiores.
Según el registro del NVD, el fallo consiste en que la herramienta visit_page solo valida el protocolo de la URL: comprueba que hayas pasado http: o https: y nunca filtra rangos de IP privados o reservados. El aviso detalla después la cadena completa: un atacante dirige mediante inyección de prompt el argumento de URL controlado por el LLM, el navegador Playwright del servidor navega a un endpoint interno como un servicio de metadatos de instancia en la nube, y el contenido sensible de esa página interna —credenciales incluidas— se devuelve al contexto del modelo.
Eso no es una ruta de ataque teórica. Es la descripción del CVE.
Tampoco es un caso aislado. CVE-2026-26118 es un server-side request forgery en el propio Azure MCP Server de Microsoft, valorado en CVSS 3.1 8,8 HIGH, también CWE-918, corregido en 1.0.2 y 2.0.0-beta.17. Si Microsoft publicó un SSRF en un MCP server oficial, las probabilidades de que un servidor de scraping hecho en un fin de semana lo haya hecho bien no son buenas.
La escalera de bypass: seis formas en que falla una comprobación de URL
Aquí viene la parte incómoda. La mayoría de quienes sí añaden protección SSRF añaden el primer o segundo peldaño de esta escalera y se detienen. Cada peldaño de abajo es un bypass real del peldaño anterior.
1. Validar solo el protocolo. Comprobar http:/https: y nada más. Esto es exactamente CVE-2026-65056. Detiene file:// y gopher://, y nada de lo que importa aquí.
2. Listas negras de cadenas de host. Bloquear las cadenas literales localhost y 127.0.0.1. Se esquiva trivialmente, porque una dirección IP se escribe de muchas formas.
3. Codificaciones alternativas de literales IP. 127.0.0.1 también es 2130706433 en decimal y 0x7f000001 en hexadecimal. El analizador de URLs de WHATWG —el que lleva integrado cualquier runtime moderno— normaliza todas ellas a la misma dirección después de que tu comprobación de cadenas ya haya pasado. Peor aún: en Node.js un literal IP nunca pasa por la resolución DNS, así que las protecciones enganchadas a la llamada lookup no ven absolutamente nada.
4. IPv6 con IPv4 mapeada. ::ffff:127.0.0.1 y ::ffff:169.254.169.254 incrustan una dirección IPv4 dentro de la notación IPv6. Una comprobación de rangos que solo entiende IPv4 en cuatro octetos las deja pasar sin más. Esto además abre una variante controlada por DNS: el atacante publica un registro AAAA que apunta a una dirección interna mapeada.
5. DNS rebinding (TOCTOU). Resuelves el nombre de host, confirmas que es una dirección pública, la apruebas... y entonces el cliente HTTP la resuelve otra vez cuando de verdad se conecta. Con un TTL corto, el atacante devuelve una IP pública en la primera consulta y una interna en la segunda. La única solución duradera es comprobar y luego fijar la conexión a la IP validada, de modo que la dirección que aprobaste sea la dirección a la que te conectas.
6. Saltos de redirección. Validas la URL que te dieron. El servidor devuelve 302 Location: http://169.254.169.254/. A menos que cada salto se revalide —y a menos que un primer salto permitido no deje sin protección silenciosamente el resto de la cadena—, simplemente has movido la vulnerabilidad un paso más abajo.
Hay un séptimo caso específico de la automatización de navegador: si tu herramienta maneja Playwright o Puppeteer, el navegador ejecuta su propia navegación. Proteger tu envoltorio de fetch no sirve de nada. Necesitas una comprobación previa a la navegación y una relectura posterior de la URL real, porque las redirecciones del lado del cliente y los meta-refresh ocurren dentro de la página.
Una lista de defensas que aguanta
[ ] Block by resolved IP range, never by hostname string
[ ] Run the range check on IP-literal hosts too — they skip DNS entirely
[ ] Normalize IPv4-mapped IPv6 before any range comparison
[ ] Pin the connection to the validated IP (defeats DNS rebinding)
[ ] Re-validate every redirect hop, not just the first URL
[ ] Scope allowlists per-hop, so one trusted host does not unguard the chain
[ ] Guard browser navigation separately, with a post-navigation URL re-check
[ ] Block 169.254.0.0/16 (metadata), loopback, and 0.0.0.0 by default
[ ] Offer strict mode: full RFC1918 and IPv6 ULA private ranges
[ ] Put a deadline and a size cap on every response body read
[ ] Mask secrets before any telemetry or log write
[ ] Require authentication — 91.8% of audited servers do not
Los rangos que conviene bloquear por defecto son loopback (127.0.0.0/8, ::1), link-local incluidos los metadatos de la nube (169.254.0.0/16) y la dirección no especificada 0.0.0.0. El bloqueo completo de rangos privados (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fc00::/7) debería estar disponible como modo estricto: hay muchos despliegues legítimos que sí necesitan hacer scraping de un host interno de staging, y una protección que nadie puede configurar es una protección que la gente desactiva por completo.
Cómo lo implementa CrawlForge
No escribimos esto desde la barrera. La versión v5.0.0 de CrawlForge fue un programa de remediación de siete fases, y su primera fase trató exactamente esta clase de fallo, incluido uno que habíamos publicado nosotros mismos.
Nuestra protección SSRF resolvía los nombres de host y comprobaba las direcciones resultantes, pero no aplicaba esa misma comprobación cuando el host ya era un literal IP. Ese es el tercer peldaño de la escalera de arriba, y estaba activo en nuestro código. La fase 1 lo arregló ejecutando la comprobación de rangos sobre los nombres de host que son literales IP en la verificación previa y, por separado, envolviendo el buildConnector del dispatcher de undici con una comprobación por conexión, de modo que un salto de redirección directo a una dirección interna se detecta en el momento de conectar aunque Node nunca lo haya enrutado por DNS.
El resto de la escalera queda cubierto así:
- La IPv6 con IPv4 mapeada se normaliza a la IPv4 incrustada antes de comprobar los rangos, tanto en modo por defecto como en estricto.
- Las conexiones se fijan a la IP validada, cerrando la ventana del DNS rebinding.
- Las listas de permitidos se evalúan por salto: un primer salto aprobado ya no deja sin protección la cadena de redirecciones.
- La navegación del navegador se protege por separado:
scrape_with_actionsvalida antes depage.gotoy releepage.url()después, cerrando la página si la navegación aterrizó en un rango bloqueado. - Todos los subsistemas que descargan están conectados: las descargas de páginas y metadatos, las descargas de PDF, la entrega de webhooks y las notificaciones de investigación pasan por la protección en lugar de usar
fetchdirecto. - Los secretos se enmascaran antes de que la telemetría de uso salga del proceso.
Por defecto se bloquean loopback, link-local/metadatos y 0.0.0.0. SSRF_STRICT=true añade la aplicación completa de RFC1918 y ULA, ALLOWED_DOMAINS permite hosts internos de confianza, y SSRF_PROTECTION_ENABLED=false existe como kill switch para quien de verdad lo necesite.
SSRF_STRICT=true # full private-range enforcement
ALLOWED_DOMAINS=staging.acme.dev # trusted internal targetsSi eres usuario y no desarrollador
No necesitas leer el código fuente de nadie para reducir tu exposición de forma significativa.
Audita lo que tienes conectado. Cada MCP server de la configuración de tu cliente se ejecuta con el acceso de red de tu máquina y tus credenciales. En una VM en la nube o en una VPN corporativa, ese alcance es mucho mayor que en un portátil.
Prefiere servidores que publiquen su postura de seguridad. Un changelog que nombra las clases de CVE que ha cerrado te dice más que una lista de funciones. El silencio no es prueba de seguridad; visto lo visto en el estudio, el silencio se parece más a la prueba de lo contrario.
Reduce la superficie de ataque que expones al modelo. Si un servidor admite filtrado de herramientas, úsalo. CrawlForge acepta CRAWLFORGE_TOOLS o CRAWLFORGE_TOOL_GROUPS para exponer solo las herramientas que de verdad necesitas, lo que reduce la saturación de contexto y encoge aquello a lo que puede recurrir un modelo con inyección de prompt.
Trata el contenido descargado como entrada hostil. Es el cambio de mentalidad más importante de todo esto. Cualquier página que lea tu agente puede contener instrucciones dirigidas a tu modelo. Todos los ataques anteriores dependen de eso, y ninguna cantidad de refuerzo de red arregla un flujo de trabajo que canaliza texto descargado directamente a una llamada de herramienta sin revisión.
¿Desarrollas agentes que leen la web en vivo? Empieza gratis con 1.000 credits — protección SSRF activada por defecto, sin configuración. Consulta la documentación completa, la referencia de scrape_with_actions o cómo gestionamos la detección anti-bot en modo stealth.
Pruébalo tú mismo — sin necesidad de registrarte
Ejecuta cualquiera de las 27 herramientas de scraping y extracción de CrawlForge en el playground y luego empieza gratis con 1,000 credits.
1,000 credits gratis • Por única vez • No se requiere tarjeta de crédito
Etiquetas
Sobre el autor
Mantente al día con los últimos artículos
Recibe tutoriales, novedades del producto y consejos de web scraping en tu bandeja de entrada.
Sin spam. Cancela tu suscripción cuando quieras.