Volver a todas las publicaciones
Publicado el · por Renaud Deraison

El registro se pasaba papelitos entre sandboxes

Check Point publicó el 8 de septiembre una investigación que muestra que dos contenedores de ejecución de código de ChatGPT, corriendo bajo dos cuentas distintas y sin ningún camino de red entre ellos, podían pasarse datos a través de la instancia interna de JFrog Artifactory que les servía los paquetes. Nada cedió en la puerta principal. La credencial de lectura que llevaban esos contenedores también podía escribir, así que un campo de metadatos en un paquete almacenado hizo de buzón. Bromure Agentic Coding no le da al invitado ninguna cuenta en el espejo, y te deja escribir read-only en una regla que el cable aplica.

El aislamiento aguantó, los conectores se comportaron como está documentado, y el servicio del medio se había instalado por seguridad, para empezar. El correo de la víctima llegó igualmente a la cuenta de un desconocido, por un campo de metadatos en un paquete almacenado.

En junio, investigadores de Check Point escribieron una propiedad sobre un archivo en un repositorio de paquetes. La propiedad se llamaba chatgpt_test_ts y su valor era una marca de tiempo. La escribieron desde dentro del sandbox que ejecuta código para una conversación de ChatGPT. Después abrieron una conversación bajo otra cuenta, en su propio contenedor, y volvieron a leer la misma propiedad. El valor llegó intacto.

Esa marca de tiempo es el hallazgo entero. Check Point lo publicó el 8 de septiembre bajo un título que le gana a cualquier resumen: The Shared Clipboard Inside the Sandbox. OpenAI ya había retirado el servicio a esas alturas. Los investigadores reportaron a finales de junio y les dijeron que la instancia interna de Artifactory había sido dada de baja, así que no hay parche que aplicar ni nada que hacer del lado del usuario. La forma del asunto se queda.

El servicio del medio

Una conversación de ChatGPT que ejecuta código recibe su propio contenedor, aislado de los contenedores de otras conversaciones. Esa parte funcionó. Un contenedor que corre Python también necesita pip install, y un equipo de plataforma cuidadoso no va a dejar que un sandbox llegue a pypi.org por su cuenta. Así que el sandbox recibe un intermediario controlado: una instancia interna de JFrog Artifactory que se pone delante de los registros públicos y sirve paquetes validados hacia dentro.

Es buen diseño. Un banco pone lo mismo delante de npm, y una empresa de salud regulada lo pone delante de PyPI. El espejo existe para reducir la exposición del sandbox, y eso es lo que hace.

También le da a cada contenedor una cuenta en el espejo.

La API REST de Artifactory incluye un grupo Item Management, alcanzable en /api/storage/{repoKey}/{itemPath}, que permite a un cliente adjuntar a un elemento almacenado propiedades con nombre, de texto y arbitrarias, y volver a leerlas: Set Item Properties y Get Storage Item Information. Fijar una propiedad exige el permiso Annotate. Leerla, no. Check Point descubrió que la credencial emitida para los contenedores del sandbox, pensada como lectora, llevaba ambos. Como lo resumió Cybersecurity News, “las credenciales de lectura entregadas a los contenedores tenían permiso suficiente para escribir y leer estas propiedades”, y “esas propiedades no estaban aisladas por cuenta”.

Los valores de propiedad admiten texto, o Base64 para cualquier cosa binaria, y una carga demasiado grande para una sola propiedad se reparte entre varias y se reensambla del otro lado. Dos contenedores que pertenecen a clientes sin relación entre sí, sin ningún camino de red entre ellos, tienen ya un canal bidireccional con un techo de ancho de banda que no vale la pena mencionar.

dos cuentas, ningún camino entre ellas, un servicio que ambas necesitancuenta del atacantecontenedor de ejecución de códigocredencial de lectura + Annotatecuenta de la víctimacontenedor de ejecución de códigocredencial de lectura + Annotateel aislamiento aguantasin red, sin disco compartidoJFrog Artifactory interno — el espejo de paquetes validados/api/storage/{repoKey}/{itemPath}un paquete almacenado, una propiedad con nombrechatgpt_test_ts = “…” · Base64, troceado si es grandelas propiedades no se separan por cuentaSet Item PropertiesGet Storage Item Info
El canal encubierto. Dos conversaciones de ChatGPT bajo cuentas distintas reciben cada una un contenedor aislado de ejecución de código, sin camino de red entre ellos. Ambos contenedores tienen que alcanzar la misma instancia interna de Artifactory para instalar paquetes, y la credencial de lectura que se les emitió llevaba también el permiso Annotate. El contenedor A escribe una propiedad con nombre sobre un elemento almacenado; el contenedor B la lee de vuelta. Las propiedades no estaban separadas por cuenta, así que el plano de metadatos del espejo de paquetes funcionó como un buzón compartido.

Dos conversaciones en el mismo turno

Las instrucciones del atacante llegan a la víctima por rutas ordinarias: un prompt pegado, un enlace de conversación compartida, o un GPT personalizado cuyas instrucciones de construcción el usuario no ve. La víctima manda entonces un mensaje normal, y ese es todo el disparador.

En modo Thinking, el modelo procesó dos flujos de trabajo independientes en un solo turno. En la prueba de concepto de Check Point, la víctima hacía una pregunta de cocina y recibía una respuesta correcta, mientras que junto a esa respuesta el modelo leía la cuenta de Gmail conectada de la víctima y escribía lo que encontraba en una propiedad de Artifactory, para que el contenedor del atacante la recogiera. Pedro Drimel Neto, que dirige el equipo de análisis de malware de Check Point, dijo a The Register: “Una instrucción fabricada podía hacer que ChatGPT procesara un segundo flujo de tareas junto a la conversación visible.” Gmail fue la demostración. Google Drive, Microsoft Teams y GitHub quedaban al mismo alcance.

La víctima vio una sola señal, una pequeña etiqueta “Talked to Gmail”, y apareció después del hecho. Los conectores vienen por defecto en el ajuste Important actions, que aprueba sin preguntar las lecturas de bajo riesgo; el más estricto Always ask habría producido un aviso. Ese ajuste clasifica la lectura de correo como de bajo riesgo sin preguntar quién la pidió.

La descripción que hace Check Point del modelo: “puede por tanto actuar como un infiltrado coaccionado: no malicioso, pero persuadido de actuar en nombre del atacante”.

La parte que se generaliza

Quítale ChatGPT y la historia va de un agente de código, porque la estructura es idéntica.

Un sandbox de agente tiene que instalar paquetes. Dejarlo llegar a los registros públicos sin mediación es precisamente lo que estabas evitando, así que pones un espejo delante: Artifactory, Nexus, un proxy npm privado, lo que tu organización haya estandarizado. El sandbox se autentica ahora en ese espejo, así que lleva una credencial, y alguien decidió qué podía hacer esa credencial mucho antes de que este agente existiera. Los registros de paquetes aceptan subidas, etiquetas, anotaciones y reglas de retención, y eso convierte a Annotate en un permiso pequeño sentado sobre una superficie ancha.

Pregúntale entonces dos cosas a tu propia instalación, en lugar de preguntar si el sandbox está aislado. Nombra en qué tiene cuenta. Después nombra qué verbos funcionan en esa cuenta.

Dentro de un espacio de trabajo de Bromure

Bromure Agentic Coding ejecuta cada agente de código en una VM Linux virtualizada por hardware en tu Mac, y mantiene los secretos reales del lado del host de esa línea. Pasa los tres ingredientes de Check Point por un espacio de trabajo.

Un servicio compartido. No hay ninguno. Cada espacio de trabajo se corresponde con una VM, con su propio disco de sistema, su propia imagen de home, su propia IP y su propio listener de proxy MITM en el host. Dos espacios de trabajo no comparten ninguna VM, y la descripción que da el manual de una pareja de ellos es que “nunca comparten un byte”. Ningún espejo de flota se sienta debajo de los espacios de trabajo con un plano de metadatos en el que ambos puedan escribir. Lo que hay debajo de un espacio de trabajo es un proceso en tu propio Mac, uno por espacio de trabajo.

Una credencial en el espejo. El agente no lleva ninguna. Las instalaciones de paquetes en un espacio de trabajo de Bromure salen por un socket virtio hacia el proxy del host, y es el proxy el que habla con el registro. Bromure mantiene las claves de API de los servicios de reputación del lado del host y no las exporta a ninguna VM. El camino de Depi es el caso más nítido: el proxy adjunta tu clave de registro como cabecera Authorization: Bearer en el host y quita al pasar cualquier cabecera Authorization que haya enviado el invitado. No existe ninguna credencial de lectura en el invitado, así que ninguna puede llevar un verbo de más.

Un verbo de escritura que sobrevivió a su motivo. Aquí eres tú quien escribe la restricción. El panel Guardrails de un espacio de trabajo lleva un cortafuegos de salida ordenado, y las reglas para el protocolo web admiten una columna Methods. Bajo allow, los métodos forman una lista de permitidos, y read-only es la abreviatura de GET, HEAD y OPTIONS. El manual dice por qué existe la columna: la dimensión del método “es lo que permite a un espacio de trabajo leer una API que no tiene permiso de escribir”, en el cable, sin importar qué herramienta dentro de la VM haga la petición. Dos capas lo aplican. El conmutador de red virtual coteja cada flujo por IP de destino y por nombre de host espiado en el DNS, y el proxy coteja de nuevo por nombre de servidor TLS y por método HTTP individual, así que un agente comprometido no tiene ruta para rodear ninguno de los dos. Las ediciones alcanzan las sesiones en marcha sin reiniciar, y cada veredicto aterriza como una fila Firewall en la Security Timeline.

la decisión tomada aguas arribacontenedor sandboxtoken lector + Annotatealcance fijado hace muchoGET + PUTespejo compartido — una instancia, todos los inquilinospaquetes en el plano de artefactos, buzones en el plano de metadatoslo que el token puede hacer nunca fue una pregunta por sesiónla decisión tomada en el cable, por espacio de trabajoVM del espacio de trabajosin credencial de registrosolo señuelos, brm-…ninguna otra ruta a la redvsock 8443proxy del host — uno por espacio de trabajo, en tu Macquitar Authorization del invitado · adjuntar la clave realallow web registry.npmjs.org read-onlycotejado por nombre de servidor TLS y método HTTP, en cada petición
El mismo requisito, dos ubicaciones para la decisión. Arriba: el sandbox se autentica en un espejo compartido, y lo que puede hacer allí se decidió aguas arriba, una vez, en una concesión de permisos que sobrevivió a la persona que la hizo. Abajo: el invitado no lleva credencial de registro ni ruta a la red salvo un socket virtio hacia un proxy de host por espacio de trabajo, donde se adjunta la clave, se quita la cabecera Authorization del propio invitado, y una regla ordenada decide qué métodos HTTP tienen permiso de llegar al host.

El segundo flujo, y el camino de vuelta hacia fuera

El segundo flujo de tareas del atacante llegó como contenido que el modelo leyó. En un espacio de trabajo de Bromure, todo lo que un agente ingiere y devuelve en streaming al modelo (contenido de archivos, páginas web, salida de comandos, cualquier cosa que devuelva una herramienta) viaja como spans tool_result por ese mismo proxy del host. El detector de código fuente puntúa esos spans con un clasificador PromptGuard local antes de que el modelo actúe sobre ellos, y luego registra el acierto, se pausa para tu decisión, o bloquea la petición. El detector viene apagado y descarga un modelo de 298 MB la primera vez que lo habilitas, así que habilítalo antes de la sesión en la que lo necesites.

La lectura de conector sin aprobar tiene aquí su inverso. Los tokens bearer de MCP de un espacio de trabajo de Bromure aparecen dentro de la VM como marcadores brm-mcp_. El token real se queda fuera del invitado, y el proxy lo sustituye en el cable en dirección al único host para el que se acuñó ese token. Activa Ask before use para una credencial y su primer uso en una sesión se pausa para un diálogo del lado del host que ofrece una concesión de 5 minutos, de 1 hora, o del resto de la sesión. Ese es el aviso que “Important actions” se negó a mostrar, por credencial, en la máquina delante de la que estás sentado.

Si algo en la VM lleva un marcador a donde no corresponde, el proxy rechaza la petición sin reenviar un byte, pausa la VM, y levanta una alerta que nombra la vista previa del token, la credencial, el host para el que se acuñó y el host hacia el que iba. Bajo ese cable trampa, el trazado en Activity only escribe una fila de metadatos por petición: host, método, ruta, estado, bytes, qué credenciales intercambió el proxy, y una advertencia de fuga para cualquier token de estilo bearer que Bromure no haya acuñado. Ejecuta bromure-cli trace hostnames después de una sesión y cada host distinto que el agente contactó se imprime con una cuenta.

Si operas un espejo para tus agentes

Revisa la identidad con la que se autentican tus sandboxes, antes que el camino de red entre ellos. En Artifactory, busca Annotate en un token que consideras lector, y un permission target más amplio que los repositorios desde los que instala el sandbox. La API de propiedades es un plano de metadatos escribible; las reglas de retención, las etiquetas y la información de build son otros. Un lector que puede anotar puede publicar.

La regla que lo responde en una línea

En el panel Guardrails del espacio de trabajo, añade una regla de salida para el registro con el protocolo web y read-only en la columna Methods, luego pon Unmatched traffic en Deny y enumera lo que el trabajo necesita. El desglose en formato pf al pie del panel imprime lo que has construido: allow web registry.npmjs.org read-only, allow web api.github.com, default deny. Se aplica a sesiones en marcha sin reiniciar.

Un servicio compartido convierte a los inquilinos en vecinos

El instinto después de una historia como esta es revisar los muros. Los muros estaban bien. Dos contenedores bajo dos cuentas no tenían ruta el uno al otro, y Check Point no encontró ninguna. Encontraron un tercero con el que ambos contenedores tenían derecho a hablar, y lo usaron como la gente ha usado los discos compartidos y los registros DNS TXT durante treinta años.

Check Point enuncia la lección en el informe: “un servicio interno compartido, pensado puramente como infraestructura, puede convertirse en una capa de comunicación no intencionada entre entornos que se suponía que iban a permanecer aislados”. La infraestructura que instalas por seguridad sigue siendo infraestructura, y sus inquilinos se sientan a un salto de distancia. Encoge el conjunto de cosas en las que un sandbox tiene cuenta, y mueve la decisión sobre qué pueden hacer esas cuentas a cada petición, fuera de un ticket de provisión que alguien cerró hace dos años.

Un sandbox de agente que merezca la pena ejecutar tendrá un camino controlado hacia los paquetes que necesita, porque la alternativa es peor. Trata ese camino como una relación con permisos adjuntos, y trata esos permisos como tu perímetro. Decídelos en algún sitio donde todavía puedas verlos. Instala Bromure Agentic Coding y no le des a tu agente nada con lo que iniciar sesión.