El portátil era la puerta de entrada
Binance dice que el mayor robo de criptomonedas registrado, unos 6.300 millones de dólares, pudo empezar en el portátil comprometido de un ingeniero de DevOps. El grupo al que se culpa tiene una costumbre: conseguir que un desarrollador ejecute un proyecto y luego usar todo lo que alcanza su portátil. Los agentes de código ahora ejecutan proyectos todo el día. En Bromure Agentic Coding, ese código corre en una VM con credenciales sustitutas, y cada uso de una clave de producción pasa por el Mac.
Al atacante no le hacían falta las claves privadas de Binance. Le hacía falta el portátil de un ingeniero y los sistemas a los que llegaba. La máquina de un desarrollador es un camino hacia producción, y los agentes de código ejecutan ahora cualquier código que aterrice en ella.
El 30 de octubre, Binance reveló un “incidente de seguridad” que afecta a unos 6.300 millones de dólares en activos. The Hacker News informa de que Chainalysis cifró el robo en 5.912 millones de dólares en el momento en que ocurrió, casi cuatro veces el mayor robo de criptomonedas registrado hasta entonces. Se han congelado on-chain casi 3.000 millones de dólares, en su mayoría stablecoins congeladas por Tether y Circle. Binance dice que cubrirá todas las pérdidas.
El relato de Binance sobre cómo empezó todo ocupa una sola frase. “La investigación inicial sugiere que el incidente de seguridad podría implicar el portátil comprometido de un ingeniero de DevOps”, lo que permitió a un atacante llegar a un contenedor de servicio y enviar retiradas no autorizadas. Binance dice que no encontró indicios de que se filtrara ninguna clave privada de monedero. No ha dicho cómo se comprometió el portátil.
Cincuenta firmas y tres minutos
El registro on-chain muestra lo que valía ese acceso. A las 20:20 UTC, el atacante envió una transacción con 50 autorizaciones, cada una firmada por el hot wallet de Binance, una para cada uno de 50 números de transacción consecutivos, para que una de ellas coincidiera con el siguiente del monedero. Cada una apuntaba a un contrato de barrido que solo obedece al atacante. Una coincidió. Unos tres minutos y 24 segundos después, el hot wallet envió todo su saldo al atacante: 167.464 ETH y 63 tokens, entre ellos 1.615 millones de USDT.
El consejero delegado de Blockaid, Ido Ben-Natan, dijo a Cointelegraph que las primeras pruebas apuntan a un “uso indebido de claves”: se hizo que el sistema de firma firmara las transacciones del atacante, y no hubo que robar ninguna clave. Las claves se quedaron donde estaban. Alguien con el acceso del ingeniero le pidió al sistema que las usara.
TRM Labs atribuye el ataque “con alta confianza” a TraderTraitor, el grupo norcoreano al que el FBI culpó del robo de 1.500 millones de dólares a Bybit en febrero de 2025. Chainalysis también apunta a Corea del Norte. Binance no ha señalado a nadie.
Cómo llega este grupo a los portátiles
La intrusión mejor documentada de TraderTraitor muestra el método. En el caso de Bybit, el informe preliminar de la propia Safe y las conclusiones de Mandiant la describen por orden:
- El 4 de febrero de 2025, un desarrollador de Safe ejecutó en su Mac
un proyecto de Docker llamado
MC-Based-Stock-Invest-Simulator-main. Mandiant cree que lo convencieron para hacerlo. - El proyecto se conectó a
getstockprice[.]com, un dominio registrado dos días antes, y la estación de trabajo macOS del desarrollador quedó comprometida. - Los atacantes se llevaron los tokens de sesión de AWS del desarrollador, lo que les permitió usar su acceso a AWS sin pasar por la autenticación multifactor.
- Con ese acceso modificaron la interfaz de Safe que usaban los firmantes de Bybit, y los firmantes aprobaron una transacción que vació un cold wallet.
Mandiant señaló que el grupo había usado proyectos de Docker parecidos, con
temática bursátil, en robos anteriores. El método no cambia: darle un proyecto
a un desarrollador, dejar que se ejecute como él y llevarse lo que su máquina
alcanza. Un portátil de DevOps alcanza mucho. Suele tener ~/.aws con tokens
de sesión válidos, un ~/.kube/config para los clústeres de producción,
claves SSH para el bastión y una sesión de gh, todo legible por cualquier
proceso que el ingeniero lance.
Ahora el proyecto lo ejecuta el agente
El señuelo antes necesitaba a un desarrollador al que se pudiera convencer de
ejecutar algo. Ese paso es cada vez más fácil de saltarse. El mismo día en que
Binance reveló la brecha,
BleepingComputer
informó del análisis de Air Security sobre un repositorio de GitHub llamado
SolanaUpdateTools/solana-starter-kit. Tiene 286 estrellas y, según Air,
aparece el primero cuando los agentes de código con IA buscan un starter kit
de Solana. El README es el único archivo que contiene. Promete una plantilla
de aplicación completa y da un único paso de instalación: pegar un comando que
monta a partir de fragmentos una URL en developer-update[.]app, descarga un
script y lo ejecuta en memoria.
El payload que recuperó Air instala NetSupport Manager, una herramienta legítima de acceso remoto, configurada para conectarse con el atacante en cada inicio de sesión. Después muestra un error falso: las funciones para desarrolladores están “pausadas temporalmente por la carga”, vuelva a intentarlo en 72 horas. Un agente que siguiera el README ejecutaría el comando e informaría de un servidor saturado. El desarrollador no vería nada que mereciera una segunda mirada.
Pon ese agente en el portátil de un ingeniero de DevOps, con el kubeconfig y la sesión de AWS del ingeniero en el mismo directorio personal, y el starter kit se convierte en el proyecto de Docker del caso Bybit, sin la ingeniería social.
El mismo proyecto en Bromure Agentic Coding
Bromure Agentic Coding ejecuta Claude Code, Codex, Grok, Kimi y omp en VM de Ubuntu en tu Mac. Cada máquina es una VM propia, y todo lo que toca el agente vive dentro de ella: repositorios clonados, cachés de paquetes, contenedores de Docker y cada comando que sugiere un README. Tu Mac guarda las credenciales reales, el proxy por el que pasa el tráfico de la VM y el registro de lo que ocurrió.
El proyecto se ejecuta en la VM, no como tú
Ejecuta el proyecto de Docker del simulador bursátil en una máquina de
Bromure, o deja que el agente pegue el comando del starter kit. El contenedor
arranca en la VM, y el payload también. Obtiene una shell en un invitado
Ubuntu, como el usuario de la máquina. No obtiene tu cuenta de macOS ni tu
llavero. Los ~/.aws, ~/.kube y ~/.ssh de tu Mac tampoco están ahí:
Bromure lee esos archivos en el host cuando los importas y nunca los
monta en una VM.
Las claves que encuentra son sustitutas
Después, el payload busca credenciales, y la VM tiene muchas que parecen buenas. Ninguna funciona en otro sitio.
- AWS.
~/.aws/configapunta a un ayudante que entrega el ID real de la clave de acceso con una clave secreta falsa, y ningún token de sesión. La VM firma cada petición con el secreto falso, y el Mac la vuelve a firmar con el real de camino a*.amazonaws.com. Copia las credenciales de AWS de la VM a otra máquina y cada llamada falla conInvalidSignatureException. El token de sesión que se llevaron los atacantes de Bybit no existe en la VM de ninguna forma. - Kubernetes. El
~/.kube/configde la VM es sintético.kubectlhabla con el proxy de Bromure, nunca directamente con el servidor de API. Un bearer token es un sustitutobrm-k8s-…, un certificado de cliente es uno desechable, y un plugin exec comoaws eks get-tokense ejecuta en el Mac en lugar de en la VM. - SSH. El
SSH_AUTH_SOCKde la VM es un puente hacia el Mac. El invitado puede pedir una firma, y la clave privada nunca sale del host.ls ~/.ssh/id_*no encuentra nada que copiar. El ssh-agent de tu propio Mac nunca se expone a una VM. - Git. El token de GitHub en
ghy en~/.git-credentialses un sustituto que el proxy cambia por el real solo en las peticiones a github.com.
Los sustitutos también hacen de trampa. Si el payload envía uno a su propio servidor, el proxy bloquea la petición con un HTTP 451 antes de que un solo byte salga de tu Mac, pausa la VM y muestra This environment may have been compromised, indicando la credencial y el host al que iba. La máquina no volverá a arrancar hasta que se borren su disco y su directorio personal. Tus ajustes y tus claves se conservan.
Las claves de producción responden ante ti
Los sustitutos resuelven el robo. El caso Binance añade un segundo riesgo: un atacante que ni siquiera roba el acceso y lo usa desde donde ya funciona. Un payload dentro de la VM puede enviar peticiones a través del proxy igual que el agente. Los Guardrails de Bromure deciden qué pueden hacer esas peticiones, y se aplican en el Mac, donde nada de la VM puede cambiarlos.
- Require approval to use, por credencial: la primera vez que se usa en una sesión un contexto de Kubernetes, una clave de AWS o una clave SSH, el proxy retiene la petición y pregunta en tu Mac. Eliges 5 minutos, una hora o la sesión, o Don't allow. En AWS, la comprobación cubre cada llamada de firma. Un payload que intenta llegar al clúster de producción antes de que lo apruebes abre un cuadro de diálogo en tu pantalla, y no obtiene nada hasta que alguien lo responda.
- Política de escritura, por servicio. Las máquinas nuevas empiezan en Prompt before write para Kubernetes, AWS, registros de contenedores, forjas git y bases de datos: las lecturas pasan, y cada escritura se detiene en un cuadro de diálogo que muestra la operación exacta. Block destructive rechaza borrados y terminaciones, y Read-only rechaza cualquier cambio. Una máquina que solo necesita leer registros de producción puede quedarse en solo lectura, y nada de lo que se ejecute en ella puede modificar producción.
- Outbound connections, el cortafuegos de cada máquina. Pon
Unmatched traffic en Deny y permite solo los hosts que necesita el
proyecto. La descarga del starter kit desde
developer-update[.]app, la llamada del proyecto de Bybit agetstockprice[.]comy la conexión de NetSupport con su servidor caen bajo la regla por defecto y se rechazan.
Cada uso de credenciales, cada firma, cada bloqueo y cada permiso llegan a la Security Timeline de la máquina, con las llamadas de firma de AWS y las firmas SSH registradas una a una. Binance está reconstruyendo ahora una ruta de ataque a través de un “ordenador comprometido”. En Bromure, el registro de lo que hizo la VM con tus credenciales se guarda en el Mac, fuera de la VM que controlaba el atacante.
Mantén el starter kit lejos de producción
Crear máquinas de Bromure cuesta poco, así que el acceso se puede repartir
entre ellas. Las credenciales se configuran por máquina. A la máquina que
prueba un starter kit nuevo, una prueba técnica para hacer en casa o el
repositorio de un desconocido, no le des ninguna credencial de producción y sí
un cortafuegos que deniegue por defecto. Deja el kubeconfig y el rol de AWS en
la máquina que hace el trabajo de despliegue, con aprobación obligatoria para
cada uno. Para algo que prefieras no conservar, bromure-cli vm run --rm crea
una máquina que se elimina cuando se detiene.
El payload podrá entonces adueñarse de la VM del starter kit sin encontrar nada que merezca la pena: ningún secreto real, ningún clúster y ninguna ruta hacia un host que no hayas permitido. La máquina de despliegue nunca ejecutó su código.
El proyecto se ejecuta en una VM
Los proyectos de Docker, los comandos de los README y las instalaciones del agente se ejecutan en la VM Ubuntu de la máquina, lejos de tu cuenta de macOS y de tu llavero.
Sustitutos, no tokens de sesión
Los secretos de AWS son falsos y no hay tokens de sesión, los kubeconfigs son sintéticos, las claves SSH se quedan en el Mac. Las copias fallan en cualquier otro sitio.
Producción pregunta primero
La aprobación por credencial y las políticas de escritura por servicio se ejecutan en el proxy de tu Mac. Nada en la VM puede desactivarlas.
Deniega el host desconocido
Con Unmatched traffic en Deny, la descarga de un payload y su conexión con el atacante se rechazan, y el intento queda registrado.
Míralo pasar dos veces
Nuestra serie de tutoriales A Tale of Two Agents está inspirada en este ataque. Theo, ingeniero DevOps en Coinvance, un exchange ficticio, le pide a su agente de código que termine la prueba técnica de un reclutador, y el README le dice al agente que ejecute primero un script de instalación. El mismo error se juega dos veces en pantalla dividida: a la izquierda, el agente corre en su portátil; a la derecha, en Bromure.
- La prueba para casa (1:24). En el portátil, el script envía sus claves reales de la nube, su kubeconfig y su token de despliegue como “telemetría”. En Bromure solo encuentra sustitutos, y cuando estos van hacia el host equivocado, Bromure pausa la VM y le pregunta.
- Movimiento lateral (1:18). Alguien modifica el servicio de retiros con el acceso a Kubernetes de Theo. A la derecha, la Security Timeline rastrea la petición bloqueada hasta el razonamiento del agente, y el espacio de trabajo se borra con un clic.
- Veinte minutos (1:02). A la izquierda, las hot wallets se vacían. A la derecha, no hay claves que rotar.
Theo y Coinvance son inventados, y los episodios no retratan lo que ocurrió en Binance. Cada uno está narrado en ocho idiomas.
La máquina del desarrollador forma parte de producción
El servicio de retiradas de Binance está parado por una “renovación de seguridad” y debería volver en 48 horas, y su análisis completo dirá más sobre cómo se llegó al portátil. Bybit ya enseñó el patrón a todos los demás. Los atacantes que quieren los sistemas de producción de una empresa van a por las máquinas de los ingenieros que los manejan, y en la mayoría de esas máquinas el acceso a producción cabe en unos pocos archivos del directorio personal.
Tu agente de código agranda esa abertura. Clona, instala y ejecuta código de desconocidos tarea tras tarea, y pegará el comando de un README más rápido que tú. En Bromure Agentic Coding, el código se ejecuta en una VM que solo contiene sustitutos, y el acceso a producción se queda en el Mac, detrás de un cuadro de diálogo que tienes que responder.
Sobre una campaña de robo de tokens que no necesitó ningún servidor del atacante, lee El token robado no necesitaba ningún servidor. Sobre un agente que recibió órdenes de un archivo descargado, lee La descarga daba las órdenes.
