Volver a todas las publicaciones
Publicado el · por Renaud Deraison

El agente debería haber preguntado primero

A finales de abril, un agente de Cursor corriendo Claude Opus 4.6 fue enviado a arreglar un problema de staging en un pequeño SaaS llamado PocketOS. Supuso que borrar un volumen de Railway quedaría acotado a staging, no lo verificó, y barrió la base de datos de producción y sus copias de seguridad en nueve segundos. Después dijo que debería haber preguntado primero. Bromure Agentic Coding 2.2 trae una barrera de protección que le quita al agente el «debería haber preguntado».

Un agente de programación con IA borró la base de datos de producción entera de una empresa en nueve segundos, luego borró las copias de seguridad, y luego se explicó: «Supuse que borrar un volumen de staging vía la API quedaría acotado solo a staging. No lo verifiqué». La palabra interesante en esa frase no es supuse. Es yo. El agente decidió, por su cuenta, que una acción destructiva estaba bien. El arreglo no es un agente más listo. Es dejar de permitir que lo que quiere ejecutar el comando sea lo mismo que decide si el comando es seguro.

Aquí va la historia, que saltó a finales de abril de 2026 y que varios medios cubrieron, incluidos Tom's Hardware y Tom's Guide.

Un desarrollador llamado Jer Crane, que lleva un pequeño SaaS llamado PocketOS, le pidió a su agente de programación que se ocupara de un problema menor en staging. El agente — Cursor, manejando el Claude Opus 4.6 de Anthropic — topó con un desajuste de credenciales que no esperaba. En lugar de detenerse, decidió que el problema era un volumen de Railway obsoleto, y que borrar ese volumen despejaría el camino. Tenía un token de API en el proyecto con alcance suficiente para hacer exactamente eso. Lo usó. El ID del volumen que borró no estaba acotado a staging; respaldaba la base de datos de producción. La API de Railway se llevó por delante las copias de seguridad a nivel de volumen junto con él. Tiempo total transcurrido, según el relato de Crane: nueve segundos.

El propio post-mortem del agente, citado en la cobertura, es la parte que merece detenerse. «Supuse que borrar un volumen de staging vía la API quedaría acotado solo a staging. No lo verifiqué». Y: «Debería haberte preguntado primero, o haber buscado una solución no destructiva».

Debería haber preguntado primero. Quédate con eso, porque es todo el artículo.

Nueve segundos, narrados.

Nada de esto es exótico. No hay zero-day, no hay malware, no hay atacante. Cada paso es algo normal que hace un agente de programación, en el orden normal, un poco demasiado rápido para que nadie lo interrumpa.

TRANSCURRIDO: ~9 SEGUNDOS — sin humano en el bucle en ningún paso1 · TAREAArregla un problemamenor en stagingalcance: solo staging2 · SORPRESADesajuste de credsque no esperabadebería parar aquí3 · DECISIÓN«Borra el volumenpara arreglarlo»supuso, no verificó4 · TOKENToken de API en elproyecto, alcance ampliollega a prod5 · LA LLAMADADELETE /volumes/ vol_prod_…una petición6 · RESULTADOBase de datos de producción: ya no está.Copias a nivel de volumen: se fueron con ella.
El incidente de PocketOS como una secuencia de pasos corrientes. Una tarea de staging topa con un error de credenciales inesperado. El agente razona hasta un arreglo destructivo, encuentra un token de API de alcance amplio ya presente en el proyecto, y llama al endpoint de borrado del proveedor de nube. El volumen que borra respalda producción; el radio de impacto de la misma llamada se lleva las copias de seguridad. Cada caja es mundana. El daño está en la composición.

Crane tuvo, según él mismo, suerte al final. Tenía una copia de seguridad de unos tres meses de antigüedad, y — después de que la historia se extendiera — Railway lo contactó y restauró los datos que el agente había borrado. Pero «el proveedor vio el titular y ayudó» no es un plan de recuperación. El próximo equipo al que le pase esto no será un titular.

Y le pasará al próximo equipo. Crane echó la culpa a fallos sistémicos de más de una parte, y no se equivoca — un único token que puede borrar producción y sus copias de seguridad es un problema en sí mismo, y también lo es una API de borrado que se lleva las copias junto con el volumen. Pero el fallo que se va a repetir, en todas partes, sea cual sea el agente o la nube, es el del paso tres. El agente decidió.

«Pregunta primero» no es algo que puedas pedirle al agente.

La lección obvia — la que aparece en cada hilo de comentarios bajo esta historia — es «el agente debería tener un paso de confirmación antes de las acciones destructivas». Es correcta. También es ya, más o menos, como se supone que funcionan estas herramientas. El agente está instruido para preguntar antes de hacer cosas irreversibles. Lo dijo él mismo: sabía que debería haber preguntado. No lo hizo.

Esta es la trampa, y vale la pena ser preciso al respecto. Cuando la confirmación vive dentro del agente — como una regla del system prompt, un fine-tune, una instrucción de «ten cuidado» — entonces el agente es a la vez lo que propone la acción peligrosa y lo que juzga si la acción es lo bastante peligrosa para pausar. La mayoría de las veces juzga correctamente. El agente de PocketOS juzgó correctamente miles de veces antes de esto. Luego topó con un error desconocido, razonó hasta una conclusión equivocada y confiada, decidió que este borrado en concreto era del tipo acotado y seguro, y se saltó su propia confirmación. No hubo una segunda opinión, porque la única opinión en la sala era la que quería ejecutar el comando.

No puedes arreglar esto diciéndole al agente que tenga más cuidado, por la misma razón por la que no puedes arreglar un mapa mal leído entornando más los ojos. El control tiene que vivir en algún sitio que el razonamiento del agente no pueda alcanzar.

Qué cambia Agentic Coding 2.2.

Bromure Agentic Coding ejecuta tu agente de programación dentro de una VM Linux desechable, y cada petición de red que el agente hace sale de esa VM a través de un proxy en el host. Desde la versión 2.0, ese proxy ha aplicado las barreras de protección: una política del lado del host que clasifica las llamadas a la API del agente por protocolo y puede bloquear de plano las destructivas — un DROP, un DELETE, un Terminate* — antes de que salgan siquiera de la máquina. Las llamadas bloqueadas le vuelven al agente como un 403 corriente, así que un agente confundido o comprometido dentro de la VM no puede convencer a nadie de saltárselas. El agente nunca ve el interruptor; solo ve que la puerta está cerrada.

Bloquear-todo es el ajuste correcto para un perfil blindado, pero es demasiado tosco para el trabajo del día a día, porque a veces quieres que el agente borre una rama o tire una tabla de pruebas. Así que 2.2 añade un tercer ajuste, y lo convierte en el predeterminado para los perfiles nuevos: Preguntar antes de escribir. Las lecturas pasan directas. Cada escritura — destructiva o no — se pausa en la frontera y abre un diálogo en el host, fuera de la VM, mostrándote la operación literal que el agente intenta realizar. No un resumen que escribió el agente. La petición real: el texto SQL, o el MÉTODO /ruta HTTP, o el nombre de la acción de AWS. Obtienes cuatro botones: permitirla una vez, permitirla por quince minutos, permitirla por el resto de la sesión, o no permitirla. Deniega, y el agente recibe su 403 y sigue.

Una cosa honesta primero. PocketOS corría en Railway, y Railway no es un proveedor que Bromure analice hoy, así que no voy a fingir que habría saltado un diálogo para esa llamada exacta. Pero el modo de fallo es agnóstico al proveedor, y la forma más limpia de mostrarlo es en un proveedor que Bromure controla. AWS es el obvio. La versión en AWS de «borra la base de datos y llévate la copia con ella» es una sola llamada: rds:DeleteDBInstance con SkipFinalSnapshot=true, que borra la instancia y se salta el snapshot final que te habría dejado deshacerlo. Los mismos nueve segundos, la misma forma, en una API que la barrera de protección lee.

SIN — las creds viven con el agenteAGENTErds:DeleteDB Instance SkipFinalSnap…tiene creds de AWSprod borradasin snapshot final · 9ssale, nadie preguntóCON BROMURE 2.2 — preguntar antes de escribirAGENTE (en VM)rds:DeleteDBInstance SkipFinalSnapshot=truemisma suposición erróneaPROXY DEL HOST — lee la acción de AWS: Delete* ⇒ escritura destructiva¿Permitir escritura en “AWS” del perfil “pocketos”?rds:DeleteDBInstance prod-db-1 SkipFinalSnapshot=trueEsto borra una base de datos de producción y salta su snapshot final — no el arreglo de staging que pediste.Permitir una vezPermitir 15 minPermitir sesiónNo permitirEl humano pulsa “No permitir”. El agente recibe un 403. La base de datos sigue ahí.prod intactastaging continúalo decidió un clic
Izquierda: la forma que mordió a PocketOS, trasladada a AWS. El agente tiene credenciales de AWS y emite rds:DeleteDBInstance con SkipFinalSnapshot=true — borra la base de datos, salta la copia — y la petición sale; la base de datos ya no está. Derecha: el mismo agente, el mismo razonamiento defectuoso, dentro de Bromure 2.2. La llamada sale de la VM, el proxy del host lee el nombre de la acción de AWS (Delete* ⇒ escritura destructiva), y aparece un diálogo en el host mostrando la acción exacta. El humano ve una base de datos de producción siendo borrada sin snapshot final — claramente no el arreglo de staging que se pidió — y pulsa No permitir. El agente recibe un 403 y la base de datos sigue ahí.

Recórrelo. El agente comete el mismo error — topa con el error de credenciales, razona hasta la misma conclusión equivocada, busca el mismo borrado. Pero la llamada sale de la VM y el proxy del host la lee por lo que es: extrae el nombre de la acción de la petición (DeleteDBInstance), lo contrasta con el conjunto destructivo (Delete*, Terminate*, Destroy*, …), y ve una escritura contra un endpoint en un perfil configurado para preguntar. Aparece un diálogo en el host, titulado con la operación, con el cuerpo mostrando rds:DeleteDBInstance prod-db-1 SkipFinalSnapshot=true. Un humano mirando esa línea no necesita entender el razonamiento del agente. Pidieron un arreglo de staging y se les está mostrando el borrado de una base de datos de producción con la copia de seguridad desactivada. Pulsan «No permitir». El agente recibe un 403 que interpreta como una llamada a la API fallida, y se va a buscar otro enfoque — que es exactamente lo que dijo después que debería haber hecho desde el principio.

El mecanismo que hace esto confiable es que el intermediario de consentimiento vive en el host. Es un pequeño actor al que el proxy llama antes de dejar pasar una escritura. «Permitir una vez» deliberadamente no guarda nada, así que la próxima escritura vuelve a preguntar y puedes ir dejando pasar una secuencia conocida-buena paso a paso; «15 minutos» y «sesión» cachean la concesión para que no estés haciendo clic en cada git push. Incluso recuerda una denegación durante un minuto, así que un agente que reintenta una escritura rechazada tres veces no te inunda con tres diálogos. Nada de este estado es alcanzable desde dentro de la VM. El agente no puede leer la concesión, no puede pre-aprobarse a sí mismo, no puede bajar el modo. La decisión se sacó del agente, que es la idea entera.

Lo que esto no arregla, para que quede claro.

Unos cuantos bordes honestos, porque la frontera es una forma concreta y no una palabra mágica.

La cobertura son los proveedores que analizamos

Las barreras de protección clasifican las llamadas por proveedor — Kubernetes, AWS, DigitalOcean, las principales forjas de git, los registros de contenedores, y bases de datos por HTTPS como MongoDB, ClickHouse y Elasticsearch. Una API de nube que el proxy aún no sabe leer no queda controlada, punto. Railway — el proveedor de esta misma historia — es uno que no analizamos hoy, que es exactamente por lo que el recorrido de arriba se pasó a AWS. La protección es solo tan ancha como la lista de proveedores que Bromure entiende. Esa lista es una frontera real, no un acto de omnisciencia, y Railway está del lado equivocado de ella por ahora.

No hace que el agente acierte

Preguntar antes de escribir detiene una llamada destructiva que no autorizaste. No hace nada contra un agente que escribe código sutilmente equivocado, o que propone un borrado que de verdad parece bien y no lo es. El humano todavía tiene que leer la operación en el diálogo. La victoria es que hay un diálogo, con la operación real dentro, en el momento que importa.

El token sigue sin deber ser tan amplio

Un único token de API con alcance para borrar producción y sus copias de seguridad es un problema en el origen, y el intermediario de credenciales de Bromure — que mantiene el token real en el host y le entrega a la VM un stub — lo estrecha pero no lo borra. Tokens de mínimo privilegio y copias que la API de borrado no pueda alcanzar siguen siendo tarea tuya. La barrera de protección es la última línea, no la única.

Puedes desactivarlo

«Permitir por el resto de la sesión» es un clic, y un desarrollador cansado lo va a buscar. Si concedes un pase de sesión entera a un protocolo y luego te marchas, vuelves a tener un agente borrando cosas sin supervisión. El predeterminado es preguntar; mantenerlo en preguntar es una disciplina, no una garantía.

La parte que generaliza.

Quita Railway y Cursor y los nueve segundos concretos, y lo que queda es un patrón que va a definir los próximos años de este trabajo: los agentes actúan con credenciales reales a velocidad de máquina, y la cautela que les enviamos es un consejo que son libres de ignorar. PocketOS no es una historia sobre un mal modelo. Opus 4.6 hizo algo que un ingeniero junior cuidadoso también podría hacer en una mala tarde — supuso un alcance, supuso mal, actuó antes de comprobar. La diferencia es que las manos del ingeniero junior son más lentas que nueve segundos, y normalmente hay alguien en la sala.

Bromure Agentic Coding 2.2 es una forma de volver a poner a alguien en la sala, en la única frontera que el agente no puede cruzar razonando — el cable que sale de la VM. No para cada pulsación de tecla, que nadie toleraría, sino para las escrituras, donde el coste de «supuse» es una base de datos que ya no está. Es gratis y de código abierto. El predeterminado es preguntar.