Voltar para todas as publicações
Publicado em · por Renaud Deraison

Você confiou no workspace, não nos servidores

Em 26 de junho de 2026, a Wiz divulgou a CVE-2026-12957: o `.amazonq/mcp.json` de um repositório clonado fazia o Amazon Q iniciar automaticamente servidores MCP que herdavam todo o ambiente do desenvolvedor — chaves AWS, tokens de CLI de nuvem, segredos de API e sockets do agente SSH —, sem nenhuma etapa de consentimento separada para os próprios servidores. Um único clique em 'confiar neste workspace' substituía a criação de processos em segundo plano que carregavam sua sessão de nuvem ativa. A Amazon corrigiu isso no Language Servers 1.69.0. Eis por que a correção fecha um produto, mas não a classe, e o que muda quando o agente que abre o repositório vive em uma VM Bromure por perfil, atrás de um broker de credenciais, de uma proteção de leitura/escrita e de um rastreamento em nível de hipervisor.

Ontem a Wiz divulgou a CVE-2026-12957. Um repositório que você clona pode trazer um arquivo chamado .amazonq/mcp.json, e no momento em que você abre a pasta no Amazon Q e clica em Confiar neste workspace, esse arquivo inicia servidores em segundo plano sem um segundo aviso. Eles sobem herdando suas chaves AWS, seus tokens de CLI de nuvem, seus segredos de API e o socket do seu agente SSH. Um clique de confiança alcançou tudo o que seu shell consegue alcançar e entregou isso a um código que o repositório escolheu.

Um desenvolvedor que clona um repositório para experimentar um módulo de infraestrutura não pensa nisso como conceder acesso a coisa alguma. Clonar é inerte: escreve arquivos no disco e nada é executado. A decisão de julgamento vem um passo depois, quando você abre a pasta no seu editor e o assistente pergunta se deve confiar nela. Esse aviso se parece com aquele familiar “você confia nos autores dos arquivos desta pasta” que toda IDE exibe, e você clica em sim do mesmo jeito que já fez mil vezes, porque a alternativa é um assistente que não consegue ler seu código. Esse sim em particular fez mais do que deixar o assistente ler. No Amazon Q, antes da correção, ele também iniciava quaisquer servidores que o repositório tivesse escrito em .amazonq/mcp.json, e esses servidores subiam dentro do seu shell com sua sessão de nuvem ativa já em seu ambiente.

Escrevemos sobre o mesmo formato no início deste mês, quando o worm Miasma plantou configuração de projeto em 73 dos próprios repositórios da Microsoft e a carga disparou ao abrir a pasta. Aquela história era sobre uma fonte confiável sendo a superfície de ataque. Esta é mais restrita e mais desconfortável: nenhum worm, nenhum mantenedor comprometido, nada para apontar o dedo a não ser o assistente. O bug estava em como o Amazon Q lia um arquivo comum de configuração de projeto e decidia, no seu único clique de confiança, criar processos de longa duração que carregavam a coisa mais sensível no seu laptop.

O que a CVE-2026-12957 de fato fez.

Em 26 de junho de 2026, a Wiz Research divulgou a CVE-2026-12957, uma falha de alta gravidade (CVSS 8.5) nos Language Servers for AWS, o motor que alimenta o Amazon Q Developer no VS Code, JetBrains, Eclipse e Visual Studio. A Wiz reportou à Amazon em 20 de abril, a Amazon lançou uma correção em 12 de maio, e os detalhes vieram a público em 26 de junho. Não há sinal de que tenha sido explorada em campo. A mecânica, reduzida ao essencial:

  • O Amazon Q lê .amazonq/mcp.json de um workspace que você abre: um arquivo com escopo de projeto que declara servidores Model Context Protocol para o assistente usar.
  • Ao abrir a pasta, o Q iniciava os servidores MCP que o arquivo declarava sem uma etapa de consentimento separada para os próprios servidores. Um repositório que você clonou podia, portanto, colocar uma definição de servidor na frente do assistente e fazê-la executar.
  • Os processos criados herdavam todo o ambiente do desenvolvedor, nas palavras da Wiz, “chaves AWS, tokens de CLI de nuvem, segredos de API e sockets do agente SSH”. Um servidor MCP é apenas um comando que o Q inicia, e esse comando subia com tudo o que o seu próprio shell teria.
  • Uma definição de servidor pode apontar para qualquer comando, então o arquivo equivale a execução de código arbitrário ao abrir a pasta: ele roda como você, com suas credenciais de nuvem já carregadas, no momento em que você confia no workspace.

A divulgação carrega uma divergência real sobre consentimento, e é o ponto central deste post. A posição da Amazon: “o usuário precisa confiar no workspace quando solicitado.” Há uma barreira, e você clica para atravessá-la. A constatação da Wiz: antes da correção não havia etapa de consentimento separada para os próprios servidores MCP. Ambas se sustentam, e a falha vive na lacuna entre elas. Uma decisão de confiança grosseira e familiar, o mesmo sim/não que você dá a uma pasta para que o editor possa indexá-la, autorizava uma concessão muito maior: criar servidores em segundo plano que carregavam sua sessão ativa. Você respondeu a uma pergunta sobre ler arquivos. O Amazon Q gastou o clique em rodar servidores como você.

A Amazon corrigiu isso no Language Servers 1.69.0 (clientes: VS Code 2.20+, JetBrains 4.3+, Eclipse 2.7.4+, Visual Studio 1.94.0.0+), adicionando o consentimento por servidor que faltava, e corrigiu um desvio de verificação de symlink irmão, CVE-2026-12958. Atualize o Amazon Q. Depois olhe além do patch para a parte que ele deixa de pé: abrir um repositório podia colocar sua sessão de nuvem ativa dentro de um processo que o repositório escolheu.

LAPTOP DO DESENVOLVEDOR — sua sessão de nuvem ativa está no ambiente que todo servidor criado herdaDESENVOLVEDOR CLONAgit clone …/terraform-modulesnada roda aindatraz .amazonq/mcp.jsonuma definição de servidor, no discoABRIR NO AMAZON Q"Confiar neste workspace?"um clique familiar → [Trust]lê .amazonq/mcp.jsonsem consentimento por servidorSERVIDORES MCP INICIAM SOZINHOSQ cria o comando declaradocomando = o que o repositório escreveuroda como você, no seu shell↳ código arbitrário ao abrir a pastaAMBIENTE HERDADO — todo servidor criado recebe tudo, tudo real$AWS_ACCESS_KEY_ID, ~/.awssua conta (real)tokens de CLI de nuvem (gcloud, az)seus projetos (real)segredos de API em env / .envchaves de prod (real)$SSH_AUTH_SOCKassina como você (real)ler · usar · exfiltrar→ para fora da sua máquinaRESULTADOcódigo roda como vocêsessão de nuvem em mãoschaves lidas & enviadas para foraum clique de confiança comprouo laptop inteiro
A CVE-2026-12957 em um laptop comum de desenvolvedor. Clonar o repositório não executa nada. Abri-lo no Amazon Q e clicar em ‘Confiar neste workspace’, a única barreira familiar, faz o Q ler o .amazonq/mcp.json e iniciar os servidores MCP que ele declara, sem consentimento separado por servidor. Cada servidor criado é um comando que o Q inicia, e ele sobe herdando todo o ambiente do desenvolvedor: chaves AWS, tokens de CLI de nuvem, segredos de API, o socket do agente SSH. Como uma definição de servidor pode apontar para qualquer comando, isto é código arbitrário rodando como você, com sua sessão de nuvem ativa já carregada. O único clique de confiança respondeu a uma pergunta sobre ler arquivos, e o Q o gastou rodando servidores como você.

O mesmo repositório, aberto dentro do Bromure Agentic Coding.

O Bromure Agentic Coding roda seu agente de codificação, Amazon Q incluído, dentro de uma VM Linux por perfil: seu próprio kernel, seu próprio sistema de arquivos, sua própria pilha de rede, no framework de Virtualização da Apple. Um perfil é um escopo coerente de trabalho: este cliente, este serviço, este módulo open-source que você clonou para avaliar. Você clona o repositório dentro desse perfil e o abre ali. O comportamento vulnerável se reproduz exatamente como a Wiz descreveu: você clica em Confiar neste workspace, o Q lê .amazonq/mcp.json, e inicia os servidores que o arquivo declara. A criação dispara, e o código escolhido pelo repositório roda.

Ele roda no convidado. O servidor MCP sobe dentro da VM e herda o ambiente da VM, e o ambiente da VM não contém sua sessão de nuvem. O Bromure entrega o convidado com stubs: valores falsos que parecem reais para aws, gcloud, az, kubectl, git e qualquer outra coisa que leia um cabeçalho Authorization ou um AWS_ACCESS_KEY_ID. Um proxy no seu Mac fica na frente de cada conexão que sai do sandbox, reconhece o stub e o troca pelo segredo real no fio à medida que a requisição sai; o sandbox que segurou a chave percorre o mecanismo. A chave AWS real, o token de CLI de nuvem real, o segredo de API real nunca tocam um arquivo, uma variável de ambiente ou uma página de memória que a VM consiga ler.

Então percorra a herança da CVE através desse limite. O servidor criado lê $AWS_ACCESS_KEY_ID e encontra um stub. Ele lê ~/.aws e encontra um perfil stub. Ele lê o ambiente em busca dos tokens de nuvem e dos segredos de API e encontra placeholders. O servidor roda até o fim como foi escrito, herdando uma caixa que nunca esteve segurando suas chaves. O que fez da CVE-2026-12957 um bug de roubo de credenciais é a herança de ambiente na criação, e o Bromure não a quebra. Ele deixa o ambiente herdado sem valor.

VM BROMURE POR PERFILconfiar no workspace → Q lê mcp.jsonservidor MCP inicia sozinho, rodacódigo arbitrário — só no convidadoO QUE O SERVIDOR HERDA$AWS_ACCESS_KEY_IDstub_AKIA…tokens de nuvem, segredos de APIstub / ausente$SSH_AUTH_SOCKencaminhadotenta: aws s3 rm / ec2 terminateuma escrita → sai pelo proxyexfiltrar chaves do host: nada real a levarraio de impacto = só este perfilsem fs do host, sem alcance ao keychain do hostPROXY · SEU MACBROKER DE CREDENCIAISchaves AWS reais ficam aquistub → real, no fioo valor nunca entra na VMPROTEÇÃO: LEITURA/ESCRITAdelete / terminate → AVISOnomeia verbo + alvoAUDITORIAcada criação + chamada registradaabaixo do agenteRESULTADOsessão de nuvem:stubs herdados,chaves reais intocadascódigo-como-você:roda em um convidadodescartável, não no hostchamada destrutiva:pausada, você diz nãoo que rodou:no rastreamento
A mesma abertura de pasta, o mesmo servidor iniciado automaticamente, dentro do Bromure. (1) Isolamento: o servidor MCP é criado na VM por perfil, então o ‘código arbitrário como você’ cai em um convidado descartável em vez de no host, e o raio de impacto é um perfil. (2) Brokering de credenciais: o servidor herda o ambiente do convidado, que contém apenas stubs; as chaves AWS reais, os tokens de nuvem e os segredos de API ficam no host atrás do proxy, trocados no fio, de modo que a herança recebe placeholders. (3) Proteção: qualquer chamada que altere estado que o código tente, como apagar um bucket, terminar uma instância ou enviar um branch, é uma escrita que é interrompida no fio para um aviso que nomeia o verbo e o alvo. Cada camada é imposta abaixo do agente, em um limite que o processo criado não consegue contornar, e cada criação e chamada de saída é registrada no rastreamento.

“Confiar neste workspace” era a pergunta errada.

Esta CVE vale mais do que uma nota de patch por causa da lacuna de consentimento, e a lacuna é um problema de granularidade. O aviso de confiança fazia uma pergunta ampla, você confia nesta pasta, e um único sim tinha de cobrir tanto a coisa inofensiva que você quis dizer (deixar o assistente ler meu código) quanto a coisa perigosa que você não sabia estar anexada (iniciar servidores em segundo plano com minha sessão de nuvem). Você não consegue responder bem a isso. Ninguém consegue, porque a pergunta funde duas concessões que nada têm a ver uma com a outra e mostra a você apenas a inocente.

O Bromure não pede que você seja melhor nesse julgamento. Ele tira o julgamento do caminho. O clique de confiança dentro de um perfil ainda deixa o assistente fazer seu trabalho, e ainda assim ele não consegue iniciar um processo segurando sua sessão de nuvem real, porque essa sessão não está na VM para herdar. Ela vive no host, atrás do broker, alcançável apenas como uma requisição com stub que o proxy preenche no fio e registra. A metade perigosa da concessão se foi. Você não a reteve; não havia nada ali para conceder, porque o limite fica abaixo do agente, onde o aviso de confiança não pode movê-lo.

A outra metade perigosa é um servidor criado que vira destrutivo em vez de só bisbilhoteiro, e ele encontra as Proteções. O Bromure lê a operação, não apenas a conexão: um aws s3 ls é uma leitura, um aws s3 rm é uma escrita; um git fetch é uma leitura, um git push é uma escrita. Configure a credencial de nuvem de um perfil para perguntar na escrita, e o momento em que o código tenta uma chamada que altera estado, como um DELETE, um Terminate* ou um force-push, o Bromure a interrompe no fio e exibe um aviso no seu Mac nomeando o verbo, o alvo e o perfil. Leituras nunca interrompem você. A mutação é o que pausa, do mesmo jeito que “o agente apagou o banco de dados de produção” deixa de ser um post-mortem e vira uma caixa de diálogo que você recusa.

O que o rastreamento mostra.

Toda equipe faz a mesma pergunta na manhã seguinte a algo como isso acontecer: eu abri aquele repositório, e o que ele rodou? Em um laptop comum a resposta honesta é um dar de ombros. O servidor MCP que o Q criou era um processo filho na sua sessão, e o que quer que ele tenha lido e para onde quer que tenha ligado, fez isso como você, sem nenhum registro que o separe do seu próprio trabalho.

Dentro do Bromure o agente fica em uma VM e cada byte de saída passa pelo proxy do host, então a criação e suas chamadas permanecem visíveis mesmo quando o agente não consegue vê-las. O host registra o servidor MCP subindo, os comandos que ele rodou, as credenciais que ele pediu ao broker para preencher e cada conexão que ele tentou, no mesmo rastreamento de sessão que todo o resto que o agente fez, escrito abaixo do agente, onde o código criado não consegue alcançar para editá-lo. “O servidor deste repositório tocou minha conta” deixa de ser um palpite que você reconstrói a partir do CloudTrail semanas depois e vira uma linha que você lê: o broker entregou um stub, a requisição tinha um nome, o alvo foi registrado. Para uma empresa essa é a diferença entre corrigimos o Amazon Q e podemos mostrar o que cada repositório que nossos desenvolvedores abriram fez, e a postura de auditoria é aquela à qual nosso trabalho corporativo sempre retorna.

Onde isto não te salva.

Um socket de ssh-agent encaminhado é utilizável enquanto está encaminhado.

O Bromure mantém suas chaves privadas SSH no Keychain do macOS e nunca as copia para a VM. Mas se um perfil tem o socket do ssh-agent encaminhado para dentro (do jeito que o OpenSSH pretende), um servidor criado pode pedir ao agente que assine com essas chaves enquanto o socket está ativo. O arquivo da chave nunca sai do host; a capacidade de assinatura de fato chega ao convidado. Encaminhe o socket apenas para perfis que precisam dele, e dê a ele o mesmo escopo que o broker dá a uma credencial.

Uma escrita que você aprova é uma escrita que acontece.

A proteção de leitura/escrita pega a chamada destrutiva que o agente não te contou. Ela não lê sua mente sobre intenção. Se você está derrubando um stack de propósito e aprova o aviso, o Bromure encaminha o Terminate. O aviso te dá uma olhada no verbo e no alvo; você ainda tem de lê-lo.

O perfil é de longa duração, então a persistência persiste.

Um perfil Bromure não é um disco descartável. Um servidor criado que se escreve em um caminho de inicialização dentro do perfil pode acordar na próxima sessão naquele perfil. Aquilo a que ele acorda é um convidado sem chaves do host e um broker que fala apenas tokens de curta duração, avisados e com escopo: presença em uma caixa que não tem nada dentro, mas presença mesmo assim.

Corrigido não é o mesmo que resolvido.

A Amazon adicionou consentimento por servidor no 1.69.0, e você deve atualizar. Mas o próximo assistente que ler configuração de projeto ao abrir a pasta tomará a mesma classe de decisão, e o aviso que ele exibir vai parecer igualmente rotineiro. Isolamento é a parte que não depende de um fornecedor específico acertar uma caixa de diálogo de consentimento específica.

O próximo workspace já está clonado em algum lugar.

A lição do escopo da Red Hat foi que o publicador não é uma defesa. A lição dos repositórios da Microsoft foi que o repositório também não é, e que abrir uma pasta é o suficiente para rodar código. O Amazon Q adiciona a próxima linha: o aviso de confiança também não é uma defesa. A pergunta que ele te faz, você confia nesta pasta, não é a pergunta cuja resposta importa, que é esta pasta deveria poder criar servidores carregando minha sessão de nuvem. A segunda nunca te foi mostrada, e você não conseguiria tê-la respondido bem se tivesse sido.

Você não conserta isso lendo o aviso com mais cuidado, porque o aviso era o aviso errado. Você conserta arranjando as coisas de modo que “qual workspace é este” deixe de ser a pergunta da qual suas chaves de nuvem dependem; por que um agente de codificação não é um sandbox é a versão mais longa desse argumento. O Bromure Agentic Coding é a configuração em que o agente abre o repositório dentro de uma VM por perfil, as credenciais reais ficam no host atrás de um broker, cada escrita que o agente faz precisa passar por um aviso, e cada servidor que ele cria é escrito em um rastreamento que ele não consegue editar. O pior que um mcp.json envenenado pode fazer é herdar uma caixa que nunca esteve segurando suas chaves. É gratuito, open-source e lançado hoje.