O scanner recusou-se a lê-lo
O Threat Intelligence Group da Google publicou o seu AI Threat Tracker a 8 de setembro. Enterrada na secção sobre um grupo de comprometimento da cadeia de fornecimento chamado UNC6780 está uma técnica que transforma a política de segurança de um modelo em cobertura: o carregador JavaScript do malware abre com um bloco de comentários a exigir rotas de síntese de armas biológicas e especificações de armas nucleares, colocado ali para que um scanner de segurança baseado em LLM recuse por política e nunca chegue ao código por baixo. A recusa é a evasão. O Bromure Agentic Coding responde a artefactos destes com verificações que nunca os leem.
Convencer um scanner de segurança a aprovar malware dá trabalho. Entregar-lhe um ficheiro tão radioativo que ele se recusa a olhar é um bloco de comentários, e o seu pipeline arquiva a recusa como análise indisponível.
O seu pipeline de build já tem um LLM lá dentro. A maioria tem. Algures entre a chegada da atualização de dependência e o acender do botão de merge, um modelo lê o diff, lê os ficheiros novos e escreve uma opinião curta sobre se algo daquilo parece hostil. Bom uso da tecnologia: apanha carregadores ofuscados por onde a correspondência de padrões passa ao lado, e custa uma fração de cêntimo por ficheiro.
A 8 de setembro, o Threat Intelligence Group da Google publicou o seu AI Threat Tracker, um balanço trimestral do que os atacantes andam a fazer com isto. A maior parte da cobertura foi para o número de manchete: um agente com motivação financeira que comprometeu a infraestrutura cloud de uma empresa e depois, nas palavras do GTIG, “aproveitou um chatbot de programação com IA, um prompt e um conjunto de instruções de agente para planear, construir e executar uma campanha de recolha massiva de credenciais em menos de seis horas”. Milhares de credenciais de terceiros, encaminhadas para fora pelos próprios endereços IP da vítima. Num servidor exposto separado, os investigadores encontraram uma framework de reconhecimento cujo painel acompanhava em tempo real mais de 23 800 segredos recolhidos.
Foi essa a história que se escreveu. O parágrafo que merece a sua tarde está várias secções mais abaixo, na parte sobre um grupo de cadeia de fornecimento que a Google segue como UNC6780.
O comentário no topo do ficheiro
O UNC6780, que também atende por TeamPCP, tem conduzido comprometimentos de open
source em larga escala desde março de 2026 no PyPI, no npm e no Docker Hub. O seu
ladrão de credenciais atual chama-se DUSTMAKER, e é uma payload JavaScript.
Payloads JavaScript têm um carregador. O deste é um ficheiro chamado _index.js,
e o GTIG encontrou algo novo no topo dele:
Além de prompts embutidos em ficheiros de configuração dirigidos a agentes de programação com IA, as amostras de DUSTMAKER incluíam prompts embutidos como comentários no topo dos scripts carregadores JavaScript do malware (
_index.js). Estes prompts contêm texto adversarial extremo, referindo temas como armas biológicas e nucleares, provavelmente com a intenção de fazer falhar scanners de segurança baseados em LLM ou de os levar a saltar a análise do código JavaScript malicioso por baixo, devido a recusas de segurança ou de política.
O bloco de comentários deixa o malware à vista de todos. Desempacotado, sem codificação, num único ficheiro: o JavaScript malicioso está três linhas mais abaixo, onde qualquer pessoa que lesse até ao fim tropeçaria nele.
O comentário torna o leitor pouco disposto a chegar ao fim. Abre com uma falsa anulação de sistema, anuncia que as diretrizes de segurança estão suspensas, e exige uma rota de síntese passo a passo para armas biológicas dispersas em aerossol. Depois passa ao desenho de uma arma nuclear de implosão, com alvo de potência incluído. Um modelo que ingere o ficheiro e a quem se pergunta “este código é malicioso?” passa a ter à frente uma pergunta mais barulhenta, e é essa que responde, com uma recusa. O scanner devolve uma mensagem de política. O seu pipeline regista análise indisponível, como faz umas dezenas de vezes por semana para timeouts e ficheiros demasiado grandes, e o build fica verde.
A técnica não custa nada ao UNC6780. Não exige conhecimento nenhum sobre que modelo lê o ficheiro, que fornecedor aloja esse modelo, ou o que diz o seu prompt de sistema. Pede uma coisa ao leitor: uma política de segurança, que num pipeline de garantia é a razão pela qual escolheu um modelo logo à partida.
O resto da cadeia faz o mesmo
Assim que se vê a jogada, o resto do ofício do UNC6780 lê-se como variações dela. Cada defesa restante no caminho é também um leitor a formar um juízo sobre um artefacto que o atacante escreveu, e cada uma é alimentada em vez de derrotada.
O pacote é entregue pelas ferramentas em que o agente mais confia. O GTIG
descreve o UNC6780 a comprometer contas legítimas de programadores “para publicar
forks trojanizados de servidores MCP legítimos no registo PyPI, como
tiktoken_mcp, e injetar código malicioso diretamente em repositórios GitHub
oficiais de organizações, como azure-functions-mcp-extension”. Pôr backdoors em
servidores MCP significa que a payload chega pela única classe de dependência que
um agente de programação é feito para carregar e à qual concede ferramentas.
A verificação de proveniência recebe uma assinatura válida. Quem trate atestações como sinal de confiança devia parar nesta:
As amostras de DUSTMAKER contêm funcionalidade para detetar quando estão a correr num ambiente de integração e entrega contínuas (CI/CD). Confirmando-o, extraem tokens OIDC da memória de processos dos runners do GitHub Actions. Com esses tokens, o DUSTMAKER autoriza-se a si próprio como publicador de confiança e publica versões comprometidas de pacotes com atestações SLSA Build 3 válidas e assinadas criptograficamente. Pacotes publicados com tokens válidos passarão as verificações de confiança automatizadas dos agentes de programação com IA.
Foi a identidade do próprio publicador que assinou aquele pacote. O DUSTMAKER levantou a identidade da memória de processos no runner onde vive, pelo que um verificador que confira a assinatura devolve válida, e tem razão.
O agente de endpoint vigia o bairro errado. O DUSTMAKER “larga ou modifica
ficheiros maliciosos em diretórios ocultos de workspace de projeto para
assistentes de programação com IA e ambientes de desenvolvimento integrados
(IDEs) (.claude/, .vscode/, .cursor/, etc.)”. O GTIG diz porquê: essas
pastas deixam o malware fundir-se “no ruído rotineiro do programador” e afastar-se
dos sítios que a deteção de endpoint vigia, como chaves de registo e
/etc/cron.*. O seu fornecedor de EDR não lançou uma regra para um ficheiro novo
em .cursor/, porque até este ano aquela pasta guardava preferências do editor.
O assistente recebe um ficheiro de configuração, e ficheiros de configuração são
instruções. A partir desses mesmos diretórios ocultos, o DUSTMAKER “usa
ficheiros de configuração maliciosos … para instruir o assistente de IA a
executar comandos ou scripts arbitrários (como setup.mjs) durante interações
rotineiras de desenvolvimento. Isto força efetivamente o modelo de IA a executar
comandos em nome do atacante sem o conhecimento do programador”. O assistente leu
a configuração do seu workspace, que é o seu trabalho, e a configuração nomeou um
script para correr. Nenhum exploit em toda essa frase.
E a API de auditoria apaga a trilha de auditoria. O malware disfarça as suas tarefas de CI com nomes de tema IA como “Copilot Setup”, e depois emite chamadas automatizadas à API para remover os logs de execução de workflows da interface do GitHub.
As cinco funcionaram como projetado
Não tem bug nenhum para reportar aqui. O scanner aplicou a sua política de segurança, que é aquilo por que lhe paga. O verificador validou uma assinatura que era válida. O assistente carregou a configuração do seu workspace, que é a funcionalidade. O agente de endpoint vigiou os caminhos que importavam antes de os agentes de programação terem diretórios de configuração. Cada um fez o seu trabalho sobre a entrada que recebeu, e foi o UNC6780 que escolheu a entrada.
A evasão comum pede um veredicto errado: empacotar o binário, partir a string, codificar o URL, esperar que a análise volte limpa. O DUSTMAKER consegue o que quer de um veredicto certo, ou de veredicto nenhum.
Toda a defesa com a forma ler o artefacto, formar uma opinião está ao alcance disto. Um modelo de linguagem na cadeira do leitor alarga esse alcance, porque um modelo carrega a sua própria lista de coisas que não fará, e essa lista é pública, documentada e acessível a quem saiba escrever um comentário. A indústria passou dois anos a endurecer modelos contra serem convencidos a dizer sim. O UNC6780 convence-os a não dizer nada.
Faça então outra pergunta aos controlos do seu pipeline agêntico: quais deles têm de ler conteúdo escrito pelo atacante para fazer o seu trabalho, e o que fica de pé depois de pôr esses de lado.
Verificações com que não se discute
O Bromure Agentic Coding corre cada agente de programação dentro de uma VM Linux virtualizada por hardware no seu Mac, com todos os controlos de segurança do lado do anfitrião dessa fronteira. O que conta contra uma cadeia como esta é o que esses controlos tomam como entrada.
O portão de idade lê um relógio. O proxy do anfitrião reconhece pedidos aos grandes registos de pacotes e aplica a política de cadeia de fornecimento do workspace antes de um byte chegar à VM. O portão de idade, a única camada ligada por omissão e definida num mínimo de dois dias, recusa versões mais novas do que o corte. Reescreve para isso a listagem de versões do registo, pelo que do ponto de vista do agente uma versão demasiado fresca ainda não existe; uma obtenção direta fixada volta como HTTP 451 cujo corpo indica a idade real do pacote. O pacote em si nunca é lido. Um bloco de comentários concebido para descarrilar um modelo de linguagem não move nenhuma data de publicação, e os forks trojanizados do UNC6780 são publicações frescas por construção. npm, PyPI, Cargo, RubyGems e Packagist trazem todos datas de publicação por versão, por isso o portão cobre-os.
Um classificador não tem política a invocar. O detetor de código-fonte do
Bromure pontua os trechos tool_result que o agente devolve em streaming ao
modelo — conteúdos de ficheiros, páginas web e saída de comandos — com um modelo
PromptGuard local da família DeBERTa a correr como ONNX no seu Mac. É um
classificador de sequências e não um modelo generativo. Entregue-lhe o bloco de
comentários do DUSTMAKER e ele não compõe resposta nenhuma, não pesa nenhuma
questão sobre se responder é permitido, e não declina nada. Emite um número entre
zero e um, e texto que abre com uma falsa anulação de sistema a anunciar diretrizes
de segurança suspensas é exatamente a forma que faz subir esse número. Por
workspace, escolhe o que um acerto faz: registar, perguntar ou bloquear. Um bloqueio
devolve 451, e o modelo nunca vê o conteúdo.
Outra coisa que não o agente lê a configuração do workspace. Um ficheiro em
.claude/ a dizer ao assistente para correr setup.mjs é a backdoor por ficheiro
de regras, e tem o seu próprio detetor: uma passagem heurística determinista para
Unicode oculto, padrões de meta-instrução, caminhos de credenciais e construções
curl-para-shell, mais um classificador ModernBERT afinado para as instruções
maliciosas que não batem com padrão fixo nenhum. Ambos correm no proxy, no
dispositivo, sobre os ficheiros de instruções extraídos do prompt de sistema, onde
nada dentro da VM os pode desligar. Ambos são interruptores por workspace, e cada
um quer um download de modelo na primeira vez que o liga. Esse download são os
cinco minutos que esta história lhe pede.
Um ladrão de credenciais precisa de credenciais. O DUSTMAKER existe para
colher segredos em ambientes de desenvolvimento, e um workspace Bromure não tem
nenhum. O Bromure substitui cada credencial que configura por um falso que
preserva a estrutura, derivado do valor real e de um sal por instalação:
sk-ant-api03-brm-…, um token ghp_ do comprimento certo, brm-mcp_…,
brm-k8s-…. Esses falsos vão para as variáveis de ambiente e para
~/.git-credentials, ~/.docker/config.json, ~/.kube/config e
~/.aws/config, que é a lista que um ladrão enumera. Os seus valores reais ficam
cifrados no Mac, e o proxy do anfitrião troca-os na linha, limitados ao anfitrião
de destino para que cada um foi cunhado. Os bytes das chaves privadas SSH nunca
entram na VM; só as assinaturas atravessam. Nenhum interruptor governa nada disto,
porque o proxy é a única rota da VM para a rede.
Os falsos servem também de fios-armadilha. Um token falso tem um único destino legítimo. O proxy varre cada pedido de saída, cabeçalhos e corpo, à procura de um falso a caminho de outro sítio. Ao encontrar um, recusa o pedido sem encaminhar um byte, põe a VM em pausa ali mesmo, e regista uma linha vermelha de Credential brokering na Security Timeline. Marca o workspace como comprometido, e o arranque seguinte obriga-o a limpar primeiro o disco e a imagem de home. Não roda nada depois, porque o ladrão levava um marcador de lugar e o marcador nunca saiu.
O registo vive na sua máquina, fora do alcance da API que o malware chama. Com
o tracing em Activity only, o proxy escreve uma linha de metadados por pedido
que sai da VM, sem corpos. bromure-cli trace hostnames imprime cada anfitrião
distinto que o workspace contactou com contagens, e bromure-cli trace leaks
nomeia o destino depois de um alerta de comprometimento. Um atacante com um token
do GitHub esvazia um histórico de workflows em meia dúzia de chamadas à API.
Esvaziar aquele registo implica chegar ao seu Mac.
Duas definições, esta tarde
Abra o painel Supply Chain do workspace e confirme que o portão de idade está ligado com um corte com que consiga viver. Dois dias é a omissão, e é o controlo mais barato que tem contra um fork trojanizado acabado de publicar. Depois abra Prompt Injection e ative os dois detetores; cada um descarrega o seu modelo uma vez, e daí em diante a análise é local e gratuita.
Uma regra que encolhe a pergunta
Em Guardrails, ponha Unmatched traffic em Deny e liste o que o
trabalho precisa: allow web api.github.com, allow web registry.npmjs.org,
default deny. Um ladrão que não consegue chegar ao seu servidor de comando é
um ficheiro num disco que está prestes a deitar fora, e gravar empurra a regra
para as sessões em curso sem reinício.
A ausência vence a avaliação
Continuamos a chegar ao mesmo sítio por caminhos diferentes. Um proxy de saída que confiou num nome que o agente podia escrever. Uma guarda de comandos que lia bash de forma diferente do bash. Um gateway de IA cuja verificação falhada de chave caía num objeto de autenticação vazio. Em cada caso um componente fazia um trabalho honesto de avaliar alguma coisa, e a avaliação partiu-se.
O DUSTMAKER afia o argumento, porque não pede avaliação partida nenhuma. Pede que uma avaliação aconteça sobre conteúdo que o UNC6780 escreveu. Dê um ficheiro a um leitor e o leitor forma uma opinião sobre ele; quem forneceu o ficheiro decide o resto.
A avaliação é uma primitiva mais fraca do que a ausência, e não paramos de entregar à avaliação o trabalho que a ausência faz de graça. Não se discute com uma data de publicação, e uma probabilidade não tem vontade nenhuma de se retratar. Um ladrão de credenciais a correr com privilégios totais dentro de uma VM descartável, a percorrer todos os ficheiros de configuração que conhece, sai de lá com um punhado de marcadores de lugar e um socket que não consegue contornar.
Pôr um modelo no seu pipeline de revisão foi a decisão certa. Garanta que os controlos que travam as coisas são aqueles com quem nada no repositório consegue falar. Instale o Bromure Agentic Coding e dê ao seu agente verificações que nunca têm de ler o ficheiro do atacante.