La wordlist ya conocía tu directorio personal
F5 Labs registró 807 ataques y 32.000 eventos en un solo mes contra servidores de desarrollo Vite expuestos, mediante un truco de cadena de consulta que pasa de largo ante la propia deny-list de Vite. Los escáneres no buscan tu aplicación. Piden /home/ubuntu/.aws/credentials por ruta absoluta, y /proc/self/environ, y terraform.tfstate. En un workspace de Bromure Agentic Coding ese puerto mira a un switch privado, y el archivo que la wordlist quiere no guarda ninguna clave.
Este atacante no te envía ningún paquete ni ningún archivo comprimido. Es tu propio servidor de desarrollo el que está escuchando, y un desconocido le pide archivos por su nombre. Qué máquina responde decide lo que se lleva.
Le pides al agente que levante el frontend para poder mirarlo. Teclea
npm run dev, abre el puerto, carga la página, y tú vuelves a revisar el diff.
En algún punto de ese bucle, en un docker-compose.yml o en una bandera
--host que añadiste hace semanas para que la vista previa fuera accesible desde
el móvil, el servidor se ató a todas las interfaces en vez de al loopback. Doce
minutos después, algo que se presenta como Googlebot le pide a tu servidor de
desarrollo /@fs/../.env?raw?? y recibe un HTTP 200.
F5 Labs publicó las cifras el 11 de septiembre. A lo largo de un solo mes de datos de sensores, agosto de 2026, sus honeypots registraron 807 ataques agrupados por sesión y unos 32.000 eventos en bruto dirigidos a servidores de desarrollo Vite expuestos, frente a una línea base de 1.732 eventos en los tres meses anteriores. Eso es dieciocho veces el tráfico, de un mes a otro, por un solo fallo. BleepingComputer lo cubrió el 14 de septiembre.
Una cadena de consulta que esquiva la deny-list
Vite sirve archivos del sistema de archivos del host mediante una ruta interna
llamada /@fs/, que es como el servidor de desarrollo le entrega a tu editor un
módulo que vive fuera de la raíz del proyecto. Como esa ruta puede llegar a
cualquier parte, Vite incluye una deny-list, server.fs.deny, para bloquear los
objetivos obvios: archivos .env, certificados, fuentes privadas.
CVE-2026-39364, publicada el 7 de abril, permite a un atacante saltarse esa deny-list adornando la petición con una cadena de consulta. F5 describe el mecanismo:
El servidor procesa la petición, normaliza la ruta y elimina o malinterpreta la cadena de consulta durante la validación de acceso, sin llegar a disparar la comprobación server.fs.deny.
El servidor no aplica el filtrado por deny-list y sirve el archivo objetivo con una respuesta HTTP 200.
El fallo afecta a Vite 7.1.0 hasta 7.3.2, y a las 8.x anteriores a 8.0.5. F5
capturó estas formas de petición en la práctica, cada una lo bastante corta para
leerse en una línea: GET /@fs/.env?raw??, GET /@fs/../.env?raw??,
GET /@fs/..%252f..%252f..%252f..%252froot/.env?raw?? y
GET /@fs/..%252f..%252f..%252f..%252fproc/self/environ?raw??. Otras variantes
del mismo utillaje usan ?import&raw, ?import&url&inline, ?inline&import y
?raw?import.
Esos trucos de parámetros llevan sus propios números de CVE: CVE-2025-30208,
CVE-2025-31125 y CVE-2024-45811, tres elusiones más antiguas de @fs todavía
cargadas en los mismos escáneres. Quien opera la flota de escaneo no se reequipó
para un fallo nuevo. Añadió una línea más a un archivo que ya tenía.
La wordlist es un mapa de la máquina de un desarrollador
Lee lo que piden los escáneres y fíjate en qué poco de ello tiene que ver con tu aplicación.
Piden .env, .env.local, .env.production, .env.development y
.env.staging. Piden terraform.tfstate, terraform.tfvars,
.terraform/terraform.tfstate, serverless.yml y
.serverless/serverless-state.json. Piden .azure/credentials y
.azure/accessTokens.json. Piden /etc/passwd, /proc/1/environ,
/proc/self/cwd/.env y /proc/self/environ. Esa última ruta guarda el bloque de
entorno del propio proceso del servidor de desarrollo, donde acaba una API_KEY
que exportó tu shell.
Y luego piden credenciales de AWS recorriendo la lista de directorios personales bajo los que podría estar ejecutándose el proceso de un desarrollador:
/root/.aws/credentials, /home/ec2-user/.aws/credentials,
/home/ubuntu/.aws/credentials, /home/node/.aws/credentials,
/home/www-data/.aws/credentials, /home/admin/.aws/credentials,
/home/debian/.aws/credentials, /var/www/.aws/credentials,
/usr/src/app/.aws/credentials, /app/.aws/credentials. Luego .aws/config,
.aws/credentials.backup, .aws/credentials.bak, .aws/sso/cache/,
rootkey.csv, aws-exports.js y amplifyconfiguration.json.
Esas rutas inventarían la máquina de un desarrollador, enumerada por nombre de usuario, y Vite es solo la puerta. El fallo es incidental; tres fallos más antiguos de la misma ruta viajan en las mismas peticiones. Los operadores apuestan a que un proceso que escucha en una dirección enrutable corre bajo un usuario en cuyo directorio personal hay claves de verdad.
El tráfico va vestido para sobrevivir a una mirada distraída a los registros. F5
anotó cabeceras User-Agent falsificadas que rotan entre Googlebot/2.1,
ClaudeBot/1.0, GPTBot/1.4, PerplexityBot/1.0, OAI-SearchBot/1.3 y
Amazonbot/0.1, además de valores falsos de X-Forwarded-For y X-Real-IP para
sortear las allow-lists de IP. Las fuentes están en los rangos 34.x y 35.x de
Google Cloud, repartidas por varias regiones, encabezadas por Estados Unidos con
17.297 eventos, luego Bélgica con 4.407 y los Países Bajos con 4.011. Este mes,
una línea de tu registro de acceso que dice ser un crawler de IA es una prueba
endeble de que la haya enviado un crawler.
Dos de las recomendaciones de F5 son preguntas de arquitectura
F5 cierra con cinco consejos. Tres son corrientes y correctos: actualizar a 7.3.2
u 8.0.5, filtrar /@fs/ en el borde, verificar los crawlers por DNS inverso en
lugar de fiarse de la cabecera. Los otros dos describen una postura que hay que
sostener más que una tarea que se termina.
Asegúrate de que los servidores de desarrollo no se aten a interfaces externas. Audita las configuraciones de Docker compose, las reglas de ingress de Kubernetes y los grupos de seguridad en la nube.
Rota los secretos expuestos: si un servidor de desarrollo Vite sin parchear estuvo accesible desde redes externas durante agosto de 2026, trata las variables .env locales, las credenciales de AWS, los tokens de acceso de Azure y los archivos de estado de Terraform como potencialmente comprometidos.
La primera te pide mantener una promesa sobre cada puerto, en cada archivo
compose, a lo largo de cada rama, mientras viva el proyecto, en un momento en que
quien teclea npm run dev suele ser un agente y no tú. La segunda pregunta qué
haces después, y responde: rota lo que la máquina pudo ver.
Las dos se vuelven más fáciles si el puerto se abre en otro sitio, y si los archivos que la wordlist nombra no guardan nada que merezca rotarse.
Dónde coloca el puerto un workspace de Bromure
Bromure Agentic Coding ejecuta agentes de código dentro de una VM Linux virtualizada por hardware en tu Mac, con los controles de seguridad en el lado del host de esa frontera. Dos de ellos responden a esta campaña.
El servidor de desarrollo se ata dentro de un switch privado. En el modo NAT
por defecto, cada VM de workspace se engancha a un único switch L2 por software a
escala de proceso, multiplexado sobre una sola interfaz vmnet, en una subred
privada. Esa subred es 192.168.64.0/24 salvo que tu propia LAN ya la use,
Bromure ejecuta en ella su propio servidor DHCP, y cada workspace conserva una MAC
determinista y una concesión estable. El manual enuncia la consecuencia: tu Mac
puede llegar a las VM, tu LAN física no las ve, y las conexiones entrantes desde
cualquier otro sitio son imposibles a menos que publiques tú mismo un servicio. Un
agente que se ata a 0.0.0.0 dentro de esa VM se ha atado a todas las interfaces
que posee, y cada una de ellas mira a un switch que empieza y acaba en tu portátil.
No tienes ningún grupo de seguridad que auditar, porque no tienes ninguna ruta de
entrada que asegurar.
Aun así puedes ver qué está escuchando, y es una lista, no una auditoría. El
panel del workspace lleva una tarjeta Listening Ports que muestra cada socket
alcanzable desde fuera en el invitado, como un endpoint <IP-VM>:<puerto> con
copia en un clic. Eso convierte la recomendación n.º 2 de F5 en una tarjeta que
miras de reojo, refrescada desde el invitado cada segundo y medio, en vez de en
una auditoría que programas. Cuando sí quieres que el mundo vea una vista previa,
un servicio probablemente HTTP recibe un botón de globo que publica ese servicio
concreto mediante un quick tunnel de Cloudflare, tras un diálogo de
consentimiento de una sola vez. Expones un servicio haciendo clic en él, servicio
a servicio, en el host, en lugar de dejando viva una bandera en un archivo
compose.
Conservas el motivo por el que recurriste a --host en primer lugar. El sidecar
Chromium desechable comparte el mismo segmento L2 que la VM del workspace, así
que el navegador integrado carga el servidor de desarrollo del agente en la
dirección de la VM. No en localhost, puesto que el navegador corre en una
máquina aparte.
Si otras máquinas sí necesitan llegar a la VM, el modo Bridged la une a tu LAN física. Eso lo fijas por workspace en el editor de workspace, en el host, y cae de vuelta a NAT si la interfaz no está disponible al arrancar. Esa elección la haces en un panel, no en un archivo de configuración que el agente pueda editar.
Y si publicas el servicio a propósito
A veces sí quieres la vista previa en internet, para un cliente o un compañero. Así que pulsa el globo, abre el túnel y deja que los escáneres la encuentren. Baja por la wordlist, entrada a entrada, y mira qué vuelve.
.env y /proc/self/environ devuelven el entorno del workspace, y cada
credencial que hay en él es falsa. Bromure deriva cada sustituto del valor real
más una sal de 32 bytes propia de la instalación, mediante HKDF-SHA256,
conservando la forma que espera un validador del lado del cliente: una clave de
Anthropic se lee sk-ant-api03-brm-…, un token de GitHub es ghp_ más 36
caracteres, el de GitLab es glpat- más 20. Bromure escribe esos sustitutos en
las variables de entorno y en ~/.git-credentials, ~/.docker/config.json,
~/.kube/config y las configuraciones MCP. Los valores reales nunca entran en la
VM; se quedan cifrados en el Mac, y un proxy del lado del host cambia cada uno en
el cable en el último momento, acotado al host de destino al que pertenece.
/home/ubuntu/.aws/credentials es la entrada más afilada, porque /home/ubuntu
es el directorio personal de una VM de workspace de Bromure. El escáner acierta
con qué usuario ejecuta el servidor. Aun así el archivo no está. La configuración
de AWS de Bromure no escribe ningún archivo de credenciales; escribe
~/.aws/config con una línea credential_process que apunta a un ayudante que
entrega, por un socket del host, tu ID de clave de acceso real emparejado con una
clave secreta falsa de cuarenta caracteres, y omite el token de sesión. Los
SDK de AWS, la CLI aws, terraform y boto3 lo toman todos por su cuenta. Un
escáner que lee el archivo de configuración obtiene la ruta de un ayudante al que
no puede llamar.
Llévate la clave secreta falsa de todos modos y te habrás llevado algo inerte. El
invitado firma sus peticiones con esa falsificación, y el host retira la firma y
vuelve a firmar con la clave real al salir. Una petición que llegue a AWS por
cualquier otra vía falla con InvalidSignatureException. La última recomendación
de F5 es tratar cada secreto local como comprometido y rotarlo. La línea
equivalente en la propia documentación de Bromure dice lo contrario: como solo se
filtró la falsificación, la credencial real nunca necesita rotación.
Una entrada de la wordlist nombra un archivo que vale dinero de verdad:
terraform.tfstate. Los archivos de estado viven donde vive el repositorio, así
que tu lista de carpetas compartidas decide su exposición. Las carpetas del host
se enganchan a un workspace como montajes virtiofs en /home/ubuntu/<basename>,
con un tope de ocho por workspace, y son la única parte del sistema de archivos de
tu Mac a la que la VM llega. Comparte el repositorio en el que trabaja el agente y
nada más, y el traversal encuentra un directorio en lugar de un disco.
La mayoría de las historias de seguridad para desarrolladores de este año describen algo que llega: un paquete, un archivo comprimido, un archivo de documentación. Aquí no llega nada. En su lugar, 32.000 peticiones al mes le piden a un proceso que tú arrancaste que le lea archivos en voz alta a un desconocido, y el desenlace depende de qué máquina ejecuta ese proceso y de qué hay en su directorio personal.
Pon el servidor de desarrollo del agente en un switch donde solo esté tu Mac, y llena su directorio personal de sustitutos. Instala Bromure Agentic Coding, y luego deja que los escáneres pregunten.