O symlink saiu do workspace, e não encontrou nada que valesse levar
O GhostApproval mostrou como um repositório hostil pode enganar seis assistentes de codificação com IA para que escrevam e leiam arquivos fora da pasta em que deveriam ficar: plantando chaves SSH, sequestrando a inicialização do shell e lendo credenciais de nuvem na própria máquina do desenvolvedor. O bug é um erro de resolução de symlink. O motivo de ele doer é que o agente roda em uma máquina cheia dos seus segredos. O Bromure Agentic Coding muda esse segundo fato.
Um agente de codificação é um programa que você convida a ler e escrever arquivos no seu laptop. O GhostApproval é a história do que acontece quando um repositório hostil convence esse programa a escrever um pouco fora das linhas: nas suas chaves SSH, na configuração do seu shell, nas suas credenciais de nuvem. O bug é velho e sem graça. O estrago vem de onde o agente estava parado.
Em 8 de julho de 2026, a equipe de pesquisa da Wiz publicou o GhostApproval, um relato da mesma falha encontrada, em seis formas diferentes, em seis assistentes de codificação com IA populares: Amazon Q Developer, Claude Code da Anthropic, Augment, Cursor, Antigravity do Google e Windsurf. Os detalhes variam por produto. A forma, não. Você abre um repositório, talvez um tutorial que alguém linkou ou um projeto que um colega pediu para você olhar, e aponta seu agente de codificação para ele. Em algum lugar desse repositório há um arquivo que não é um arquivo.
Um arquivo que não é um arquivo.
O truque é um link simbólico, ou symlink: uma entrada do sistema de arquivos que parece um arquivo, mas é uma placa apontando para algum outro caminho. Symlinks são um recurso normal do Unix, com quarenta anos de idade. O problema de segurança, catalogado como CWE-61, é quase tão velho: um programa que abre um symlink sem verificar para onde ele aponta deixa um atacante guiá-lo até um arquivo que o autor nunca pretendeu.
No GhostApproval, um repositório malicioso traz um symlink com nome de
aparência inocente, digamos project_settings.json. Em vez de
configurações, ele guarda um ponteiro para ~/.ssh/authorized_keys, ou
~/.zshrc, ou ~/.aws/credentials, no diretório home do desenvolvedor,
bem fora da pasta do repositório. Um README, ou o usuário agindo
segundo as instruções do repo, então pede ao agente para "atualizar o
project_settings.json". O agente segue a placa sem resolver aonde ela
leva, e escreve no alvo real.
Duas coisas fazem disso mais que uma curiosidade. A primeira é o que os
alvos fazem. Acrescentar uma linha a ~/.ssh/authorized_keys instala a
chave de um atacante para SSH sem senha na sua máquina. Escrever em
~/.zshrc roda o comando do atacante toda vez que você abre um
terminal. O agente da Augment nem precisou escrever: perguntado sobre
"chaves AWS no projeto", ele percorreu um symlink até um arquivo de
credenciais e imprimiu os segredos no chat, sem prompt algum.
A segunda é uma falha mais sutil, que a Wiz classifica como
CWE-451, deturpação
da interface do usuário. Com o Claude Code, o próprio raciocínio interno
do agente reconheceu o arquivo como uma config de shell, e o diálogo de
confirmação ainda assim perguntou apenas "Fazer esta edição em
project_settings.json?". O único momento em que um humano poderia ter
pegado o perigo mostrou ao humano a informação errada. Windsurf e
Amazon Q Developer estavam piores: escreviam o arquivo no disco antes
de mostrar os botões de aprovação, então o diálogo era um prompt de
desfazer, não um portão. A chave SSH do atacante já estava no lugar.
A maioria dos fornecedores já corrigiu sua variante: o Cursor na v3.0 (CVE-2026-50549), o Amazon Q no language-server 1.69.0 (CVE-2026-12958), o Google no Antigravity v1.19.6, o Claude Code com um aviso de resolução de symlink. Essa é a resposta certa, e você deve aplicar as atualizações. Mas remendar o tratamento de symlinks de cada produto conserta o mecanismo e deixa o que está em jogo onde estava.
O que está em jogo depende de onde o agente está.
Cada um desses payloads assume a mesma coisa: que alcançar o diretório
home do desenvolvedor vale o esforço. Que ~/.ssh guarda uma chave que
abre uma máquina real, ~/.aws/credentials guarda um token de nuvem
vivo, e ~/.zshrc roda em um shell que você vai abrir amanhã. O symlink
é a estrada. O destino é um laptop com toda a sua vida de trabalho
dentro.
A maioria dos ataques a agentes de codificação repousa sobre a mesma suposição. O agente é um programa capaz e aberto que lê entrada não confiável (repositórios, páginas web, tarballs de pacotes, saída de ferramentas) e executa ações em uma máquina onde suas credenciais ficam em arquivos comuns, a alguns diretórios de distância. Endureça o agente o quanto quiser; ele compartilha um sistema de arquivos e um chaveiro com tudo o mais que você roda. Atacantes vão continuar pavimentando estradas novas. O destino é o problema.
O Bromure Agentic Coding remove o destino. O agente, os shells que ele gera, os repositórios que ele clona e qualquer código dentro deles rodam dentro de uma VM Linux por perfil: uma máquina separada que o hypervisor isola do seu Mac. Suas credenciais reais nunca entram nela. Escrevemos sobre por que uma fronteira vence uma jaula em por que o Bromure Agentic Coding não é um sandbox; o GhostApproval é um teste limpo da ideia, porque ele escapa da pasta do workspace, a única pequena fronteira em que a indústria estava se apoiando.
Trace o mesmo escape dentro da VM. O symlink ainda resolve (o Bromure
nunca precisa detectar ou bloquear o truque) e a escrita ainda cai em
~/.ssh/authorized_keys. Mas esse arquivo vive no diretório home do
convidado, em uma máquina descartável que não tem rota para o seu Mac.
A chave do atacante agora concede login a uma máquina que você vai jogar
fora, uma que, para começar, nunca foi alcançável de fora.
A variante de roubo de credenciais é ainda mais anticlimática. Quando um
agente comprometido percorre um symlink até ~/.aws/credentials e
imprime o conteúdo no chat, ele lê um stub: um arquivo de
credenciais bem formado cujas chaves não autenticam em nada. Os tokens
reais ficam no host, atrás de um broker que troca o placeholder pelo
segredo real apenas no momento de uma chamada de saída que você
permitiu, e o troca de volta para fora da resposta. Uma dependência ou
um agente enganado que varre o sistema de arquivos em busca de segredos
encontra mobília.
O prompt, e a segunda rede.
O Bromure enfrenta as duas arestas mais afiadas do GhostApproval em camadas diferentes.
A primeira é o problema do prompt de confirmação, o CWE-451: o diálogo
que dizia project_settings.json enquanto o agente sabia que
significava ~/.zshrc. O Bromure dispensa o diálogo de escrita de
arquivo; escritas dentro da VM descartável tocam um disco dispensável e
não precisam de aprovação. Em vez disso, o Bromure insere o humano na
fronteira real, para as chamadas que alteram estado e saem da VM: um
git push, um DROP de banco de dados, um Terminate de nuvem. Essas
pausam no host e mostram a você a operação literal, não um resumo
escrito pelo agente. É o mesmo princípio que o GhostApproval violou,
aplicado onde importa: o momento em que uma decisão tem consequências
fora do sandbox é o momento em que um humano deve ver a chamada real.
A segunda aresta é a instrução que inicia o ataque inteiro: um
README mandando o agente "atualizar o project_settings.json", que o
modelo lê como contexto e obedece como ordem. O Bromure lê esse conteúdo
não confiável primeiro, no dispositivo: um classificador local pontua
arquivos que chegam, buscas na web e saída de ferramentas em busca de
instruções que não têm nada que estar ali, e os arquivos de regras que
um agente trata como ordens permanentes recebem um exame mais severo. O
classificador vai deixar passar algumas formulações, e o isolamento
derrota este ataque sozinho; trate-o como uma segunda rede sob a
primeira.
Onde a linha não salva você.
O isolamento é uma forma específica, e a forma tem arestas.
Um perfil vive muito, então a persistência persiste.
O payload no ~/.zshrc vai rodar na próxima vez que um shell abrir
dentro da VM daquele perfil. Ele roda em um convidado sem chaves do
host e só com credenciais stub, um shell em uma sala vazia, mas roda.
Se isso preocupa você em uma dada tarefa, rode-a em um perfil novo.
O que você monta, você expõe.
A VM não guarda nada seu por padrão. Se você deliberadamente montar um diretório real do host em um perfil, ou colar um token vivo no convidado, um escape de symlink pode alcançá-lo. A linha mantém seus segredos fora; colocá-los de volta é uma escolha que só você pode fazer.
Delimite o broker de propósito.
Stubs significam que o arquivo no disco não vale nada, mas o broker ainda guarda tokens reais para as chamadas que você permite. Um perfil que só precisa ler um repo não deveria carregar um token capaz de publicá-lo. O isolamento contém a explosão; o escopo decide quão grande ela poderia chegar a ser.
O workspace era a parede errada.
O GhostApproval é, no fundo, uma história sobre o que a indústria
concordou em tratar como fronteira: a pasta do workspace, a ideia de que
"o agente fica no diretório do projeto" é uma propriedade de segurança,
e não um padrão que qualquer placa pode contornar. O symlink em si é um
bug que os fornecedores podem corrigir, e corrigiram. Desenhe sua
fronteira em uma pasta e você vai passar a eternidade provando que
nenhum symlink, nenhum .., nenhum caminho esperto jamais sai dela.
Desenhe-a no hypervisor e a pergunta deixa de importar, porque o lugar
para o qual o agente escapa é uma máquina descartável que nunca
guardou nada seu.
Aplique os patches dos fornecedores; eles fecham um buraco real. Mas o buraco doeu porque o agente estava parado no seu laptop, a um diretório das suas chaves. Tire o agente do seu laptop e o próximo escape (haverá um) chega a uma sala vazia. O Bromure Agentic Coding é gratuito, open-source e já está disponível hoje.