Volver a todas las publicaciones
Publicado el · por Renaud Deraison

Confiaste en el espacio de trabajo, no en los servidores

El 26 de junio de 2026, Wiz reveló la CVE-2026-12957: el `.amazonq/mcp.json` de un repositorio clonado hacía que Amazon Q lanzara automáticamente servidores MCP que heredaban el entorno completo del desarrollador con claves de AWS, tokens de CLI de la nube, secretos de API y sockets del agente SSH, sin ningún paso de consentimiento aparte para los propios servidores. Un único clic de “confiar en este espacio de trabajo” sustituía al hecho de generar procesos en segundo plano que llevaban tu sesión de nube en vivo. Amazon lo parcheó en Language Servers 1.69.0. Aquí está por qué la corrección cierra un producto pero no la clase, y qué cambia cuando el agente que abre el repositorio vive en una VM de Bromure por perfil, detrás de un intermediario de credenciales, una barrera de lectura-escritura y un rastro a nivel de hipervisor.

Ayer Wiz reveló la CVE-2026-12957. Un repositorio que clonas puede incluir un archivo llamado .amazonq/mcp.json, y en el momento en que abres la carpeta en Amazon Q y haces clic en Confiar en este espacio de trabajo, ese archivo lanza servidores en segundo plano sin un segundo aviso. Aparecen heredando tus claves de AWS, tus tokens de CLI de la nube, tus secretos de API y tu socket del agente SSH. Un clic de confianza alcanzó todo lo que tu shell puede alcanzar, y se lo entregó al código que el repositorio eligió.

Un desarrollador que clona un repositorio para probar un módulo de infraestructura no piensa en ello como concederle acceso a nada. Clonar es inerte: escribe archivos en el disco y nada se ejecuta. La decisión llega un paso después, cuando abres la carpeta en tu editor y el asistente pregunta si confías en ella. Ese aviso se lee como la familiar puerta de “¿confías en los autores de los archivos de esta carpeta?” que muestra cada IDE, y haces clic en sí como lo has hecho mil veces, porque la alternativa es un asistente que no puede leer tu código. Este sí en particular hizo más que dejar leer al asistente. En Amazon Q, antes de la corrección, también lanzaba cualquier servidor que el repositorio hubiera escrito en .amazonq/mcp.json, y esos servidores aparecían dentro de tu shell con tu sesión de nube en vivo ya en su entorno.

Escribimos sobre la misma forma a principios de este mes, cuando el gusano Miasma plantó configuración de proyecto en 73 de los propios repositorios de Microsoft y la carga útil se disparó al abrir la carpeta. Aquella historia trataba de que una fuente de confianza fuera la superficie de ataque. Esta es más acotada y más incómoda: ningún gusano, ningún mantenedor comprometido, nada a lo que señalar salvo el asistente. El fallo estaba en cómo Amazon Q leía un archivo corriente de configuración de proyecto y decidía, con tu único clic de confianza, generar procesos de larga duración que llevaban lo más sensible de tu portátil.

Qué hizo realmente la CVE-2026-12957.

El 26 de junio de 2026, Wiz Research reveló la CVE-2026-12957, un fallo de alta gravedad (CVSS 8.5) en los Language Servers for AWS, el motor que impulsa Amazon Q Developer en VS Code, JetBrains, Eclipse y Visual Studio. Wiz lo reportó a Amazon el 20 de abril, Amazon publicó una corrección el 12 de mayo, y los detalles se hicieron públicos el 26 de junio. No hay indicios de que se haya explotado en la naturaleza. La mecánica, reducida a lo esencial:

  • Amazon Q lee .amazonq/mcp.json de un espacio de trabajo que abres: un archivo con alcance de proyecto que declara servidores del Model Context Protocol para que los use el asistente.
  • Al abrir la carpeta, Q lanzaba los servidores MCP que ese archivo declaraba sin un paso de consentimiento aparte para los propios servidores. Por tanto, un repositorio que clonaste podía poner una definición de servidor delante del asistente y hacer que se ejecutara.
  • Los procesos generados heredaban el entorno completo del desarrollador, en palabras de Wiz, “claves de AWS, tokens de CLI de la nube, secretos de API y sockets del agente SSH”. Un servidor MCP no es más que un comando que Q inicia, y ese comando aparecía con todo lo que tendría tu propio shell.
  • Una definición de servidor puede apuntar a cualquier comando, así que el archivo equivale a ejecución de código arbitrario al abrir la carpeta: se ejecuta como tú, con tus credenciales de la nube ya cargadas, en el momento en que confías en el espacio de trabajo.

La revelación lleva consigo un desacuerdo real sobre el consentimiento, y es el quid de esta publicación. La postura de Amazon: “el usuario tiene que confiar en el espacio de trabajo cuando se le pide.” Hay una puerta, y la atraviesas con un clic. El hallazgo de Wiz: antes de la corrección no había un paso de consentimiento aparte para los propios servidores MCP. Ambos se sostienen, y el fallo vive en la brecha entre ellos. Una decisión de confianza tosca y familiar, el mismo sí/no que le das a una carpeta para que el editor la indexe, autorizaba una concesión mucho mayor: generar servidores en segundo plano que llevaban tu sesión en vivo. Respondiste a una pregunta sobre leer archivos. Amazon Q gastó el clic en ejecutar servidores como tú.

Amazon lo corrigió en Language Servers 1.69.0 (clientes: VS Code 2.20+, JetBrains 4.3+, Eclipse 2.7.4+, Visual Studio 1.94.0.0+), añadiendo el consentimiento por servidor que faltaba, y parcheó un bypass hermano de comprobación de enlaces simbólicos, CVE-2026-12958. Actualiza Amazon Q. Luego mira más allá del parche a la parte que deja en pie: abrir un repositorio podía poner tu sesión de nube en vivo dentro de un proceso que el repositorio eligió.

PORTÁTIL DEL DESARROLLADOR — tu sesión de nube en vivo está en el entorno que hereda cada servidor generadoEL DESARROLLADOR CLONAgit clone …/terraform-modulesnada se ejecuta aúnincluye .amazonq/mcp.jsonuna definición de servidor, en discoABRIR EN AMAZON Q"¿Confiar en este espacio?"un clic familiar → [Trust]lee .amazonq/mcp.jsonsin consentimiento por servidorLOS SERVIDORES MCP SE AUTOLANZANQ genera el comando declaradocomando = lo que escribió el repose ejecuta como tú, en tu shell↳ código arbitrario al abrir la carpetaENTORNO HEREDADO — cada servidor generado lo recibe todo, todo real$AWS_ACCESS_KEY_ID, ~/.awstu cuenta (real)tokens de CLI de la nube (gcloud, az)tus proyectos (real)secretos de API en env / .envclaves de prod (real)$SSH_AUTH_SOCKfirma como tú (real)leer · usar · exfiltrar→ fuera de tu máquinaRESULTADOel código se ejecuta como túsesión de nube en manoclaves leídas y enviadas fueraun clic de confianza comprótodo el portátil
La CVE-2026-12957 en un portátil de desarrollador normal. Clonar el repositorio no ejecuta nada. Al abrirlo en Amazon Q y hacer clic en “Confiar en este espacio de trabajo”, la única puerta familiar, Q lee .amazonq/mcp.json y lanza los servidores MCP que declara, sin un consentimiento aparte por servidor. Cada servidor generado es un comando que Q inicia, y aparece heredando el entorno completo del desarrollador: claves de AWS, tokens de CLI de la nube, secretos de API, el socket del agente SSH. Como una definición de servidor puede apuntar a cualquier comando, esto es código arbitrario ejecutándose como tú, con tu sesión de nube en vivo ya cargada. El único clic de confianza respondió a una pregunta sobre leer archivos, y Q lo gastó en ejecutar servidores como tú.

El mismo repositorio, abierto dentro de Bromure Agentic Coding.

Bromure Agentic Coding ejecuta tu agente de programación, Amazon Q incluido, dentro de una VM de Linux por perfil: su propio kernel, su propio sistema de archivos, su propia pila de red, sobre el framework de Virtualización de Apple. Un perfil es un ámbito de trabajo coherente: este cliente, este servicio, este módulo de código abierto que clonaste para evaluar. Clonas el repositorio en ese perfil y lo abres ahí. El comportamiento vulnerable se reproduce tal como lo describió Wiz: haces clic en Confiar en este espacio de trabajo, Q lee .amazonq/mcp.json, y lanza los servidores que el archivo declara. La generación se dispara, y se ejecuta código de la elección del repositorio.

Se ejecuta en el invitado. El servidor MCP aparece dentro de la VM y hereda el entorno de la VM, y el entorno de la VM no contiene tu sesión de nube. Bromure entrega el invitado con stubs: valores falsos que parecen reales para aws, gcloud, az, kubectl, git, y cualquier otra cosa que lea una cabecera Authorization o un AWS_ACCESS_KEY_ID. Un proxy en tu Mac se sitúa delante de cada conexión que sale del sandbox, reconoce el stub y lo intercambia por el secreto real en el cable a medida que sale la solicitud; el sandbox que guardaba la clave recorre el mecanismo. La clave de AWS real, el token de CLI de la nube real, el secreto de API real nunca tocan un archivo, una variable de entorno ni una página de memoria que la VM pueda leer.

Así que recorre la herencia de la CVE a través de esa frontera. El servidor generado lee $AWS_ACCESS_KEY_ID y encuentra un stub. Lee ~/.aws y encuentra un perfil stub. Lee el entorno en busca de los tokens de la nube y los secretos de API y encuentra marcadores de posición. El servidor se ejecuta hasta el final tal como está escrito, heredando una caja que nunca contuvo tus claves. Lo que convirtió a la CVE-2026-12957 en un fallo de robo de credenciales es la herencia de entorno al generar, y Bromure no la rompe. Deja sin valor el entorno heredado.

VM DE BROMURE POR PERFILconfiar espacio → Q lee mcp.jsonel servidor MCP se autolanza, correcódigo arbitrario — solo en el invitadoLO QUE HEREDA EL SERVIDOR$AWS_ACCESS_KEY_IDstub_AKIA…tokens de la nube, secretos de APIstub / ausente$SSH_AUTH_SOCKreenviadointenta: aws s3 rm / ec2 terminateuna escritura → sale por el proxyexfil de claves del host: nada real que tomarradio de impacto = este único perfilsin fs del host, sin acceso al llavero del hostPROXY · TU MACINTERMEDIARIO DE CREDENCIALESclaves de AWS reales aquístub → real, en el cableel valor nunca entra en la VMBARRERA: LECTURA/ESCRITURAborrar / terminar → AVISOnombra verbo + objetivoAUDITORÍAcada generación + llamada registradapor debajo del agenteRESULTADOsesión de nube:stubs heredados,claves reales intactascódigo-como-tú:corre en un invitadodesechable, no el hostllamada destructiva:en pausa, dices que nolo que corrió:en el rastro
La misma apertura de carpeta, el mismo servidor autolanzado, dentro de Bromure. (1) Aislamiento: el servidor MCP se genera en la VM por perfil, así que el “código arbitrario como tú” aterriza en un invitado desechable en lugar de en el host, y el radio de impacto es un solo perfil. (2) Intermediación de credenciales: el servidor hereda el entorno del invitado, que solo contiene stubs; las claves de AWS, los tokens de la nube y los secretos de API reales se quedan en el host detrás del proxy, intercambiados en el cable, así que la herencia toma marcadores de posición. (3) Barrera: cualquier llamada que cambie el estado que el código intente, como borrar un bucket, terminar una instancia o subir una rama, es una escritura que se detiene en el cable para un aviso que nombra el verbo y el objetivo. Cada capa se aplica por debajo del agente, en una frontera que el proceso generado no puede rodear, y cada generación y llamada saliente se escribe en el rastro.

“Confiar en este espacio de trabajo” era la pregunta equivocada.

Esta CVE vale más que una nota de parche por la brecha de consentimiento, y la brecha es un problema de granularidad. El aviso de confianza hacía una pregunta amplia, ¿confías en esta carpeta?, y un único sí tenía que cubrir tanto lo inofensivo que querías (dejar que el asistente lea mi código) como lo peligroso que no sabías que iba adjunto (lanzar servidores en segundo plano con mi sesión de nube). No puedes responder bien a eso. Nadie puede, porque la pregunta fusiona dos concesiones que no tienen nada que ver entre sí y solo te muestra la inocente.

Bromure no te pide ser mejor en ese juicio. Saca el juicio del camino. El clic de confianza dentro de un perfil sigue permitiendo que el asistente haga su trabajo, y sigue sin poder lanzar un proceso que contenga tu sesión de nube real, porque esa sesión no está en la VM para heredarse. Vive en el host, detrás del intermediario, alcanzable solo como una solicitud con stub que el proxy rellena en el cable y registra. La mitad peligrosa de la concesión se ha ido. No la retuviste; no había nada ahí que conceder, porque la frontera se sitúa por debajo del agente, donde el aviso de confianza no puede moverla.

La otra mitad peligrosa es un servidor generado que se vuelve destructivo en lugar de solo fisgón, y se topa con las Barreras. Bromure lee la operación, no solo la conexión: un aws s3 ls es una lectura, un aws s3 rm es una escritura; un git fetch es una lectura, un git push es una escritura. Configura la credencial de nube de un perfil para que pregunte al escribir, y en el momento en que el código intenta una llamada que cambia el estado, como un DELETE, un Terminate* o un force-push, Bromure la detiene en el cable y hace aparecer un aviso en tu Mac que nombra el verbo, el objetivo y el perfil. Las lecturas nunca te interrumpen. Lo que pausa es la mutación, del mismo modo en que “el agente borró la base de datos de producción” deja de ser un análisis post mortem y se convierte en un cuadro de diálogo que rechazas.

Qué muestra el rastro.

Cada equipo se hace la misma pregunta la mañana después de que algo así aterrice: ¿abrí ese repositorio y qué ejecutó? En un portátil normal la respuesta honesta es encogerse de hombros. El servidor MCP que Q generó era un proceso hijo en tu sesión, y lo que leyera y a donde llamara, lo hizo como tú, sin ningún registro que lo separe de tu propio trabajo.

Dentro de Bromure el agente se sitúa en una VM y cada byte saliente pasa por el proxy del host, así que la generación y sus llamadas siguen siendo visibles incluso cuando el agente no puede verlas. El host registra el arranque del servidor MCP, los comandos que ejecutó, las credenciales que pidió al intermediario que rellenara y cada conexión que intentó, en el mismo rastro de sesión que todo lo demás que hizo el agente, escrito por debajo del agente donde el código generado no puede alcanzarlo para editarlo. “¿El servidor de este repositorio tocó mi cuenta?” deja de ser una conjetura que reconstruyes a partir de CloudTrail semanas después y se convierte en una fila que lees: el intermediario entregó un stub, la solicitud tenía un nombre, el objetivo quedó registrado. Para una empresa esa es la diferencia entre parcheamos Amazon Q y podemos mostrar lo que hizo cada repositorio que abrieron nuestros desarrolladores, y la postura de auditoría es a la que nuestro trabajo para empresas sigue volviendo.

Dónde esto no te salva.

Un socket de ssh-agent reenviado es utilizable mientras está reenviado.

Bromure mantiene tus claves privadas SSH en el Keychain de macOS y nunca las copia dentro de la VM. Pero si un perfil tiene el socket de ssh-agent reenviado (como pretende OpenSSH), un servidor generado puede pedirle al agente que firme con esas claves mientras el socket está activo. El archivo de la clave nunca sale del host; la capacidad de firmar sí llega al invitado. Reenvía el socket solo a los perfiles que lo necesiten, y acótalo igual que el intermediario acota una credencial.

Una escritura que apruebas es una escritura que ocurre.

La barrera de lectura-escritura atrapa la llamada destructiva que el agente no te contó. No te lee la mente sobre la intención. Si estás desmontando una pila a propósito y apruebas el aviso, Bromure reenvía el Terminate. El aviso te compra una mirada al verbo y al objetivo; aun así tienes que leerlo.

El perfil es de larga duración, así que la persistencia persiste.

Un perfil de Bromure no es un disco desechable. Un servidor generado que se escribe a sí mismo en una ruta de arranque dentro del perfil puede despertar en la siguiente sesión de ese perfil. A lo que despierta es a un invitado sin claves del host y un intermediario que solo habla con tokens de corta duración, con aviso y acotados: presencia en una caja sin nada dentro, pero presencia al fin y al cabo.

Parcheado no es lo mismo que resuelto.

Amazon añadió el consentimiento por servidor en 1.69.0, y deberías actualizar. Pero el próximo asistente que lea la configuración de proyecto al abrir la carpeta tomará la misma clase de decisión, y el aviso que muestre se verá igual de rutinario. El aislamiento es la parte que no depende de que un proveedor concreto acierte con un cuadro de diálogo de consentimiento concreto.

El próximo espacio de trabajo ya está clonado en algún sitio.

La lección del alcance de Red Hat fue que el editor no es una defensa. La lección de los repositorios de Microsoft fue que el repositorio tampoco lo es, y que abrir una carpeta basta para ejecutar código. Amazon Q añade la siguiente línea: el aviso de confianza tampoco es una defensa. La pregunta que te plantea, ¿confías en esta carpeta?, no es la pregunta cuya respuesta importa, que es ¿debería esta carpeta poder generar servidores que llevan mi sesión de nube?. Nunca te mostraron la segunda, y no habrías podido responderla bien aunque lo hubieran hecho.

Eso no se arregla leyendo el aviso con más cuidado, porque el aviso era el aviso equivocado. Se arregla disponiendo las cosas de modo que “¿qué espacio de trabajo es este?” deje de ser la pregunta de la que penden tus claves de la nube; por qué un agente de programación no es un sandbox es la versión más larga de ese argumento. Bromure Agentic Coding es la configuración donde el agente abre el repositorio dentro de una VM por perfil, las credenciales reales se quedan en el host detrás de un intermediario, cada escritura que hace el agente tiene que superar un aviso, y cada servidor que genera se escribe en un rastro que no puede editar. Lo peor que puede hacer un mcp.json envenenado es heredar una caja que nunca contuvo tus claves. Es gratuito, de código abierto, y disponible hoy.