Volver a todas las publicaciones
Publicado el · por Renaud Deraison

El agente tenía una dirección

En la DEF CON 34, Eli Woodward, de Team Cymru, mostró 48 horas de captura de un honeypot de IA: 3.993 peticiones, 327 IP de origen, 344 sondeos de credenciales, contra puertos que nadie había anunciado. Los demás ataques a un agente de código necesitan una forma de poner texto delante de él. Este necesita una ruta hasta él. Bromure Agentic Coding ejecuta el agente detrás de NAT por defecto, así que no hay ruta alguna que encontrar.

Los demás ataques a un agente de código necesitan una forma de poner texto ante sus ojos. Este necesita una ruta hasta él, y los escáneres ya tienen una.

El sábado por la mañana, en la DEF CON 34, en el Creator Stage 3, Eli Woodward, de Team Cymru, dio una charla de media hora titulada MCPwned: How Exposed AI Agents Became the Internet's New Recon Toy. Había construido un honeypot de IA: 16 personas de LLM e infraestructura de IA repartidas en 16 puertos, cada una devolviendo respuestas, cabeceras, errores y comportamiento de protocolo fieles al framework imitado, de modo que un escáner que las tocara creyera haber encontrado lo auténtico.

En una ventana de 48 horas, el honeypot recibió 3.993 peticiones de 327 direcciones IP de origen únicas, incluidos 155 sondeos de MCP y 344 sondeos de claves de API de IA.

Nadie había anunciado esos puertos, y ninguna de las 327 direcciones había elegido a Woodward como objetivo. El manual de operaciones que extrajo de la captura es del tipo aburrido e industrial: abuso del registro de modelos en LiteLLM, enumeración de recursos MCP, fuerza bruta de credenciales consciente del framework y barridos coordinados en busca de servicios de inferencia local expuestos. Los grupos que llevan una década peinando el espacio de direcciones en busca de RDP abierto y Redis sin autenticación han apuntado la misma maquinaria hacia el instrumental de desarrollo de IA, por delante de los modelos de amenazas.

Nadie tiene que enviarte nada

Repasa el último año de ataques a agentes de código y todos comparten una forma. Algo que el agente lee contiene instrucciones: un informe de error, un comentario de PR invisible, una página web que el agente descargó, un README, una línea del registro del WAF. En cada uno de esos casos, la entrega es el problema difícil del atacante. Tiene que encontrar un canal que conectaste a propósito y meter su texto por ahí.

Invierte la flecha y ese problema desaparece. Un escáner envía un SYN al puerto 11434, y algo en tu máquina responde.

Lo que encuentran los escáneres

La población que hay detrás de la captura de Woodward llega a las decenas de miles.

Censys cartografió los servicios MCP accesibles desde internet y encontró 12.520, repartidos en 8.758 direcciones IP únicas, en 56 países y 425 sistemas autónomos, a 28 de abril de 2026. Una semana después, el 6 de mayo, la cuenta ya pasaba de 21.000. Aproximadamente cuatro de cada diez aceptan peticiones de cualquiera, sin comprobación de credenciales, porque el protocolo no exigía ninguna por defecto.

Wiz fue a llamar a la puerta. En un estudio publicado el 28 de julio, encontraron MCP presente en el 80 % de los entornos de nube, con aproximadamente uno de cada seis exponiendo al menos un servidor. De los expuestos, alrededor del 70 % entregaba su catálogo completo de herramientas a un llamante sin autenticar, cerca del 42 % devolvía datos reales cuando los investigadores invocaban una herramienta, y en torno al 10 % hacía de fachada de backends sensibles. Wiz apuntó un subconjunto confirmado hacia los endpoints de metadatos de nube y recibió credenciales temporales de vuelta.

Knostic hizo el mismo ejercicio desde Shodan, tomando la huella de 1.862 servidores expuestos; cada uno de los 119 que verificaron a mano respondió a tools/list sin autenticación. Cada uno de esos servidores estaba haciendo lo único para lo que existe, para un desconocido.

La inferencia local ofrece la misma estampa con cifras más redondas. LeakIX contó 12.269 instancias de Ollama sin autenticación el 23 de febrero de 2026, cada una ofreciendo enumeración de modelos por /api/tags, cómputo gratis por /api/generate y /api/chat, robo de modelos por /api/pull y /api/push, y en cerca de mil casos la cadena de recorrido de directorios Probllama.

48 horas en 16 puertos que nadie anuncióinternet, escaneandosin lista de objetivos, sin phishing,nada que entregarsolo un SYN a un puertoalgo responde16 personas de LLM e infra de IAen 16 puertos, fieles al frameworkcabeceras, errores, protocoloy el registro se llena3.993 peticionesdesde 327 IP de origen únicasen una sola ventana de 48 horasel manual, idéntico de una IP a la siguiente155 sondeos MCP344 sondeos de claves de IAregistro de modelos LiteLLMbarridos de inferencia localenumeración de recursos, fuerza bruta de credenciales consciente del framework, y lo que respondiera la vez anteriorLo que los escáneres están encontrando, en internet21.000+ servicios MCPCensys, mayo de 2026, antes 12.520unos 4 de cada 10 sin credencial70 % entrega el catálogoWiz, julio de 2026, de forma anónima42 % devuelve datos reales12.269 Ollama abiertosLeakIX, febrero de 2026enumerar, generar, pull, push
La captura de 48 horas de Woodward, y la población real que hay detrás. El escáner no necesita lista de objetivos ni canal de entrega, porque los servicios responden por su cuenta.

Cómo acaba respondiendo tu máquina

No decidiste poner un servicio en internet. Pusiste OLLAMA_HOST=0.0.0.0 para que el portátil del sofá pudiera usar el modelo del sobremesa, y ataste un servidor MCP a todas las interfaces por la misma razón. Ejecutaste docker run -p 8080:8080 porque lo decía el README. Abriste un túnel para depurar algo en un móvil y lo dejaste abierto.

Luego te llevaste el portátil a otra parte. El wifi de un congreso, una planta de coworking, un hotel, un router doméstico donde el UPnP hizo el favor en tu nombre, o una máquina de desarrollo en la nube cuyo grupo de seguridad alguien amplió con prisas. El bind es un solo flag; la exposición pertenece a quien escribió la tabla de rutas detrás de la cual te encuentras. En ningún momento diste tu consentimiento.

Bromure Agentic Coding cierra esa brecha por defecto, sin que configures nada.

La VM no tiene dirección

Bromure ejecuta el agente de código en una VM Linux desechable sobre Apple Silicon, con cada byte de su tráfico atravesando un proxy en el anfitrión, fuera de la caja en la que corre el agente. Para esta clase de ataque, el lado de red de ese montaje es el que carga con el peso.

En Recursos → Red, el modo es NAT, y NAT es lo que obtienes sin tomar ninguna decisión. La VM comparte la conexión de red de tu Mac a través del NAT integrado de Virtualization.framework: la salida funciona, y nada de tu LAN alcanza la VM. Ata un servicio a 0.0.0.0 dentro de esa VM y lo habrás atado a una interfaz interna de la VM, detrás del NAT. No hay tabla de reenvío de puertos que rellenar mal, porque el modo no reenvía puertos en absoluto.

El SYN del escáner no llega a ningún puerto, ni filtrado ni cerrado, porque no hay ruta que lleve a uno. El honeypot de Woodward necesitó 16 procesos a la escucha para recoger algo. Un perfil de Bromure no presenta ninguno, y los 344 sondeos de credenciales no tienen dónde aterrizar.

Puente está ahí cuando lo quieras, y le da a la VM una dirección enrutable en la LAN por DHCP sobre una interfaz física que tú indicas. Es un ajuste por perfil, con un selector de interfaz explícito, para que acabes en la LAN solo en la ejecución en la que querías estar en la LAN.

Tus servidores MCP no escuchan

Los servidores del panel MCP son configuración de perfil. Bromure los traduce a JSON de Claude Code o TOML de Codex y los inyecta en el arranque. Un servidor stdio es un proceso hijo dentro de la VM que habla por tuberías, así que no tiene socket, y la enumeración por tools/list no tiene nada que alcanzar. Un servidor HTTP es una URL a la que apuntas, con un token bearer opcional, lo que te convierte a ti en quien envía la petición. El 40 % de servicios MCP que responden a desconocidos son servidores que alguien levantó y ató a mano.

La inferencia local corre en el Mac

“Barridos coordinados en busca de servicios de inferencia local expuestos” es la expresión del propio honeypot, y 12.269 Ollama abiertos es lo que encuentra. La autenticación Modelo local de Claude Code encamina la inferencia a un modelo MLX en el dispositivo, elegido en el panel Modelos locales, que corre en macOS, del lado del anfitrión del proxy. No hay puerto 11434 dentro de la VM que exponer. La pata en el dispositivo de Fusion sigue el mismo camino.

Una sonda que entrara recogería señuelos

Quien hace fuerza bruta de credenciales consciente del framework sabe dónde mirar: OPENAI_API_KEY en el entorno, ~/.aws/credentials, ~/.docker/config.json, un kubeconfig, ~/.ssh. Bromure pone todo eso en la VM y hace que todo eso sea falso. Obtienes tokens brm_… y xai-brm-…, un kubeconfig sintético con certificados de cliente desechables, una autenticación de registro en base64 falsa y material de AWS que devuelve InvalidSignatureException en cuanto algo se salta el proxy. Bromure conserva los valores reales en el anfitrión y los sustituye en el cable, para el destino al que pertenecen.

Los verbos destructivos se deciden en el anfitrión

Wiz encontró alrededor del 42 % de servidores expuestos devolviendo datos reales, y junto a eso una clase de escritura y borrado. Guardrails es un motor de políticas en el proxy del anfitrión que cubre Kubernetes, AWS, DigitalOcean, registros de contenedores, GitHub, GitLab, Bitbucket y los endpoints de bases de datos por HTTPS. Pon Bloquear lo destructivo o Solo lectura por recurso y la llamada bloqueada vuelve como un 403 seco que el agente informa como un fallo de API corriente. Bromure toma esa decisión en macOS, así que no hay nada dentro de la VM que apagar.

En el portátil de quien desarrollaOLLAMA_HOST=0.0.0.0para que el otro portátil use el modelopuerto 11434, escuchando en todoel servidor MCP está atado igualtools/list responde a quien pregunteel catálogo es el reconocimientoy el entorno es real344 sondeos en 48 h conocen las rutasdecide quien enruta hasta tiwifi de congreso, UPnP, un grupo muy amplioDentro de un perfil de Bromurela VM está en NAT, por defectola salida va; nada entra0.0.0.0 ata a una interfaz internaMCP por stdio es una tuberíaun proceso hijo, sin socket que enumerarlos servidores HTTP son URL a las que apuntasla inferencia local corre en el Macningún 11434 en la VM que escaneary el entorno guarda brm_… de todos modosvalores reales en el anfitrión, cambiados en el cable
Las mismas dos comodidades, en dos máquinas. En un portátil, un flag cada una pone un servicio en la red en la que te encuentres. En un perfil de Bromure la VM no tiene ruta de entrada, el servidor MCP es una tubería, el modelo corre en el Mac y el entorno que barrería una sonda solo contiene señuelos.

Una tarea de un desconocido sigue siendo texto

Supón que conectas un servidor MCP remoto que expuso otra persona, y que te responde con algo más que datos. Una vez que los escáneres pueden enumerar estos servicios, quien encuentre uno también puede usarlo para llegar a tu agente por la puerta principal, en forma de contenido.

Bromure puntúa ese contenido al entrar. Un modelo local de inyección de prompts lee el contenido de los archivos, las páginas web y los bloques tool_result que ingiere el agente, buscando un imperativo dirigido a quien esté leyendo. Registrar pero continuar anota cada acierto en el Registro de Seguridad. Preguntarme qué hacer pausa la petición saliente y te pone delante el fragmento marcado. Bloquear unilateralmente la detiene antes de que el modelo la vea y le entrega al agente un 451 seco. Un segundo detector, un clasificador ModernBERT afinado más un escáner determinista para cargas de ancho cero, bidireccionales y de etiquetas Unicode, cubre CLAUDE.md, AGENTS.md, GROK.md y sus variantes anidadas y globales.

Ambos modelos corren en tu Mac, descargados una vez desde bromure.io. Puntuar la salida de un servidor MCP de terceros no implica enviar esa salida a ninguna parte.

La llamada a la puerta es una línea del registro

Cada petición que hace la VM cruza el proxy del anfitrión y, en el nivel de traza Actividad, Bromure anota para cada una el host, el estado, la latencia, el informe de sustitución y cualquier aviso de fuga. Las detecciones de inyección van a parar al Registro de Seguridad con el texto marcado adjunto. Sube el nivel y Bromure conserva también los cuerpos de las peticiones de IA, cifrados con la misma clave del llavero que los secretos de tu perfil.

Un agente que ha empezado a aceptar instrucciones de fuera tiene que llegar a alguna parte para serle útil a alguien, y llegar a alguna parte es una línea que puedes leer en la máquina donde corrió la sesión.

Y cuando quieras que la máquina desaparezca, desaparece. Borrar el home limpia /home/ubuntu, es decir, dotfiles, .ssh, npm-global, .cargo y el historial del shell, y lo devuelve a su estado posterior al clonado. Restablecer a la base descarta todo cambio a nivel de sistema y vuelve a clonar el disco de trabajo desde la imagen base.

MCP tendrá mejores valores por defecto y Ollama tendrá una historia de autenticación, y los puertos del honeypot de Woodward serán otros puertos el agosto que viene. La forma se mantiene. Ejecutar bien un agente hoy significa ejecutar una pasarela y un puñado de servidores de herramientas a su lado, y cada uno de ellos es un programa que ata un socket en un portátil que viaja.

Otras entradas de aquí te piden que desconfíes de lo que lee tu agente. Esta plantea una pregunta más corta: qué responde cuando llama un desconocido, y si no preferirías que no respondiera nada.

Instala Bromure Agentic Coding y dale a tu agente una máquina que los escáneres no puedan ver.