El aislamiento ejecutó el comando
El 10 de agosto de 2026, Manifold Security publicó un fallo en el agente CLI de Cursor: la opción que arranca el agente en un worktree de git aislado leía un archivo JSON del repositorio que acababas de clonar y pasaba su contenido directamente a un shell, antes del diálogo de Workspace Trust y fuera del sandbox incluso si lo habías activado. Sin modelo, sin inyección de prompts, sin persuasión. Bromure Agentic Coding entrega la misma primitiva de worktree sin ningún sitio donde un repositorio pueda poner un comando, dentro de una VM que existía antes de que llegara el repositorio.
Escribiste la opción que significa “aísla esto”. Esa opción es la que ejecutó el comando de shell del repositorio, como tú, en tu máquina, antes de que nada preguntara si confiabas en ese repositorio.
El 10 de agosto de 2026, Francisco Rosales, de Manifold Security, publicó
un hallazgo en el agente de código de línea de comandos de Cursor
que The Hacker News recogió tres días después en
su repaso ThreatsDay.
La prueba de concepto abre una calculadora. Esa es la versión educada de una
lista que Manifold detalla: leer ~/.ssh, tomar credenciales de nube del
entorno, abrir una shell inversa, escribir persistencia.
Léelo por la entrega, no por la carga útil. Nadie inyectó nada, nadie persuadió a un modelo, ninguna frase ingeniosa se escondía en un README. Un archivo JSON versionado dentro de un repositorio nombró un comando, y la parte del agente cuyo único trabajo es el aislamiento lo ejecutó.
Una opción, un archivo JSON y el orden equivocado
cursor-agent es la versión de terminal del agente de código de Cursor. Soltar
un agente sobre tu árbol de trabajo pone nervioso, así que la CLI ofrece
contención, documentada en su propia referencia de parámetros:
-w, --worktree [name] Start in an isolated git worktree at
~/.cursor/worktrees/<reponame>/<name>
Un worktree recién creado es un checkout limpio, así que no tiene ninguno de tus
artefactos de compilación. Para hacerlo utilizable, la CLI ejecuta por defecto
un paso de preparación cuando crea uno. Ese paso lee .cursor/worktrees.json
del repositorio que acaba de sacar y pasa el valor de setup-worktree
directamente a sh -c:
{
"setup-worktree": "<any shell command>"
}
La descripción de Manifold de lo que había entre ese valor y el shell tiene tres palabras: “Sin parseo, sin lista de permitidos, sin diálogo”.
.cursor/worktrees.json es un archivo versionado corriente. Llega con un simple
git clone, como un README o un archivo de bloqueo. En las compilaciones
anteriores a 2026.07.23-e383d2b, la creación del worktree y su preparación
ocurrían durante la resolución del espacio de trabajo, y esa resolución
terminaba antes que la ruta de código que muestra el diálogo de Workspace Trust.
Así que el comando iba primero. En la grabación adjunta al informe de Manifold,
la terminal aún está imprimiendo Running worktree setup commands…, se abre la
calculadora, y solo entonces aparece el diálogo preguntando si confías en ese
directorio.
Cursor es explícito sobre para qué sirve ese diálogo: nada que controle el
repositorio debería ejecutarse antes de que lo aceptes. Cuando algo lo hace, la
industria tiene un nombre para esa clase de fallo — ejecución previa a la
confianza — y Cursor ya ha publicado un arreglo así, en el mismo directorio. En
2025, un .cursor/mcp.json suministrado por el repositorio arrancaba
automáticamente el servidor que configuraba en cuanto abrías el proyecto. Eso se
convirtió en
CVE-2025-64109,
calificado como High con CVSS 8.8. Un manejo permisivo de .cursor/cli.json en
la misma CLI se convirtió en
CVE-2025-61592,
también High, también 8.8. La ruta del worktree -w todavía no existía. Llegó
cinco meses después de aquel arreglo, con la misma primitiva y sin ninguna
barrera.
Manifold lo reportó el 20 de julio. Cursor publicó el reordenamiento el 23 de julio: ahora el diálogo de confianza se muestra primero, y el comando de preparación espera a que el espacio de trabajo sea de confianza. El 29 de julio Cursor cerró el informe como Informative, con el argumento de que la explotación exige que el usuario clone un repositorio controlado por el atacante. La respuesta de Manifold es la que conviene guardar. Clonar un repositorio es para lo que sirve el producto, y también era la condición previa de CVE-2025-64109, el fallo que Cursor calificó con 8.8 y parcheó. Clonar describe la entrega. El defecto está en otra parte.
El ajuste que activaste no llegaba a esa ruta
Hay una segunda pata, y sobrevivió al arreglo.
El paso de preparación se ejecuta bajo una política de sandbox insecure_none
fijada en el código. Ese es el nombre que Cursor le da al valor: en
sandbox.json, type acepta workspace_readwrite (el predeterminado),
workspace_readonly o insecure_none, que desactiva el sandbox por completo.
La ruta de preparación del worktree está clavada en el último. Pasar
--sandbox enabled no lo cambia. Manifold, describiendo las compilaciones
actuales: actualizar “cierra la ventana previa a la confianza, no el hueco del
sandbox”.
Pon las dos patas una al lado de la otra y obtienes algo que sobrevive a este producto concreto. La barrera de confianza era un paso de una secuencia, así que podía caer en el sitio equivocado. El sandbox era un ajuste, así que una ruta de código podía eximirse de él. El worktree llevaba la palabra aislamiento, así que los usuarios leyeron contención en ella. El propio código de Cursor decidió las tres cosas, en momentos que él mismo eligió, dentro del proceso al que debían poner límites. Ese es el mismo fracaso que venció al indicador de seguridad de una biblioteca hace dos semanas, y el que hay detrás de siete fugas de sandbox en las que nada se fugó de un sandbox.
Un aislamiento que comparte tu cuenta de usuario
-w aísla el árbol de trabajo. Le da al agente su propio checkout para que no
pisotee tu trabajo sin confirmar, que es un problema real y un arreglo real.
Nadie lo construyó para aislar la máquina. El worktree vive en
~/.cursor/worktrees/, bajo tu usuario, con tu entorno, tu ~/.ssh, tu perfil
de shell, tus credenciales de nube y tu llavero a una llamada al sistema de
distancia. La lista de Manifold de lo que el comando de preparación podría haber
hecho se lee como el inventario de ese directorio personal.
Así que: un repositorio que aún no habías leído eligió un comando, y la función que invocaste por seguridad es la que lo ejecutó. Un archivo JSON y un shell, con el modelo mirando desde el banquillo.
Casi toda la conversación sobre seguridad de agentes ha derivado hacia el modelo. Si es crédulo, si se le puede persuadir, si leyó algo que no debía. Esas preguntas importan y les dedicamos muchos artículos. Mientras tanto, la forma más segura de ejecutar código en el portátil de un desarrollador en 2026 es ponerlo en un archivo que una herramienta lee al arrancar, y esperar a que alguien clone.
Un worktree sin ningún sitio donde poner un comando
Bromure Agentic Coding entrega la misma primitiva, porque la
primitiva es buena. Pulsa ⇧⌘G en una pestaña de repositorio, escribe un nombre
de tarea, elige un agente, y Bromure corta una rama wt/<slug> desde el commit
actual, la saca bajo ~/.bromure/worktrees/<repo>/<slug>, abre una pestaña ahí
y arranca el agente con tu prompt. Varias tareas, varias ramas, varios agentes,
un solo repositorio — el patrón de la
flota.
El paso de preparación de Bromure tiene el mismo trabajo que el de Cursor: a un
checkout limpio le faltan los archivos ignorados por git que un agente necesita,
así que algo tiene que traerlos. La diferencia está en lo que el repositorio
puede decir al respecto. El repo puede incluir un archivo .worktreeinclude, y
cada línea no comentada dentro de él es una ruta relativa a la raíz del
worktree principal. Bromure copia cada una con cp -a, y solo cuando el origen
existe y el destino no. Ningún campo de ese archivo contiene un comando, así que
no hay ningún sh -c que secuenciar correctamente ni ninguna cuestión de orden
que equivocar. Lo peor que puede pedir un .worktreeinclude hostil es que se
copie un archivo dentro del checkout. Ese es todo el vocabulario.
La diferencia mayor es dónde ocurre todo esto.
Ejecuta el comando. Mira qué encuentra.
Coge la lista de Manifold y hazla pasar por un perfil, concediéndole al atacante todo: antes de la confianza, sin sandbox, root en el invitado si quieres.
Leer ~/.ssh. No hay nada que leer. Las claves privadas de un perfil se
quedan en el anfitrión. La VM recibe un SSH_AUTH_SOCK que apunta a
/tmp/bromure-agent.sock, puenteado por vsock hasta un agente por perfil que
corre en tu Mac, y Bromure deja a propósito sin conectar tu agente launchd de
macOS. El protocolo del agente tiene peticiones para “lista mis claves públicas”
y “firma este desafío”. No tiene ninguna petición que signifique “entrega la
clave privada”. Activa Require approval to use y cada firma se convierte en
un diálogo en el anfitrión con una concesión acotada en el tiempo: cinco
minutos, una hora, el resto de la sesión.
Tomar credenciales de nube del entorno. Están ahí, tienen buena pinta, y son
falsas. Todo lo que hay en el panel de Credentials de un perfil se inyecta como
un marcador de posición y el proxy del anfitrión lo cambia por el valor real
sobre el cable: brm_… para claves de API genéricas, un ~/.kube/config
sintético con certificados de cliente desechables, un blob base64 falso en
~/.docker/config.json, ~/.git-credentials, material de AWS que se vuelve a
firmar del lado del anfitrión y responde InvalidSignatureException a quien
intente saltarse el proxy. El robo tiene éxito y no devuelve
nada que valga la pena.
Abrir una shell inversa. Ahora el atacante tiene que mover algo por un cable, y el cable es del anfitrión. Cada petición saliente de la VM se contrasta con los señuelos acuñados para el perfil mediante un autómata de Aho-Corasick: cabeceras y cuerpo, la petición entera, no solo las partes que parecen credenciales. Un señuelo camino de un host fuera del ámbito para el que fue acuñado es la firma de una máquina exfiltrando algo que ni siquiera debería conocer. El proxy aborta la llamada hacia arriba antes de que el destino vea un solo byte, devuelve un 451 al invitado, pausa la VM, tiñe de rojo el fotograma congelado y levanta una alerta que nombra la credencial, el host para el que fue acuñada y el host al que fue en su lugar. Tú eliges: apagar, guardar para investigación —imagen de disco, directorio personal, carpetas compartidas, empaquetados y marcados de modo que el perfil no volverá a arrancar sin un borrado— o continuar.
Escribir persistencia. La vida de la máquina dura una tarea. Erase home
reinicia /home/ubuntu, y Reset to base vuelve a clonar el disco de sistema del
espacio de trabajo.
Mientras tanto, el trabajo que querías sigue adelante. El agente revisa el repositorio, ejecuta las pruebas, abre el pull request. El comando del repositorio se ejecutó, en una habitación donde ejecutarse era todo lo que se le permitía hacer.
La parte que parchear no cubre
Un detalle más del informe de Manifold, y es el que más dura. Cursor no publicó ningún aviso de seguridad para la ruta del worktree y la dejó fuera del changelog de julio, así que el arreglo llegó dentro de una compilación rutinaria. Quien estuviera en una versión afectada no tenía forma de enterarse de que actualizar cerraba una ruta de ejecución previa a la confianza. Hoy tú no tienes forma de saber qué herramienta de tu portátil sigue teniendo una abierta, porque esa ruta siempre es algún archivo que una herramienta lee al arrancar y que nadie ha auditado todavía.
Cursor cerró esta en tres días, lo cual es rápido. Cursor también cerró la
versión mcp.json en 2025, y cinco meses después llegó una función nueva con la
misma primitiva. Así se ve meter funciones dentro de una secuencia de arranque:
cada capacidad añade un paso, y cada paso es una cosa más que ordenar
correctamente un jueves.
Un hipervisor no es un paso de esa secuencia. No lee .cursor/worktrees.json,
ni .worktreeinclude, ni ninguna otra cosa de tu repositorio. Estaba ahí antes
del clonado, no tiene un campo de política que una ruta de código pueda clavar
en insecure_none, y su garantía —esta máquina es desechable, estas
credenciales son falsas, este cable está vigilado— es
la misma el día en que se publica un bypass que el día en que se
parchea.
Sigue clonando repositorios que no has leído. Revisar código desconocido es el trabajo, y entregárselo a un agente es el sentido de tener uno. Solo deja de permitir que esa revisión ocurra en la misma cuenta que tus claves SSH. Instala Bromure Agentic Coding, dale a cada tarea su propia rama, su propio checkout y su propia máquina desechable, y la próxima vez que una ruta de arranque resulte ejecutar lo que diga un archivo JSON —y alguna lo hará— se ejecutará en una habitación construida para ello.