O isolamento executou o comando
Em 10 de agosto de 2026, a Manifold Security publicou uma falha no agente de CLI do Cursor: a opção que inicia o agente num worktree git isolado lia um arquivo JSON do repositório que você tinha acabado de clonar e passava o conteúdo direto para um shell — antes do diálogo de Workspace Trust e fora do sandbox, mesmo com o sandbox ligado. Sem modelo, sem injeção de prompt, sem persuasão. O Bromure Agentic Coding entrega a mesma primitiva de worktree sem nenhum lugar onde um repositório possa colocar um comando, dentro de uma VM que já existia antes de o repositório chegar.
Você digitou a opção que significa “isole isto”. Foi essa opção que executou o comando de shell do repositório, como você, na sua máquina, antes de qualquer coisa perguntar se você confiava naquele repositório.
Em 10 de agosto de 2026, Francisco Rosales, da Manifold Security, publicou
uma descoberta no agente de código de linha de comando do Cursor,
que o The Hacker News noticiou três dias depois no
seu resumo ThreatsDay.
A prova de conceito abre uma calculadora. Essa é a versão educada de uma lista
que a Manifold detalha: ler ~/.ssh, pegar credenciais de nuvem do ambiente,
abrir um shell reverso, escrever persistência.
Leia pelo modo de entrega, não pela carga útil. Ninguém injetou nada, ninguém persuadiu um modelo, nenhuma frase esperta se escondeu num README. Um arquivo JSON versionado dentro de um repositório nomeou um comando, e a parte do agente cujo trabalho inteiro é isolamento executou-o.
Uma opção, um arquivo JSON e a ordem errada
cursor-agent é a versão de terminal do agente de código do Cursor. Soltar um
agente sobre a sua árvore de trabalho deixa qualquer um nervoso, então a CLI
oferece contenção, documentada na própria referência de parâmetros:
-w, --worktree [name] Start in an isolated git worktree at
~/.cursor/worktrees/<reponame>/<name>
Um worktree novo é um checkout limpo, portanto não tem nenhum dos seus
artefatos de build. Para torná-lo utilizável, a CLI executa por padrão um passo
de preparação quando cria um. Esse passo lê .cursor/worktrees.json do
repositório que acabou de conferir e passa o valor de setup-worktree
diretamente para sh -c:
{
"setup-worktree": "<any shell command>"
}
A descrição da Manifold do que havia entre esse valor e o shell tem três palavras: “Sem parsing, sem lista de permissões, sem diálogo”.
.cursor/worktrees.json é um arquivo versionado comum. Chega com um simples
git clone, como um README ou um arquivo de lock. Nos builds anteriores a
2026.07.23-e383d2b, a criação do worktree e a preparação aconteciam durante a
resolução do espaço de trabalho — e essa resolução terminava antes do caminho
de código que exibe o diálogo de Workspace Trust. Então o comando vinha
primeiro. Na gravação anexada ao relatório da Manifold, o terminal ainda está
imprimindo Running worktree setup commands…, a calculadora abre, e só depois
aparece o diálogo perguntando se você confia naquele diretório.
O Cursor é explícito sobre para que serve esse diálogo: nada que o repositório
controle deveria rodar antes de você aceitá-lo. Quando algo roda, a indústria
tem um nome para essa classe de bug — execução antes da confiança — e o Cursor
já publicou uma correção assim, no mesmo diretório. Em 2025, um
.cursor/mcp.json fornecido pelo repositório iniciava automaticamente o
servidor que configurava assim que você abria o projeto. Isso virou
CVE-2025-64109,
classificada como High, CVSS 8.8. Um tratamento permissivo de
.cursor/cli.json na mesma CLI virou
CVE-2025-61592,
também High, também 8.8. O caminho do worktree -w ainda não existia. Ele
chegou cinco meses depois daquela correção, com a mesma primitiva e sem
nenhuma trava.
A Manifold reportou em 20 de julho. O Cursor publicou o reordenamento em 23 de julho: o diálogo de confiança aparece primeiro agora, e o comando de preparação espera até que o espaço de trabalho seja confiável. Em 29 de julho o Cursor fechou o relatório como Informative, sob o argumento de que a exploração exige que o usuário clone um repositório controlado pelo atacante. A resposta da Manifold é a que vale guardar. Clonar um repositório é para o que o produto serve, e também era a precondição da CVE-2025-64109, o bug que o Cursor avaliou em 8.8 e corrigiu. Clonar descreve a entrega. O defeito está em outro lugar.
A configuração que você ligou não alcançava aquele caminho
Há uma segunda perna, e ela sobreviveu à correção.
O passo de preparação roda sob uma política de sandbox insecure_none fixada no
código. Esse é o nome que o próprio Cursor dá ao valor: em sandbox.json,
type aceita workspace_readwrite (o padrão), workspace_readonly ou
insecure_none, que desliga o sandbox por completo. O caminho de preparação do
worktree está pregado no último. Passar --sandbox enabled não muda isso. A
Manifold, descrevendo os builds atuais: atualizar “fecha a janela anterior à
confiança, não a brecha do sandbox”.
Coloque as duas pernas lado a lado e você obtém algo que sobrevive a este produto específico. A trava de confiança era um passo numa sequência, então podia acabar no lugar errado. O sandbox era uma configuração, então um caminho de código podia se isentar dela. O worktree carregava a palavra isolamento, então os usuários leram contenção nela. O próprio código do Cursor decidiu as três coisas, em momentos que ele mesmo escolheu, dentro do processo que elas deveriam limitar. É o mesmo fracasso que venceu o sinalizador de segurança de uma biblioteca duas semanas atrás, e o que está por trás de sete fugas de sandbox em que nada fugiu de um sandbox.
Um isolamento que compartilha a sua conta de usuário
-w isola a árvore de trabalho. Dá ao agente o próprio checkout para que ele
não pisoteie o seu trabalho não commitado, o que é um problema real e uma
solução real. Ninguém o construiu para isolar a máquina. O worktree vive em
~/.cursor/worktrees/, sob o seu usuário, com o seu ambiente, o seu ~/.ssh, o
seu perfil de shell, as suas credenciais de nuvem e o seu chaveiro a uma chamada
de sistema de distância. A lista da Manifold do que o comando de preparação
poderia ter feito se lê como um inventário desse diretório pessoal.
Então: um repositório que você ainda não tinha lido escolheu um comando, e o recurso que você invocou por segurança foi o que o executou. Um arquivo JSON e um shell, com o modelo assistindo do banco.
Quase toda a conversa sobre segurança de agentes derivou para o modelo. Ele é ingênuo, dá para persuadi-lo, será que leu algo que não devia. Essas perguntas importam e dedicamos muitos textos a elas. Enquanto isso, o jeito mais garantido de executar código no notebook de um desenvolvedor em 2026 é colocá-lo num arquivo que uma ferramenta lê ao iniciar, e esperar alguém clonar.
Um worktree sem lugar para colocar um comando
O Bromure Agentic Coding entrega a mesma primitiva, porque a
primitiva é boa. Aperte ⇧⌘G numa aba de repositório, digite um nome de tarefa,
escolha um agente, e o Bromure corta um branch wt/<slug> a partir do commit
atual, faz o checkout dele em ~/.bromure/worktrees/<repo>/<slug>, abre uma aba
ali e inicia o agente com o seu prompt. Várias tarefas, vários branches, vários
agentes, um único repositório — o padrão da
frota.
O passo de preparação do Bromure tem o mesmo trabalho que o do Cursor: um
checkout limpo não tem os arquivos ignorados pelo git de que um agente precisa,
então algo tem que trazê-los. A diferença está no que o repositório pode dizer a
respeito. O repo pode incluir um arquivo .worktreeinclude, e cada linha não
comentada dentro dele é um caminho relativo à raiz do worktree principal. O
Bromure copia cada um com cp -a, e só quando a origem existe e o destino não.
Nenhum campo desse arquivo guarda um comando, então não há nenhum sh -c para
sequenciar corretamente nem nenhuma questão de ordem para errar. O pior que um
.worktreeinclude hostil pode pedir é que um arquivo seja copiado para dentro
do checkout. Esse é o vocabulário inteiro.
A diferença maior é onde tudo isso acontece.
Execute o comando. Veja o que ele encontra.
Pegue a lista da Manifold e faça-a atravessar um perfil, concedendo tudo ao atacante — antes da confiança, sem sandbox, root no guest se quiser.
Ler ~/.ssh. Não há nada para ler. As chaves privadas de um perfil ficam no
host. A VM recebe um SSH_AUTH_SOCK apontando para /tmp/bromure-agent.sock,
ligado por vsock a um agente por perfil rodando no seu Mac, e o Bromure deixa o
seu agente launchd do macOS desconectado de propósito. O protocolo do agente tem
requisições para “liste minhas chaves públicas” e “assine este desafio”. Não tem
nenhuma requisição que signifique “entregue a chave privada”. Ligue Require
approval to use e cada assinatura vira um diálogo no host com uma concessão
limitada no tempo — cinco minutos, uma hora, o resto da sessão.
Pegar credenciais de nuvem do ambiente. Elas estão lá, parecem corretas, e
são falsas. Tudo no painel de Credentials de um perfil é injetado como um
espaço reservado e trocado pelo valor real no fio pelo proxy do host: brm_…
para chaves de API genéricas, um ~/.kube/config sintético com certificados de
cliente descartáveis, um blob base64 falso em ~/.docker/config.json,
~/.git-credentials, material da AWS que é reassinado do lado do host e
responde InvalidSignatureException a quem tentar contornar o proxy. O roubo dá
certo e devolve nada que preste.
Abrir um shell reverso. Agora o atacante precisa mover alguma coisa por um fio, e o fio pertence ao host. Toda requisição de saída da VM é confrontada com as iscas cunhadas para o perfil por um autômato de Aho-Corasick — cabeçalhos e corpo, a requisição inteira, não só as partes que parecem credenciais. Uma isca a caminho de um host fora do escopo para o qual foi cunhada é a assinatura de uma máquina exfiltrando algo que ela nem deveria conhecer. O proxy aborta a chamada acima antes que o destino veja um único byte, devolve um 451 ao guest, pausa a VM, tinge de vermelho o quadro congelado e levanta um alerta nomeando a credencial, o host para o qual ela foi cunhada e o host para onde ela foi. Você escolhe: desligar, guardar para investigação — imagem de disco, diretório pessoal, pastas compartilhadas, empacotados e marcados de modo que o perfil não volte a iniciar sem uma limpeza — ou continuar.
Escrever persistência. A vida útil da máquina é uma tarefa. Erase home
zera /home/ubuntu, e Reset to base reclona o disco de sistema do espaço de
trabalho.
Enquanto isso, o trabalho que você queria segue em frente. O agente revisa o repositório, roda os testes, abre o pull request. O comando do repositório rodou, numa sala onde rodar era tudo o que ele podia fazer.
A parte que aplicar patches não cobre
Mais um detalhe do relatório da Manifold, e é o de prazo de validade mais longo. O Cursor não publicou nenhum aviso de segurança para o caminho do worktree e o deixou de fora do changelog de julho, então a correção chegou dentro de um build de rotina. Quem estivesse numa versão afetada não tinha como saber que atualizar fechava um caminho de execução anterior à confiança. Hoje você não tem como saber qual ferramenta do seu notebook ainda tem um aberto, porque esse caminho é sempre algum arquivo que uma ferramenta lê ao iniciar e que ninguém auditou ainda.
O Cursor fechou este em três dias, o que é rápido. O Cursor também fechou a
versão mcp.json em 2025, e um recurso novo chegou cinco meses depois com a
mesma primitiva. É assim que fica embutir recursos numa sequência de inicialização:
cada capacidade acrescenta um passo, e cada passo é mais uma coisa para ordenar
corretamente numa quinta-feira.
Um hipervisor não é um passo dessa sequência. Ele não lê
.cursor/worktrees.json, nem .worktreeinclude, nem qualquer outra coisa no
seu repositório. Ele estava lá antes do clone, não tem um campo de política que
um caminho de código possa pregar em insecure_none, e a sua garantia — esta
máquina é descartável, estas credenciais são falsas, este fio é vigiado — é
a mesma no dia em que um bypass é publicado e no dia em que ele é
corrigido.
Continue clonando repositórios que você não leu. Revisar código desconhecido é o trabalho, e entregá-lo a um agente é a razão de ter um. Só pare de deixar essa revisão acontecer na mesma conta em que estão as suas chaves SSH. Instale o Bromure Agentic Coding, dê a cada tarefa o seu próprio branch, o seu próprio checkout e a sua própria máquina descartável, e da próxima vez que um caminho de inicialização se revelar capaz de executar o que um arquivo JSON mandar — e algum vai — ele rodará numa sala construída para isso.