Por volta das 9h UTC de 4 de agosto de 2026, um invasor assumiu o controle da conta de Jared Wray no GitHub . Com esse acesso, alterou diretamente a branch main do repositório keyv e publicou novas versões maliciosas em toda a família de pacotes keyv e cacheable .
A primeira leva atingiu 11 pacotes nos dois namespaces, incluindo keyv, cacheable-request, cache-manager, @cacheable/utils, flat-cache e file-entry-cache . Pesquisadores da Aikido Security, StepSecurity — que acompanha a ameaça com o nome ChainDrop —, Socket e Chainguard confirmaram o comprometimento nas primeiras horas .
Cada pacote contaminado recebeu o mesmo padrão de infecção: dois arquivos novos, setup.mjs e Math_Symbol.js, além de uma alteração no package.json que adicionava o script:
"preinstall": "node setup.mjs"
Esse tipo de script é executado automaticamente durante a instalação. Assim, quando um desenvolvedor ou sistema de integração contínua (CI) rodava npm install, o setup.mjs era acionado antes que o processo terminasse .
O arquivo funcionava como um dropper — um carregador cuja função era baixar um binário legítimo do runtime JavaScript Bun a partir do GitHub Releases e usá-lo para executar a segunda etapa, o payload ofuscado Math_Symbol.js, com aproximadamente 710 a 728 KB .
A Microsoft Threat Intelligence confirmou que o código era uma variante do Mini Shai-Hulud . O malware procurava uma ampla variedade de segredos nos ambientes infectados , entre eles:
O aspecto mais perigoso do ataque foi a capacidade de autopropagação. Depois de roubar tokens de publicação do npm e PATs do GitHub no ambiente infectado, o worm usava essas credenciais para publicar versões maliciosas de pacotes pertencentes a outros mantenedores, sem relação direta com a conta inicialmente comprometida .
O número de pacotes afetados cresceu rapidamente:
A ameaça também atravessou os limites dos namespaces originais. Em vez de permanecer na família keyv/cacheable, chegou a pacotes associados a organizações como Deliveroo, Ornikar, OneReach, Picsart, Qlik e ServiceTitan, entre outras .
As credenciais coletadas eram exfiltradas para um repositório do GitHub controlado pelo invasor. O worm podia criar um novo repositório ou usar um espaço dedicado para armazenar os dados roubados .
O payload também incluía vários canais redundantes de exfiltração . Na prática, isso tornava a operação mais resistente à derrubada de um único repositório ou canal de comunicação.
Os pesquisadores recomendaram tratar qualquer ambiente que tenha executado uma versão contaminada como potencialmente comprometido. A resposta não deve se limitar à exclusão dos arquivos maliciosos: os segredos disponíveis na máquina ou no runner de CI/CD podem ter sido capturados .
Interrompa a instalação das versões afetadas e fixe cada dependência em uma versão comprovadamente limpa. Também é possível usar os mecanismos de override do npm, Yarn ou pnpm — por exemplo, a propriedade overrides no package.json — para impedir que uma versão contaminada seja reinstalada por engano .
Revise ainda os arquivos de lock, incluindo package-lock.json, yarn.lock e pnpm-lock.yaml. A verificação deve incluir dependências transitivas, que podem ter sido puxadas indiretamente pelo projeto .
Não basta remover setup.mjs, Math_Symbol.js ou o pacote de node_modules . Qualquer máquina de desenvolvedor, servidor de build ou runner que tenha executado npm install com uma versão afetada deve ser tratada como comprometida.
A recomendação é preservar evidências para investigação e reconstruir o ambiente a partir de uma imagem limpa, quando possível.
Revogue e gere novamente todos os segredos que possam ter estado disponíveis no ambiente infectado . Isso inclui:
Esse é um detalhe crítico da resposta. Em alguns casos, o malware configura observadores de workflows do GitHub capazes de capturar novamente um token assim que ele é criado .
Por isso, os pesquisadores recomendaram desativar ou remover primeiro qualquer serviço de monitoramento ou mecanismo de persistência suspeito e só depois fazer a rotação das credenciais .
Limpe os caches do npm, pnpm e Yarn em máquinas de desenvolvimento e runners de CI/CD. Faça o mesmo com os caches de build do Docker .
Depois, reconstrua os artefatos do zero. Dependências contaminadas podem continuar presentes em caches de compilação, camadas de imagens Docker ou artefatos previamente gerados .
Procure repositórios recém-criados, workflows não autorizados e commits suspeitos . Também vale verificar artefatos de persistência que possam ter sido deixados pelo worm, como .claude/settings.json e .vscode/tasks.json .
A auditoria deve abranger contas de desenvolvedores, organizações do GitHub, tokens, aplicativos OAuth, Actions e runners auto-hospedados.
O ataque de 4 de agosto mostrou como uma única conta de mantenedor pode se transformar em um ponto de entrada para uma crise muito maior. O invasor não precisava ter acesso direto a todos os pacotes atingidos: bastava roubar tokens com permissão de publicação e deixar que o próprio worm ampliasse o alcance da campanha.
O uso de um binário legítimo do Bun para executar o payload, a autopropagação por meio de credenciais roubadas e os canais redundantes de exfiltração tornaram a operação mais sofisticada do que ataques anteriores de cadeia de suprimentos .
Para as equipes de engenharia e segurança, as principais lições são claras: fixar versões de dependências, revisar árvores de dependência, desativar scripts preinstall e postinstall quando isso for viável, monitorar atividades incomuns no GitHub e manter um plano de resposta específico para comprometimentos de dependências de software.