O repositório era mesmo da Microsoft
Entre 5 e 6 de junho de 2026, o worm Miasma empurrou código de roubo de credenciais para 73 repositórios em quatro das próprias organizações GitHub da Microsoft — Azure, Azure-Samples, microsoft, MicrosoftDocs — incluindo Azure/functions-action, a Action oficial de deploy, e durabletask, um repositório que já havia sido limpo uma vez em maio. Desta vez o payload não esperou por um npm install. Ele disparou no instante em que um desenvolvedor abriu o repositório no Claude Code, Cursor, Gemini CLI ou VS Code. Eis por que o sinal de confiança — «é um repositório da Microsoft» — foi de novo a superfície de ataque, e o que muda quando o agente que o abre vive em uma VM Bromure por perfil, atrás de um intermediário de credenciais, de um guardrail de leitura/escrita e de um cooldown de pacotes.
Há uma semana o worm entrou montado no escopo npm da Red Hat e
disparou através de um hook preinstall. Esta semana ele entrou
montado no GitHub da Microsoft e não precisou de instalação alguma. O
Miasma plantou configuração com escopo de projeto em 73 repositórios
da Microsoft — Azure/functions-action, a Action oficial de deploy,
entre eles — e o payload executou no instante em que um desenvolvedor
abriu o repositório no Claude Code, Cursor, Gemini CLI ou VS Code.
Clonar não foi o gatilho. Abrir no seu agente foi.
Um desenvolvedor que clona Azure/functions-action para depurar um
deploy que falha não hesita, e nem o agente que ele aponta para o repo.
É um repositório de primeira parte da própria organização Azure da
Microsoft — a fonte canônica da GitHub Action que metade do ecossistema
referencia como Azure/functions-action@v1. Não há mantenedor a
verificar, porque o mantenedor é a Microsoft. Não há nome a apertar os
olhos, porque o nome está soletrado exatamente da forma que deveria
estar. Então o repositório é aberto, e o agente lê a configuração do
projeto da forma que toda ferramenta de codificação moderna faz ao
abrir a pasta — e um desses arquivos de configuração aponta para um
comando, e o comando é um blob de aproximadamente 4,3 megabytes que
começa a ler o sistema de arquivos em busca de chaves.
Nós documentamos a metade npm desta mesma campanha há sete dias. O Miasma é o mesmo worm — uma variante do código «Mini Shai-Hulud» que o TeamPCP liberou publicamente em meados de maio — e o fato incômodo que ele demonstra é o mesmo, girado mais uma volta: fonte reputada não é um controle de segurança. Parece um. A maior parte dos conselhos de cadeia de suprimentos se apoia nele. E em 5 de junho ele não comprou absolutamente nada, em dobro: o namespace era da Microsoft, e a execução não veio de um pacote que você escolheu instalar. Ela veio de abrir uma pasta.
O que o Miasma fez com os repositórios da Microsoft.
Entre 5 e 6 de junho de 2026, o GitHub desativou 73 repositórios em quatro organizações GitHub da Microsoft após commits maliciosos serem empurrados para eles, segundo a The Hacker News e uma análise detalhada da StepSecurity. A Redmond Magazine cobriu o caso em 8 de junho. A distribuição:
- Azure — 49 repositórios, incluindo
Azure/functions-action(a Action oficial de deploy do Functions) e os language workers para .NET, Python, Java, Go e PowerShell. - microsoft — 10 repositórios.
- Azure-Samples — 13 repositórios.
- MicrosoftDocs — 1 repositório.
A forma, reduzida à sua mecânica:
- O ponto de entrada foi uma conta de contribuidor previamente
comprometida com acesso de commit, usada para empurrar commits
maliciosos diretamente para os repositórios — marcados com
[skip ci]para que as mudanças escorregassem por baixo das verificações de CI/CD que de outro modo teriam rodado. - O commit plantou configuração com escopo de projeto — o tipo de arquivo que um agente de codificação ou IDE lê e sobre o qual age automaticamente quando você abre a pasta: uma task de editor, um hook de agente, um servidor MCP definido pelo projeto. Esta é a mesma classe de fronteira de confiança que o TrustFall da Adversa AI demonstrou no Claude Code, Cursor CLI, Gemini CLI e Copilot CLI — todos os quatro executam configuração definida pelo projeto logo após o prompt de confiança da pasta.
- O payload — aproximadamente 4,3 MB de código ofuscado — executou
quando o repositório era aberto no Claude Code, Gemini CLI, Cursor
ou VS Code, ou rodado através de um script
npm test. Não apenas ao clonar. O ato de apontar seu agente para a árvore clonada é o que o rodou. - Na execução, ele varria o host em busca de tokens do GitHub, chaves
AWS, service principals do Azure, credenciais GCP, tokens de
publicação npm e PyPI, chaves SSH e arquivos
.env, depois usava o acesso roubado para fazer commit de si mesmo adiante — que é o que o torna um worm em vez de um tiro único.
Um detalhe vale a pena demorar: Azure/durabletask estava entre os
repositórios atingidos — e ele já havia sido comprometido em maio na
campanha TeamPCP e limpo. Um repositório que foi remediado uma vez foi
reenvenenado cinco semanas depois. Limpeza não é um estado que você
alcança e mantém; é um estado do qual você recai no instante em que
outra credencial na cadeia é tomada.
Vale ser igualmente preciso sobre o que não aconteceu. A rede
corporativa da Microsoft não foi violada. O Azure, o serviço de nuvem,
não foi violado. Nenhum dado de cliente e nenhum sistema de produção
foi tocado. Isto foi um ataque a repositórios de código-fonte — e
sua consequência mais sentida não teve nada a ver com o malware:
no instante em que o GitHub desativou Azure/functions-action, todo
pipeline da Terra que referenciava Azure/functions-action@v1 parou
de resolver. A Microsoft foi o portador de maior visibilidade. As
pessoas de fato comprometidas foram os desenvolvedores que abriram os
repositórios envenenados em um agente entre 3 e 5 de junho, e tiveram
suas credenciais varridas das próprias máquinas.
O mesmo repositório, aberto dentro do Bromure Agentic Coding.
O Bromure Agentic Coding roda seu agente de
codificação 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 interno, este repositório
open-source que você clonou para depurar um deploy. Você clona
Azure/functions-action dentro desse perfil e o abre com seu agente
ali dentro. O gatilho de abrir a pasta dispara exatamente como
projetado. O payload roda. E então ele vai procurar chaves em um host
que não consegue alcançar.
Porque as credenciais não estão no perfil. A VM vem com stubs —
tokens falsos que parecem reais para git, gh, aws, kubectl,
npm e qualquer outra coisa que espere um cabeçalho Authorization.
Um proxy no seu Mac fica à frente de cada conexão que deixa o sandbox,
reconhece o stub e o troca pelo segredo real no fio à medida que a
requisição sai
(o sandbox que segurava a chave
percorre o mecanismo). O PAT real do GitHub, a chave AWS real, o
principal Azure real — nenhum deles toca um arquivo, uma variável de
ambiente ou uma página de memória que a VM possa ler. As chaves SSH
nunca deixam o Keychain do macOS; apenas o socket do ssh-agent é
encaminhado para dentro, do jeito que o OpenSSH sempre pretendeu.
Então percorra a varredura do Miasma através dessa fronteira. O payload
lê o ambiente em busca de $GITHUB_TOKEN e encontra um stub. Ele lê
~/.aws e não encontra nada. Ele lê ~/.npmrc e não encontra token de
publicação. Ele lê ~/.ssh e não encontra arquivo de chave — há um
socket encaminhado, não uma chave privada no disco. O blob de 4,3 MB
roda até a conclusão exatamente como escrito. Ele apenas exfiltra uma
caixa que nunca esteve segurando suas chaves, do lado errado de uma
fronteira imposta por hardware em relação a tudo que importa.
O passo de propagação é uma escrita, e escritas recebem um prompt.
Roubar chaves é apenas metade do Miasma. A outra metade é
propagação: ele usou o acesso GitHub roubado para fazer commit de si
mesmo no próximo repositório, e foi isso que transformou um punhado de
repositórios envenenados em 73. Mesmo em um perfil que legitimamente
tem acesso de push — digamos que você clonou functions-action
justamente porque pretende abrir um PR contra ele — o passo de
propagação do worm ainda tem que sair através do proxy, e é aí que os
Guardrails o encontram.
Os Guardrails leem a operação, não apenas a conexão — eles
distinguem uma leitura de uma escrita. Um git fetch é uma leitura; um
git push é uma escrita. Defina a credencial GitHub de um perfil como
perguntar ao escrever, e no instante em que o agente busca uma
chamada que altera estado — o git-receive-pack de que o worm precisa
para fazer commit de sua config de volta, um DELETE contra uma API,
um Terminate* no EC2 — o Bromure o detém no fio e exibe um prompt no
seu Mac que nomeia o verbo, o alvo e o perfil. A concessão que você dá
é limitada no tempo: quinze minutos para um release, uso único para as
assustadoras, nunca se o pedido não faz sentido. Leituras nunca
interrompem você; o agente busca, faz grep e lê o dia todo. É a
mutação que pausa.
Esta é a diferença entre «o agente tem um token» e «o agente pode fazer o que quiser com o token». O mecanismo inteiro de propagação do Miasma é uma escrita que o agente nunca te disse que estava fazendo — e uma escrita que o agente nunca te disse que estava fazendo é exatamente o que o prompt de leitura/escrita foi construído para pegar. O push que propaga o worm vira uma caixa de diálogo na qual você clica Não permitir, do mesmo jeito que «o agente apagou o banco de dados de produção» deixa de ser um postmortem e vira um prompt que você recusou.
A versão tinha horas de idade, e o Bromure faz os pacotes envelhecerem.
Há um segundo modo pelo qual o Miasma — e a linhagem mais ampla Mini
Shai-Hulud — alcança um desenvolvedor: não através de um repositório
que você abre, mas através de um pacote recém-envenenado que o
agente instala enquanto faz seu trabalho. A metade Red Hat desta
campanha foi precisamente isso, um hook preinstall em 32 pacotes em
um escopo confiável. E o detalhe brutal daqueles incidentes é o tempo:
uma versão comprometida tipicamente é pega e removida em questão de
horas — mas essas são exatamente as horas durante as quais um agente
autônomo, rodando sem supervisão, pode puxá-la.
A camada de Cadeia de Suprimentos do Bromure transforma o mesmo proxy de fronteira em um ponto de checagem de varredura, e faz as duas coisas que de fato importam contra um comprometimento do mesmo dia:
- Ela força a varredura de cada busca contra o socket.dev além do OSV. O OSV pega CVEs conhecidos acima do limiar de severidade que você define. O socket.dev pega o que os bancos de dados de vulnerabilidade ainda não alcançaram — scripts de install maliciosos, malware comportamental, typosquats, o comprometimento recém-publicado. Um release sinalizado é bloqueado antes de o tarball sequer aterrissar na VM. Crucialmente, a varredura roda abaixo do agente, no proxy: por mais que o agente reescreva sua própria config para te contornar, a busca ainda sai pela fronteira que ele não consegue cruzar.
- Ela impõe um cooldown. O Bromure coloca em quarentena qualquer
release publicado nos últimos dois dias — ajustável — de modo que uma
versão enviada há uma hora simplesmente não é instalável nesse
perfil enquanto o ecossistema se atualiza. Contra um worm cuja janela
inteira de oportunidade é o intervalo entre publicar e remover, um
cooldown não é uma heurística sobre se um pacote parece ruim. É uma
recusa a ser o primeiro a descobrir. Combine-o com a remoção de
scripts de install que o Bromure faz na hora — tirando hooks
postinstalldo tarball e corrigindo o hash de metadados para que a instalação ainda verifique — e o pacote que de fato aterrissa aterrissa inerte.
Para o Miasma especificamente, o vetor de abrir-repositório é a
manchete. Mas a mesma campanha se espalha também por pacotes, e o
cooldown é o controle que teria matado de fome o lado npm dela: um
release recente de @redhat-cloud-services, ou uma dependência
transitiva recém-envenenada puxada enquanto se depurava aquele
repositório da Microsoft, fica em quarentena justamente pelas horas em
que é perigoso.
Onde isto não te salva.
Um push que você aprova é um push que acontece.
O guardrail de leitura/escrita pega a escrita que o agente não te
contou. Ele não lê o diff. Se você está legitimamente empurrando
para functions-action e aprova o prompt, o Bromure encaminha o
push — incluindo, em princípio, um workflow envenenado que você não
notou no diff. Leia o que você aprova. O
trace de sessão te diz
quais diffs ler.
O cooldown é uma janela, não uma parede.
Dois dias está ajustado ao intervalo observado entre publicar e remover, mas um atacante paciente pode ficar sentado em uma versão comprometida por mais tempo que o cooldown e ainda ser instalável no terceiro dia. O cooldown mata de fome os worms do mesmo dia; ele não atesta um pacote que apenas ficou velho. O socket.dev e o OSV ainda têm que fazer a parte deles.
O perfil é de longa duração, então a persistência persiste.
Um perfil Bromure não é um disco descartável. Um payload que se escreve em um caminho de inicialização dentro do perfil pode sobreviver até a próxima sessão nesse perfil. O que ele acorda encontrando é um convidado sem chaves do host e um intermediário que só fala em tokens de curta duração, com prompt e escopo limitado — presença em uma caixa sem nada dentro — mas presença ainda assim.
Defina o escopo do intermediário de propósito.
Se um perfil está provisionado para empurrar para um repositório hoje e esse perfil roda o Miasma hoje, uma escrita aprovada passa. As concessões do intermediário funcionam porque são estreitas. Um perfil que só precisa ler um repositório não deveria poder escrevê-lo; um perfil que nunca publica não deveria guardar token de publicação. O isolamento contém a explosão; o escopo decide quão grande ela poderia ter sido.
O próximo repositório confiável já está clonado em algum lugar.
A lição do worm TanStack foi que o
lockfile e a assinatura não são defesas. A lição
do escopo da Red Hat foi que
nem o publicador é. A Microsoft adiciona o próximo corolário: nem o
repositório é, e o gatilho nem precisa ser uma instalação que você
escolheu — pode ser uma pasta que seu agente abriu. O repositório
Azure/functions-action não fez nada de errado ao ser confiável. Ser
confiável é o propósito inteiro de uma Action canônica de primeira
parte, e é exatamente o que o tornou digno de envenenar — duas vezes,
no caso de durabletask.
Você não pode consertar isso confiando com mais cuidado, porque a confiança nunca esteve mal colocada. Você conserta arranjando as coisas de modo que «qual repositório é este» e «qual escopo publicou isto» deixem de ser as perguntas das quais seu keychain depende. O Bromure Agentic Coding é a configuração onde o agente abre o repositório dentro de uma VM por perfil, as credenciais reais ficam no host atrás de um intermediário, cada escrita que o agente faz tem que passar por um prompt, e um pacote não pode ser instalado até sobreviver a um cooldown. O pior que uma abertura de pasta envenenada pode fazer é exfiltrar uma caixa que nunca esteve segurando suas chaves. É gratuito, open-source, e disponibilizado hoje.