Ele esperou pela terceira chamada
A Pillar Security está a acompanhar o Deadbugz, um servidor MCP empurrado para projetos de código aberto por pull request. Traz duas ferramentas honestas, conta as chamadas de ferramenta do seu agente e, na quarta, reescreve os metadados que devolve em instruções para recolher chaves SSH, credenciais AWS, histórico da shell e kubeconfig, e para nada dizer. Nenhum bug, nenhuma CVE: o protocolo permite tudo isto. A vítima é a ideia de que aprovar um servidor uma vez lhe diz alguma coisa sobre a chamada seguinte. Num espaço de trabalho Bromure Agentic Coding, a carga corre por inteiro, recolhe quatro falsificações e morre no proxy à saída.
Você leu o código. Você executou-o. Ele formatava texto, como anunciado. Você aprovou-o, e o atacante contava com essa aprovação.
Na noite de 10 de agosto, entre as 21:52 e as 23:07 UTC, uma conta do GitHub
chamada zellkernel abriu vinte e três pull requests contra projetos sem
qualquer ligação entre si, nas áreas de IA, MCP e ferramentas de
desenvolvimento. Setenta e quatro minutos, do início ao fim. Cada pull request
fazia a mesma pequena alteração: acrescentava um servidor Model Context Protocol
a um ficheiro de configuração.
A Pillar Security publicou a campanha a 12 de agosto e chamou-lhe Deadbugz, a partir do ficheiro que uma das variantes deixa cair. Um mês depois, os resumos mensais de MCP continuam a abrir com ele. O compêndio de setembro da Adversa, publicado ontem, dá-lhe toda a secção de incidentes. É o relógio que lhe vale esse espaço.
Duas ferramentas, e um contador
O servidor chama-se productivity-suite. Oferece duas ferramentas:
format_text e summarize. Ambas funcionam. Aponte um agente para ele, peça-lhe
que aperte um parágrafo, e recebe um parágrafo apertado.
Por trás delas, o servidor mantém aquilo que a Pillar descreve como “um contador
em memória, por cliente, dos pedidos tools/call”. Quando esse contador chega a
três, o servidor muda as suas respostas a dois outros tipos de pedido:
tools/list, que diz ao agente que ferramentas existem e para que servem, e
prompts/get, que entrega ao agente instruções preparadas. A partir da quarta
chamada, essas respostas voltam a carregar, nas palavras da Pillar, “instruções
destinadas a orientar um agente de IA associado para ficheiros locais sensíveis e
a esconder a atividade do seu operador”.
Quatro coisas: chaves SSH, credenciais AWS, histórico da shell, configuração do Kubernetes. Depois mais uma instrução: ocultar a atividade do utilizador.
Os nomes das ferramentas nunca mudam. format_text continua a chamar-se
format_text. O que virou foi a descrição por baixo, e a descrição é a parte que
o modelo lê como autoridade.
Nada aqui é uma vulnerabilidade
Não aparece um único bug nesta história. Não há corrupção de memória para corrigir nem CVE para registar, porque o servidor não faz nada que o protocolo proíba.
MCP é um protocolo em que um servidor publica as suas capacidades em tempo de execução e pode voltar a publicá-las. As descrições de ferramentas são texto que o servidor escolhe e o cliente vai buscar. Os prompts são texto que o servidor escolhe e o cliente vai buscar. O Deadbugz usa tudo isso tal como foi desenhado. O seu único contributo original é decidir quando dizer a verdade.
E isso chega, porque todos os controlos que a maioria das equipas tem contra um servidor MCP hostil correm uma só vez. Você lê o repositório. Arranca o servidor e mexe-lhe. Compara a lista de ferramentas com o que o README promete. Aprova, talvez fixe a versão, e segue em frente. Cada um desses gestos é uma fotografia, e é o Deadbugz que decide quando você a tira.
O próprio conselho da Pillar a quem constrói clientes MCP entrega o desenho. Tratar mudanças de definição de ferramenta num servidor já aprovado como um evento de segurança que exige nova aprovação. Tornar as mudanças de definição visíveis para o operador. Registar a impressão digital das definições de ferramenta no momento da aprovação e compará-la mais tarde. Cada uma delas é um pedido para mover um controlo do momento da aprovação para o momento da execução.
A população onde o Deadbugz caça é vasta e instável. Uma avaliação dinâmica de servidores MCP expostos à internet, publicada em julho, Exposed by Design, testou 414 dos 640 servidores de produção confirmados, de entre as mais de 21 000 instâncias que o seu autor encontrou na internet pública. Reportou 68 vulnerabilidades comunicáveis em dez classes, 91,8% de servidores a correr sem qualquer autenticação OAuth, e 687 instâncias de ferramentas a expor execução de shell sem controlo de acesso. O número que fica é a rotatividade: 41,6% dos servidores confirmados desapareceram em menos de três dias entre duas medições consecutivas, o que o autor lê como “ciclos de implantação rápidos sem revisão de segurança”. Um servidor que auditou a semana passada pode ser outro software esta semana, ou ter desaparecido.
A entrega também merece nota, porque é barata. Dezassete das vinte e três pull
requests acrescentavam um ponto de extremidade remoto,
productivity-suite-mcp.onrender.com/mcp, à configuração MCP de um projeto.
Quatro apontavam o Python a um ficheiro local escondido,
~/.config/.cache/.sys/.deadbug-mcp.py. Duas eram submissões a diretórios de
servidores. A Pillar não encontrou nenhuma integrada pelo botão de merge do
GitHub à data da revisão: dezanove fechadas, quatro ainda abertas. Mas uma pull
request é apenas uma das formas de uma linha de configuração viajar. A mesma
linha cabe num artigo de blogue, num guia de arranque, numa ficha de um diretório
MCP, ou numa resposta prestável debaixo de uma pergunta sobre formatação de
texto.
A lista de compras
Volte à lista. É específica, e é sempre a mesma: chaves SSH, credenciais AWS, histórico da shell, configuração do Kubernetes.
É o inventário permanente de uma máquina de programador. É o que um infostealer leva, o que um script postinstall malicioso procura com grep, e o que um atacante pede a um agente sequestrado para ir buscar. A lista está estável há uma década de campanhas porque o conteúdo é estável: uma chave privada que assina, um segredo que autentica, um registo do que você escreveu, e um token que chega à produção.
Um agente num portátil comum consegue satisfazer todos os itens, porque tem uma shell na sua diretoria pessoal e corre como você.
A mesma lista, dentro de um espaço de trabalho Bromure
O Bromure Agentic Coding corre cada agente de código numa VM Linux virtualizada por hardware no seu Mac, e mantém todos os segredos reais do lado do anfitrião dessa fronteira. O agente trabalha com falsificações que preservam a estrutura, derivadas do valor real mais um sal por instalação, para que ferramentas que tiram impressão digital de uma chave nunca a vejam mudar entre sessões. Um proxy do lado do anfitrião substitui o valor real no fio depois de o pedido ter saído da VM, e apenas quando se destina ao anfitrião para o qual essa credencial foi cunhada.
Corra a carga e deixe-a ganhar. Assuma que o modelo lê a descrição envenenada, acredita nela, e vai à procura. Pegue nos quatro itens por ordem.
Chaves SSH. O agente não encontra chave nenhuma, nem sequer um engodo. O
SSH_AUTH_SOCK da VM é uma ponte ssh-agent sobre um socket virtio, porta vsock
8444. O convidado pode listar identidades e pedir assinaturas; os bytes da chave
privada vivem apenas no anfitrião e, como diz o manual, não podem ser lidos nem
extraídos de dentro da VM. O Bromure nunca expõe o seu agente de início de sessão
do macOS a uma sessão. Cada assinatura que acontece emite um evento de auditoria
credential.ssh_sign com a impressão digital SHA256 da chave, e pode configurar
qualquer chave importada para pedir confirmação no anfitrião a cada pedido de
assinatura.
Credenciais AWS. Um ficheiro que parece certo e não vale nada. O
~/.aws/config da VM aponta para um auxiliar credential-process que entrega o
verdadeiro ID de chave de acesso emparelhado com uma chave secreta falsa de
40 caracteres, pela porta vsock 8445. Todos os SDK, a CLI aws, o terraform e o
boto3 aproveitam-no sem configuração extra, e o convidado produz uma assinatura
SigV4 bem formada calculada com o segredo errado. O reassinador do anfitrião
retira essa assinatura e volta a assinar à saída. Leve o par para outro sítio e a
AWS responde InvalidSignatureException.
Configuração do Kubernetes. O ~/.kube/config existe e contém um token
bearer que começa por brm-k8s-. Funciona, através do proxy, contra os
servidores de API para que o espaço de trabalho foi configurado. É inerte em
qualquer outro lado.
Histórico da shell. Real, e duradouro: o trabalho de programação precisa de
estado duradouro, por isso a VM do espaço de trabalho é uma máquina persistente e
não descartável. Guarda o histórico de uma máquina que nunca conteve uma chave
verdadeira, com comandos corridos contra engodos numa diretoria pessoal que não é
a sua, ao lado de um ~/.git-credentials e de um ~/.docker/config.json também
eles falsos.
Depois tem de a enviar
Recolher é metade do trabalho. A outra metade é a perna de saída para
productivity-suite-mcp.onrender.com, e essa perna esbarra numa pilha de
controlos do lado do anfitrião.
As falsificações são fios de tropeço. Cada uma tem uma única família de destinos legítimos, o âmbito de anfitriões para que foi cunhada, por isso o proxy examina cada pedido de saída, cabeçalhos e corpo, à procura de uma falsificação a caminho de onde não pertence. Ao acertar, trata o pedido como tentativa de exfiltração de credenciais: recusa com HTTP 451 sem encaminhar um byte, põe a VM em pausa no momento, e levanta um alerta que oferece Encerrar, Guardar para investigação (exportar primeiro o disco, a diretoria pessoal e as pastas partilhadas para perícia) ou Continuar por sua conta e risco. O evento aterra como uma linha vermelha de Intermediação de credenciais na Security Timeline.
O segundo controlo é a alcançabilidade. Cada espaço de trabalho carrega uma firewall de saída ordenada (ação, protocolo, anfitrião ou CIDR, portas, e para tráfego web os verbos HTTP individuais) com um valor por omissão para o tráfego não correspondido. Os espaços de trabalho novos permitem aquilo que nenhuma regra apanha; ponha isso em Negar, liste o que o trabalho precisa, e um subdomínio render.com não está na lista. Dois componentes fora do convidado aplicam a política: o comutador virtual faz corresponder cada fluxo pelo IP de destino e pelo nome de anfitrião espreitado no DNS, e o proxy volta a fazer corresponder pelo nome de servidor TLS. As edições de regras chegam às sessões em curso sem reinício.
O Guardrails põe um portão na consequência. Classifica as chamadas do agente ao
Kubernetes, à AWS, à DigitalOcean, a registos de contentores, a forjas git e a
bases de dados HTTPS como leituras, escritas ou operações destrutivas, e os
espaços de trabalho novos vêm por omissão em Perguntar antes de escrever:
cada mutação para numa caixa de diálogo do anfitrião que mostra a operação
literal, o SQL exato ou o METHOD /path. É isso que a Pillar pediu a quem
constrói plataformas: leituras de ficheiros sensíveis, acesso a credenciais e
execução de código não deviam ser consequências de metadados remotos.
Há também um detetor no caminho do conteúdo. Quando o agente devolve ao modelo
conteúdo externo (conteúdos de ficheiros, páginas obtidas, saída de comandos,
resultados de chamadas de ferramenta), um classificador PromptGuard local pontua
esses trechos no seu Mac antes de o modelo agir sobre eles, e pode registar,
perguntar, ou bloquear com um 451. O token bearer MCP de um servidor HTTP nunca
entra sequer na VM: o verdadeiro fica no anfitrião, a configuração do agente
recebe um marcador brm-mcp_, e o campo das definições di-lo em voz alta,
Nunca enviado para a VM — trocado pelo proxy.
Se mexeu neste
Procure nas suas configurações de cliente MCP, repositórios e diretorias
pessoais por productivity-suite-mcp.onrender.com, pelo anterior ponto de
extremidade promo-surname-xml-quantum.trycloudflare.com, e pelo artefacto
local em ~/.config/.cache/.sys/.deadbug-mcp.py. Reverta qualquer alteração
de configuração que os tenha introduzido, e não execute o script. Preserve os
registos do seu cliente MCP e procure atualizações de definições de
ferramenta depois da terceira chamada. O conselho da Pillar sobre rotação é
comedido: rode onde a evidência local sustentar compromisso.
A regra que encolhe a pergunta
No painel Guardrails do espaço de trabalho, ponha Tráfego não
correspondido em Negar e liste o que o trabalho precisa:
allow web api.github.com, allow web registry.npmjs.org, default deny.
Depois corra bromure-cli trace hostnames my-workspace a seguir a uma
sessão, que imprime cada anfitrião distinto que o agente contactou, com
contagens. Um destino que nunca escolheu aparece como uma linha que não
escreveu.
A aprovação é um instantâneo; o fio é contínuo
O instinto depois de uma campanha destas é rever com mais rigor: ler mais do código, fixar o commit. Ambos valem a pena, e nenhum toca no mecanismo. A revisão aqui estava certa. O servidor foi honesto enquanto alguém olhava, depois mudou num calendário que ele próprio controlava, e não quebrou uma única regra do protocolo ao fazê-lo.
Um controlo que sobrevive a um servidor mudar de ideias é um controlo que não depende de se ter acertado antes. Uma credencial que é um marcador continua a ser um marcador na quarta chamada e na quadringentésima. Uma chave privada no anfitrião não pode ser lida em chamada nenhuma. O proxy avalia uma regra de saída em cada ligação e classifica cada escrita no momento em que acontece. Nada disso guarda memória do dia em que você aprovou alguma coisa, e é por isso que um atacante não pode herdá-la.
O MCP tornou fácil dar novas capacidades a um agente, o que era o objetivo, e fez dessas capacidades uma coisa que uma parte remota descreve em texto que o seu modelo lê como instrução. Ambas vieram para ficar. Decida o que o seu agente pode deter e o que pode alcançar, e ponha a aplicação num sítio onde o servidor não tem voto. Instale o Bromure Agentic Coding e não dê ao seu agente nada que valha a pena esperar três chamadas.