A 4 de agosto de 2026, os atacantes comprometeram a conta do GitHub do mantenedor responsável por keyv, uma biblioteca de armazenamento chave-valor com cerca de 127 milhões de downloads semanais no npm, e utilizou esse acesso para injetar um worm de roubo de credenciais em toda a família de pacotes. O mesmo programador é proprietário de cacheable (29M de downloads/mês), flat-cache (565M de downloads/mês), file-entry-cache (557 milhões de downloads/mês) e de vários outros utilitários de cache amplamente utilizados, todos afetados pelo mesmo ataque.
A violação foi executada ao enviar ficheiros maliciosos diretamente para o principal e, em seguida, lançar imediatamente uma nova versão, o que significa que as versões envenenadas foram publicadas no npm com proveniência válida assinada por GitHub Actions.
Os pacotes comprometidos incluem:
keyv6.0.0 (604M/mês)flat-cache6.1.24 (580M/mês)file-entry-cache11.1.6 (571M/mês)cacheable-request13.0.20 (137M/mês)cacheable2.5.1 (30M/mês)@cacheable/memory2.2.1 (28M/mês)cache-manager7.2.10 (16M/mês)@cacheable/node-cache3.1.2 (6M/mês)@cacheable/utils2.5.1 (34M/mês)@cacheable/net2.1.1 (3,7 mil/mês)ecto5.0.1 (4,5 mil/mês)
Também estamos a testemunhar uma propagação muito ativa na comunidade deste worm na cadeia de fornecimento para outros mantenedores e pacotes, incluindo organizações de relevo:
@deliveroo/reevent1.0.1@or-sdk/invitations1.4.9@picsart/ai-sdk3.32.2@qlik/embed-runtime1.6.4picasso.js2.11.6
Atualização — 5 de agosto de 2026, 13:15 CEST: Pelo menos 444 pacotes (em 1381 versões) foram comprometidos pelo worm, com um total combinado de mais de 2 mil milhões de instalações mensais no momento em que este artigo foi escrito.
O que aconteceu
Cada pacote da família recebeu dois novos ficheiros, setup.mjs e Math_Symbol.js, juntamente com uma entrada "preinstall": "node setup.mjs" adicionada a cada package.json. Qualquer pessoa que tenha corrido npm install contra uma versão afetada teria tido setup.mjs a executar automaticamente antes de a instalação ser concluída.
setup.mjs é um dropper altamente ofuscado. A sua única função é descarregar silenciosamente o runtime Bun JavaScript a partir de github[.]com/oven-sh/bun/releases/download/bun-v1.3.13/ e utilizá-lo para executar o payload real, Math_Symbol.js:
execFileSync(<bun binary>, ['<script_dir>/Math_Symbol.js'], {
stdio: 'inherit',
cwd: <script_dir>
})O Math_Symbol.js é um ficheiro JavaScript de 728 KB fortemente ofuscado que contém módulos de roubo de credenciais que recolhem secrets do ambiente da vítima, encriptam as descobertas e exfiltram-nas para um repositório público do GitHub cuja descrição diz "Shai-Hulud: Here We Go Again". O payload também contém funcionalidade de propagação semelhante a um worm para infetar pacotes de outros maintainers que tenham instalado um dos pacotes comprometidos.
O que ele rouba
O Math_Symbol.js o ficheiro implementa um conjunto de extratores de credenciais, cada um direcionado a um armazenamento de secrets diferente na máquina da vítima.
tokens npm
Lê ~/.npmrc e examina o sistema de ficheiros em busca de quaisquer outros .npmrc ficheiros. Extrai authToken valores e quaisquer //registry.*:_authToken=... entradas. Valida cada token em tempo real contra registry.npmjs[.]org/-/whoami antes de efetuar a exfiltração.
tokens do GitHub
São visados três formatos de tokens: PATs clássicos (ghp_...) e tokens OAuth (gho_...), tokens de servidor para servidor da GitHub App (ghs_...) e tokens JWT OIDC. As origens incluem ~\/.config\/gh\/hosts.yml, variáveis de ambiente e uma verificação do sistema de ficheiros.
Nos executores do GitHub Actions, o payload também executa um comando de shell que lê diretamente a memória do processo do executor para despejar todo o armazenamento de secrets. Lê ACTIONS_ID_TOKEN_REQUEST_TOKEN e ACTIONS_ID_TOKEN_REQUEST_URL para roubar tokens OIDC utilizados para a publicação no npm.
Credenciais AWS
~/.aws/credentialse~\/.aws\/config, analisando todos os perfis com nomeAWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY, eAWS_SESSION_TOKENvariáveis de ambiente- Serviço de Metadados da Instância EC2 em
169.254.169.254, tentando primeiro o IMDSv2 com recurso de segurança para o IMDSv1 - ponto de extremidade de metadados do Container ECS em
169.254.170.2 - AWS Secrets Manager, chamando
secretsmanager:ListSecretspor várias regiões para enumerar e exfiltrar todos os secrets armazenados aí
secrets de Kubernetes
Lê o token da service account, o certificado CA e o namespace de \/var\/run\/secrets\/kubernetes.io\/serviceaccount\/. Utiliza o token da service account para consultar diretamente a API do Kubernetes e obter todos os secrets no namespace. Também tem como alvo KUBECONFIG e ~/.kube/config.
Tokens do HashiCorp Vault
Verifica seis origens por ordem de prioridade: a VAULT_TOKEN variável de ambiente, ~/.vault-token, o caminho do runner do GitHub Actions /home/runner/.vault-token, vários caminhos de container conhecidos, um início de sessão de autenticação do Kubernetes utilizando o JWT da service account roubado e o endpoint de autenticação IAM da AWS do Vault utilizando quaisquer credenciais da AWS roubadas. Após obter um token, enumera todos os armazenamentos KV através de /v1/sys/mounts e lê todos os secrets dos caminhos KV v1 e v2.
Tokens do Stripe e do Slack
Procura chaves da API do Stripe (tanto de teste como de produção, sk_ e pk_ prefixos) e tokens do Slack (xox[baprs]-...) em todos os ficheiros acedidos pelo scanner do sistema de ficheiros.
Verificação genérica do sistema de ficheiros
Um scanner compatível com plataformas (macOS vs Linux) executa cerca de 200 padrões glob no sistema de ficheiros, visando, entre outras coisas:
.env,.env.*, e.envrcfiles- Ficheiros de chaves privadas (
*.pem,*.key,*.p12,*.pfx,*.jks) - Chaves e configuração SSH (
id_rsa,id_ed25519,.ssh/config) - Ficheiros de estado do Terraform e
.tfvars - Ficheiros de credenciais do registo Docker (
docker/config.json) - Bases de dados KeePass (
*.kdbx) - Configurações de VPN (
*.ovpn) - Ficheiros de configuração de IDE, incluindo
.vscode/tasks.jsone.claude/settings.json
Os ficheiros com mais de 5 MB são ignorados. São utilizadas até 64 leituras concorrentes. É também aplicado um motor de expressões regulares genérico em todos os ficheiros analisados, sinalizando chaves privadas PEM, chaves públicas SSH, chaves de armazenamento do Azure, cadeias de ligação de bases de dados com credenciais incorporadas e chave=valor padrões correspondentes a nomes comuns de campos de segredos.
Exfiltração
Assim que as credenciais são recolhidas, o payload encripta o pacote completo antes de o enviar para qualquer local. Apenas o atacante, que detém a chave privada RSA correspondente, consegue desencriptar o conteúdo carregado. Isto significa que os dados roubados permanecem visíveis em infraestruturas públicas, mas são ilegíveis para qualquer outra pessoa.
O destino principal da exfiltração é um repositório público do GitHub cuja descrição contém a string "Shai-Hulud: Here We Go Again". À data de escrita, o GitHub contém cerca de 1300 repositórios públicos correspondentes a essa string, cada um funcionando como um ponto de recolha para o pacote de credenciais encriptado de uma vítima.

Se o carregamento para o GitHub falhar, o payload recorre a https://npm-cache[.]com:443/router, um domínio registado a 22/05/2026 que aparenta não ter qualquer finalidade legítima. Este domínio é obtido dinamicamente a partir de um contrato inteligente Ethereum em 0xE1f2395ee43e45A1556EC6438a88c31B83493103, permitindo ao atacante alterar a infraestrutura a qualquer momento sem mexer na payload.
Worm autorreplicável
Para além de roubar credenciais, o payload utiliza-as ativamente para propagar o malware a outros maintainers e repositórios. Possui dois vetores de infeção distintos.
Infeção de tarball do npm
Utilizando o token do npm roubado, o payload invoca https://registry.npmjs[.]org/-/npm/v1/tokens para listar todos os pacotes para os quais esse token possui direitos de publicação, obtendo e descompactando em seguida o tarball atual de cada um. Antes de proceder a uma nova publicação, efetua as seguintes modificações:
- Incrementa a versão de correção (patch) em uma unidade (por exemplo,
1.2.3torna-se1.2.4) - Adiciona
"preinstall": "node setup.mjs"aos scripts do pacote - Injeta
setup.mjsemath_init.js(funcionalmente idêntico aMath_Symbol.js) no pacote
De seguida, reempacota e publica o tarball modificado no registo.
É assim que o worm se propaga para além do mantenedor original. Após a compromissão inicial do keyv mantenedor, observámos mais de 400 pacotes infetados através da propagação na comunidade. Estas infeções de segunda geração são identificáveis pelo uso de math_init.js em vez de Math_Symbol.js, uma vez que foram propagadas pelo worm de injeção de tarball npm.
Infeção de repositório do GitHub
Quando a payload encontra um ghs_ token, faz um commit em todas as branches a que consegue aceder, até um máximo de 50 branches por repositório, começando pelas branches mais recentemente ativas e ignorando dependabot e copilot branches. Adiciona ganchos maliciosos a .claude/settings.json e .vscode/tasks.json para que a payload seja executada automaticamente da próxima vez que qualquer programador abra o repositório no VS Code ou inicie uma sessão do Claude Code no seu interior, sem ser necessário executar npm install. Os commits são criados em nome de claude com o email claude@users.noreply.github[.]com e contêm a mensagem chore: update config, misturando-se com commits reais.
Como a Aikido detecta isso
Se você é um usuário Aikido, verifique seu feed central e filtre por problemas de malware. Isso aparecerá como um problema crítico 100/100. O Aikido reanalisa todas as noites, mas recomendamos acionar uma reanálise manual agora.
Se você ainda não é um usuário Aikido, pode criar uma conta e conectar seus repositórios. Nossa cobertura de malware está incluída no plano gratuito, não é necessário cartão de crédito.
Para uma cobertura mais ampla em toda a sua equipe, o Device Protection da Aikido oferece visibilidade e controle sobre os pacotes de software instalados nos dispositivos da sua equipe. Ele abrange extensões de navegador, bibliotecas de código, plugins IDE e dependências de build, tudo em um só lugar. Pare o malware antes que ele seja instalado.
Para proteção futura, considere Aikido Safe Chain (open source). O Safe Chain se integra ao seu fluxo de trabalho existente, interceptando comandos npm, npx, yarn, pnpm e pnpx e verificando pacotes contra Aikido Intel antes da instalação.
Indicadores de Comprometimento (IOCs)
Arquivos
setup.mjs- SHA-256
54dc7ea54a1317cca0e890a2770630cf7fa6c97813e0cb9d2caa93012b350668
- SHA-256
setup.mjs(versão propagada pela comunidade)- SHA-256
fd3ca4007b225fdf8de7af4345a19179d5efa8c4bb9205f88cda806e5684b1eb
- SHA-256
Math_Symbol.jsemath_init.js- SHA-256
9fc2570b7cef51c1b8df116d144d11ff4096357be7d2c4c6367cfc2509cf1bcc
- SHA-256
Rede
https://npm-cache[.]com:443/router— endpoint de exfiltraçãoeth-mainnet.nodereal[.]iopedido que contém0xE1f2395ee43e45A1556EC6438a88c31B83493103
Outros
- Qualquer repositório público do GitHub com uma descrição que contenha
"Shai-Hulud: Here We Go Again"— estes são os repositórios controlados pelo atacante utilizados para a exfiltração de credenciais.
