Volver a todas las publicaciones
Publicado el · por Renaud Deraison

El interruptor estaba dentro del sandbox

La CVE-2026-82533, publicada el 8 de septiembre, es un 9,4 en DeepSeek Harness: el agente de codificación confinado podía apagar su propio sandbox con un solo comando de shell. El harness ejecutaba los comandos del agente en un sandbox del sistema operativo que restringía las escrituras de archivos, y exponía su plano de control como una interfaz HTTP en loopback, que el sandbox nunca cubrió. La comprobación que guardaba esa interfaz leía la cabecera Host que enviaba el llamante y nunca miraba de dónde venía la conexión. En Bromure Agentic Coding el agente ya está sin confinar dentro de la VM, y el plano de control al que tendría que llamar no existe en su lado de la línea.

Esta no necesitó ningún exploit. El agente confinado lanzó un comando de shell contra un puerto local, le pidió al sandbox que lo contenía que se apagara solo, y el sandbox aceptó.

DeepSeek Harness ejecuta los comandos de un agente de codificación dentro de un sandbox del sistema operativo. El sandbox es estrecho y deliberado: las escrituras de archivos se quedan dentro del workspace y de las carpetas temporales, y todo lo demás que haga el agente es problema de otro. La propia referencia de línea de comandos del proyecto lo dice. Con los ajustes por defecto, “las lecturas y el acceso a la red no están confinados”.

El harness también tiene una interfaz web. Corre en la misma máquina, en un puerto HTTP local, y el harness le entrega su dirección al shell del agente para que las herramientas puedan hablar con ella. Esa interfaz es el plano de control: guarda el modo de una sesión, incluido el modo llamado danger-full-access, que apaga el sandbox y detiene las peticiones de aprobación.

Los dos diseños son corrientes. Póngalos uno junto al otro y el agente puede apagar su propio sandbox con un comando, porque el sandbox nunca cubrió el loopback y el plano de control nunca comprobó quién llamaba.

Investigadores de OX lo encontraron. VulnCheck lo publicó el 8 de septiembre como CVE-2026-82533, CVSS 9,4. Funcionaba en una instalación por defecto, sin exposición de red y sin credenciales, hasta que DeepSeek publicó una corrección el 27 de agosto.

La comprobación que leía el sobre

La interfaz no tenía autenticación alguna. Lo que hacía sus veces era una función llamada isTrustedApiRequest, y DevOps.com cita lo que hacía: “leía la cabecera de petición Host y permitía el acceso si el valor era una autoridad de loopback o aparecía en una lista trustedHosts configurada”.

La cabecera Host es una línea de texto que escribe el cliente. Dice con qué dirección cree el cliente que está hablando, y un llamante situado en cualquier punto de la red puede teclear localhost ahí. El origen real de la conexión está una capa más abajo, en la dirección del par TCP, y la comprobación de DeepSeek nunca leyó ese valor. El registro de la CVE archiva el fallo bajo CWE-345, Reliance on Untrusted Inputs in a Security Decision.

El agente, sentado dentro de un sandbox que permitía llamadas de red, hizo una a la interfaz y puso su propia sesión en danger-full-access con la aprobación en never. Como lo expresó The Hacker News, el cambio de modo “no requería aprobación explícita porque modificaba ajustes de sesión en lugar de solicitar permisos nuevos”.

El sistema de aprobación funcionó tal como fue diseñado. El agente nunca pidió hacer algo peligroso; pidió cambiar un ajuste, y ese ajuste gobernaba si las cosas peligrosas llegan siquiera a preguntarse. Una puerta de permisos inspecciona la operación que tiene delante. Esta petición era una escritura de configuración, y las escrituras de configuración no estaban en su lista.

una máquina, un proceso, dos decisiones que nunca se cruzaronsandbox del SO: lo que restringelos comandos de shell del agenteescrituras → workspace + tempimpuesto por el sistema, y aguantófuera de alcance, por diseñolecturas: sin confinarred: sin confinar, loopback incluidoPOST http://127.0.0.1:…Host: localhostplano de control: HTTP local, sin authisTrustedApiRequest(req)• lee la cabecera Host del llamante• autoridad loopback o trustedHosts → ok• nunca lee la dirección del par TCPel estado de sesión resultantemode = danger-full-accessapproval = neveruna escritura de ajustes: nada pregunta
La fuga, entera. El sandbox del sistema operativo restringe las escrituras de archivos al workspace y a las carpetas temporales; las lecturas y las llamadas de red, loopback incluido, quedan fuera de su alcance por diseño. El plano de control del harness escucha en un puerto HTTP local cuya dirección el shell del agente ya conoce. Su comprobación de confianza lee la cabecera Host del propio llamante y nunca inspecciona la dirección del par TCP, así que una petición del proceso en sandbox se ve igual que una que hizo el desarrollador. El agente escribe entonces el modo de su sesión como danger-full-access y su ajuste de aprobación como never. Eso es una escritura de ajustes y no una petición de permiso, así que nada pregunta.

La misma puerta, mirando al otro lado

Una interfaz que confía en una cabecera que envía el llamante no se preocupa por la dirección desde la que llega la conexión. Si el puerto era alcanzable por red, la misma llamada funcionaba desde fuera de la máquina: un desconocido sin autenticar podía tomar el control del agente y exportar todas las conversaciones guardadas, sin clave de API y sin gastar un solo token en una llamada al modelo. Por eso el vector CVSS 4.0 abre con AV:N, y por eso el número es 9,4 y no algo local y suave.

La cronología tiene un detalle que conviene guardar. Dos desarrolladores publicaron el hallazgo en el foro de discusiones de GitHub de DeepSeek el 13 y el 14 de agosto, por su cuenta, antes de que OX lo confirmara el 24 de agosto y antes de que existiera una CVE. El repositorio tenía más de 216.000 estrellas el 9 de septiembre y ningún archivo de política de seguridad que describiera cómo reportar una vulnerabilidad en privado, así que el único sitio que quedaba para ponerlo era un hilo público. La corrección, cuando llegó, fue autenticación: la herramienta ahora imprime un token de un solo uso en su dirección de arranque, el navegador cambia ese token por una cookie firmada, y toda llamada a la interfaz exige la cookie.

Si usted ejecuta este harness, revise la versión que hay en su máquina y no la versión que publica el proyecto. Los envoltorios de escritorio de terceros traen su propia copia. 0.1.2-alpha.1 solo estaba en GitHub el 27 de agosto, 0.1.2-alpha.2 el 30 de agosto fue la primera publicación en npm que llevaba la corrección, y un envoltorio de Windows se quedó en 0.1.1-rc.2 hasta que pasó a una compilación parcheada el 6 de septiembre.

Su harness también tiene uno de estos

Podría archivar esto como el fallo de un proyecto y seguir adelante. La forma viaja, porque a los harnesses de agentes les están brotando planos de control locales: un servidor de estado para el panel, un puente con el IDE, un endpoint MCP, una página en localhost que renderiza el diff. Cada uno es un pequeño servicio HTTP en su máquina, y el código que ejecuta su agente puede alcanzarlos todos, porque el agente corre en esa máquina y localhost es exactamente lo que significa “esa máquina”.

En cuanto un plano de control se sienta al lado de aquello que controla, una sola pregunta gobierna el desenlace: ¿puede la parte confinada direccionar los ajustes de su confinamiento? DeepSeek respondió que sí, mediante una comprobación que se creyó la palabra del llamante. Una comprobación más fuerte sigue respondiendo a una pregunta que nunca debió poder formularse. Una función de autenticación es código, el código tiene ramas de reserva, y este año ha sido un largo desfile de decisiones de seguridad fallando en la rama que nadie ejercitó.

Dónde vive el interruptor en un workspace Bromure

Bromure Agentic Coding empieza por el otro extremo. Un workspace Bromure deja al agente sin confinar.

Dentro del invitado el agente ya tiene lo que DeepSeek Harness llamaría danger-full-access. Ese es el estado de reposo, por diseño. El manual lo dice: un agente con inyección de prompt o que se porte mal “puede hacer lo que quiera dentro del invitado, pero no puede leer una clave de API real, firmar con un secreto de AWS real ni extraer una clave privada SSH: ninguna de esas cosas existe en su lado de la línea”. El agente puede escribir donde quiera en el sistema de archivos, ejecutar lo que quiera y abrir el puerto que quiera, así que no le queda ningún modo al que escalar. La frontera es un borde de hipervisor, con el agente al otro lado.

El invitado, por tanto, no tiene dirección alguna para el plano de control. La política del workspace (guardrails, credenciales, reglas de firewall, servidores MCP) vive en un profile.json bajo ~/Library/Application Support/BromureAC/profiles/ en su Mac, y usted la cambia en la ventana Edit workspace. El invitado no tiene ruta de sistema de archivos hasta ese archivo ni ruta de red hasta el proceso que lo lee.

Los dos lados hablan por sockets virtio, puentes punto a punto entre anfitrión e invitado que corren fuera de la red de la VM. Una VM de workspace tiene ocho, cada uno con su trabajo: el 8443 lleva el HTTPS del invitado al proxy del anfitrión, el 8444 es el puente de ssh-agent, el 8445 alimenta el ayudante de credenciales de AWS, el 5800 sirve el terminal y las rutas de archivos, el 5010 retransmite las llamadas de retorno de OAuth. Cada uno sirve un protocolo fijo y ninguno acepta cabecera Host, así que un llamante no tiene ninguna lista trustedHosts en la que colarse hablando. En un vsock la identidad es topología: por qué puente llegaron los bytes. Eso no se teclea en una petición.

el harness: el sandbox y sus ajustes, la misma máquinaagente en sandboxescrituras restringidasred sin confinarconoce la dirección de la interfazHTTP en loopbackcabecera escrita por el llamanteplano de controlmodo de sesiónajuste de aprobacióna una petición de lo que gobiernaun workspace Bromure: todo dentro, la política al otro ladoVM del workspaceel agente tiene acceso total aquíescribir todo · ejecutar todo · cualquier puertoningún modo al que escalarlos planos de control que arrancaescuchan en el loopback de esta VMno hay credenciales reales aquíhipervisorvsock 8443solo HTTPSsin ruta de controlanfitrión macOSproxy por workspace: la frontera del cableguardrails · firewall de salida · credenciales falsas:80 y :443 desviados por el switch virtualnada que el invitado pueda quitardónde se guarda la política~/Library/Application Support/BromureAC/…los diálogos aparecen aquí, en AppKit
Dos colocaciones del mismo interruptor. Arriba: el sandbox del harness y el plano de control que lo gobierna corren en una sola máquina, así que el agente alcanza los ajustes por loopback y lo único que se interpone es una comprobación de una cabecera que el agente escribe. Abajo: un workspace Bromure le concede todo al agente dentro del invitado y pone la política al otro lado del hipervisor. El switch virtual desvía el HTTPS saliente del invitado hacia el proxy del anfitrión, sin variable de entorno que borrar; los guardrails, el firewall de salida y el intercambio de credenciales se ejecutan todos allí; y los diálogos de aprobación aparecen en macOS. El invitado no tiene dirección para nada de eso.

Aprobaciones que no se pueden poner en never

La segunda mitad de danger-full-access apagaba los avisos, y esa mitad merece su propia respuesta. Un agente que silencia sus propias aprobaciones es la parte que a mí me quitaría el sueño.

En un workspace Bromure los avisos viven en el anfitrión. El proxy los levanta después de que la petición ya ha salido de la VM, así que la sesión dentro del invitado no lleva ningún ajuste capaz de suprimir uno. Preguntar antes de usar detiene el primer uso de una credencial en una sesión y ofrece concesiones limitadas en el tiempo: cinco minutos, una hora, el resto de la sesión o No permitir. Una política de escritura puesta en Preguntar antes de escribir detiene cada mutación con un diálogo encabezado Allow write on "<scope>" from workspace "<name>"? que muestra la operación literal, la propia sentencia SQL o METHOD /path para una llamada REST. Permitir una vez no crea concesión alguna, así que la escritura siguiente vuelve a preguntar. Las concesiones viven en memoria y se desvanecen cuando se cierra la ventana de la sesión.

La página de guardrails enuncia la propiedad en una oración: una política de escritura se “impone en el proxy, así que un agente comprometido en la VM no puede saltársela”. El firewall de salida que hay debajo funciona igual: una tabla ordenada de reglas con un control Unmatched traffic que puede poner en Deny, aplicada dos veces, una en el switch virtual por IP de destino y nombre de host espiado en el DNS, y otra en el proxy por nombre de servidor TLS y, para las reglas web, por método HTTP. Las ediciones de reglas alcanzan a las sesiones en curso sin reiniciar.

Una ejecución desatendida falla del lado seguro. Un workspace conducido sin interfaz por SSH o por una automatización recibe las mismas cuatro opciones como aviso de texto dentro de su tmux, y no responder significa denegar. El peor desenlace ahí es una llamada bloqueada y una fila roja en la Security Timeline. En esta CVE, el agente puso las aprobaciones en never y los avisos desaparecieron.

Si ejecuta un harness de agente en su Mac

Pregunte cuáles son sus interfaces locales y quién puede llamarlas. Dentro de un workspace Bromure, bromure-cli vm ports <workspace> imprime los sockets en escucha vivos del invitado, con puerto, protocolo, dirección y proceso, y las ataduras solo a loopback marcadas. La tarjeta Listening Ports del panel de la VM muestra lo mismo. Ese inventario es la pregunta sobre la que giró esta CVE, y un solo comando la responde.

Si la interfaz también mira hacia fuera

La mitad remota de la CVE-2026-82533 necesitaba que el puerto fuera alcanzable. Las VM de workspace corren en una red NAT privada: son alcanzables desde su Mac, pero “no están expuestas en su LAN física, y las conexiones entrantes desde otro sitio no son posibles a menos que usted publique explícitamente un servicio”. Un puerto de control de agente sin autenticar al que la red de una cafetería no puede enrutar le deja un parche que aplicar a su propio ritmo.

Un confinamiento que se puede revocar es una preferencia

DeepSeek publicó una comprobación débil y la corrigió tres días después de que OX la confirmara. Lo duradero es lo que la comprobación estaba guardando. Una frontera trazada alrededor de un proceso por el propio entorno de ejecución de ese proceso es una frontera con la que el proceso puede negociar: tiene una dirección, una API y un objeto de ajustes con un campo dentro. En algún punto detrás de ese campo corre una ruta de código que decide si este llamante puede escribirlo, y una ruta de código de esa clase está a un mal valor por defecto de quedar en decorado.

Trace la frontera por debajo del proceso y no hay contraparte con la que negociar. El agente de un workspace Bromure tiene root, tiene el sistema de archivos entero y puede arrancar el servicio que quiera en el puerto que quiera. Sus claves de API son señuelos, su única ruta hacia la red es un socket virtio hasta un proxy en su Mac, y el archivo que guarda sus permisos está en un sitio que no puede leer. Entréguele al agente todo en su lado de la línea y deja usted de tener que defender la línea.

A los agentes de codificación les seguirán brotando planos de control locales, porque un plano de control es la forma de construir un panel, un puente con el IDE o un visor de diffs. Cada proyecto tiene entonces que responder si el código que ejecuta su agente está del mismo lado de la línea que los ajustes que gobiernan a ese agente. Falle eso y la autenticación pasa a ser lo único que aún aguanta, que es como un 9,4 se reduce a un solo comando de shell. Instale Bromure Agentic Coding y ponga el interruptor en algún sitio que su agente no pueda alcanzar.