A 4 de agosto de 2026, uns atacantes comprometeram a conta do GitHub do responsável pela manutenção do keyv, uma biblioteca de armazenamento de chave-valor com cerca de 127 milhões de downloads semanais no npm, e aproveitou esse acesso para introduzir um worm que rouba credenciais em toda a família de pacotes. O mesmo mantenedor é proprietário de armazenável em cache (29 milhões de downloads por mês), cache plana (565 milhões de downloads por mês), cache-de-entradas-de-ficheiros (557 milhões de downloads por mês) e vários outros utilitários de cache amplamente utilizados, todos os quais foram afetados pelo mesmo ataque.
A invasão foi levada a cabo através da introdução direta de ficheiros maliciosos no principal criar um ramo e, em seguida, lançar imediatamente uma nova versão, o que significa que as versões corrompidas foram publicadas no npm com uma proveniência válida, assinada pelo GitHub Actions.
Os pacotes afetados incluem:
keyv6,0,0 (604 milhões/mês)cache plana6,1,24 (580 milhões/mês)cache-de-entradas-de-ficheiros11,1,6 (571 milhões/mês)pedido-armazenável-em-cache13,0,20 (137 milhões/mês)armazenável em cache2,5,1 (30 milhões/mês)@cacheable/memória2,2,1 (28 milhões por mês)gestor de cache7,2,10 (16 milhões por mês)@cacheable/node-cache3.1.2 (6 milhões por mês)@cacheable/utils2,5,1 (34 milhões por mês)@cacheable/net2.1.1 (3,7 mil/mês)ecto5,0,1 (4,5 mil/mês)
Estamos também a assistir a uma propagação comunitária muito ativa deste «worm» da cadeia de abastecimento para outros responsáveis pela manutenção e pacotes, incluindo organizações de grande dimensão:
@deliveroo/reevent1.0.1@or-sdk/invitations1.4.9@picsart/ai-sdk3.32.2@qlik/embed-runtime1.6.4picasso.js2.11.6
Atualização — 4 de agosto de 2026, 13:37 CEST: Pelo menos 434 pacotes (em 1 381 versões) foram comprometidos pelo worm, com um total combinado de mais de 2 mil milhões de instalações mensais à data da redação deste artigo.
O que aconteceu
Cada pacote da família recebeu dois novos ficheiros, setup.mjs e Math_Symbol.js, juntamente com um "preinstall": "node setup.mjs" registo adicionado a cada um package.json. Qualquer pessoa que tenha participado npm install contra uma versão afetada teria tido setup.mjs ser executados automaticamente antes de a sua instalação estar concluída.
setup.mjs é um dropper altamente ofuscado. A sua única função é descarregar silenciosamente o ambiente de execução Bun JavaScript a partir de github[.]com/oven-sh/bun/releases/download/bun-v1.3.13/ e utilizá-lo para executar a carga útil 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 programas de roubo de credenciais que recolhem secrets ambiente da vítima, encriptam os dados obtidos e os transferem para um repositório público do GitHub cuja descrição diz «Shai-Hulud: Lá vamos nós outra vez". A carga útil também contém funcionalidades de propagação do tipo «worm» para infetar pacotes de outros responsáveis pela manutenção 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 dos quais visando um repositório de segredos diferente na máquina da vítima.
tokens npm
Lê ~/.npmrc e analisa o sistema de ficheiros à procura de quaisquer outros .npmrc ficheiros. Excertos authToken valores e quaisquer //registry.*:_authToken=... entradas. Valida cada token em tempo real em relação a registry.npmjs[.]org/-/whoami antes de proceder à exfiltração.
tokens do GitHub
São visados três formatos de tokens: os PAT clássicos (ghp_...) e tokens OAuth (gho_...), tokens servidor-a-servidor da aplicação GitHub (ghs_...), e tokens JWT OIDC. As fontes incluem ~/.config/gh/hosts.yml, variáveis de ambiente e uma verificação do sistema de ficheiros.
Nos executores do GitHub Actions, a carga útil também executa um comando de shell que lê diretamente a memória do processo do executor para extrair todo o armazenamento de segredos. Este lê ACTIONS_ID_TOKEN_REQUEST_TOKEN e ACTIONS_ID_TOKEN_REQUEST_URL para roubar os tokens OIDC utilizados na publicação no npm.
Credenciais AWS
~/.aws/credentialse~/.aws/config, analisando todos os perfis nomeadosAWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY, eAWS_SESSION_TOKENvariáveis de ambiente- Serviço de Metadados de Instâncias EC2 em
169.254.169.254, experimentando primeiro o IMDSv2, com o IMDSv1 como alternativa - Ponto de acesso container do ECS em
169.254.170.2 - AWS Secrets , a ligar
secretsmanager:ListSecretsem várias regiões, para identificar e extrair todos secrets aí secrets
secrets do Kubernetes
Lê o token da conta de serviço, o certificado da CA e o espaço de nomes a partir de secrets.io/serviceaccount/. Utiliza o token da conta de serviço para consultar diretamente a API do Kubernetes e recuperar todos secrets namespace. Também tem como alvo KUBECONFIG e ~/.kube/config.
Tokens do HashiCorp Vault
Verifica seis fontes por ordem de prioridade: o VAULT_TOKEN variável de ambiente, ~/.vault-token, o caminho do executor do GitHub Actions /home/runner/.vault-token, vários container conhecidos, um início de sessão no Kubernetes utilizando o JWT da conta de serviço roubada e o ponto final de autenticação do Vault no AWS IAM utilizando quaisquer credenciais roubadas da AWS. Após obter um token, enumera todas as bases de dados KV através de /v1/sys/mounts e lê todos os segredos 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 analisados pelo scanner do sistema de ficheiros.
Análise geral do sistema de ficheiros
Um scanner que tem em conta a plataforma (macOS vs. Linux) executa cerca de 200 padrões globais em todo o sistema de ficheiros, visando, entre outras coisas:
.env,.env.*, e.envrcfiles- Ficheiros de chaves privadas (
*.pem,*.key,*.p12,*.pfx,*.jks) - Chaves SSH e configuração (
id_rsa,id_ed25519,.ssh/config) - Ficheiros de estado do Terraform e
.tfvars - Ficheiros de credenciais do registo do Docker (
docker/config.json) - Bases de dados do KeePass (
*.kdbx) - Configurações de VPN (
*.ovpn) - Ficheiros de configuração do IDE, incluindo
.vscode/tasks.jsone.claude/settings.json
Os ficheiros com mais de 5 MB são ignorados. São utilizadas até 64 leituras simultâneas. É também aplicado um motor de expressões regulares genérico a todos os ficheiros analisados, identificando chaves privadas PEM, chaves públicas SSH, chaves de armazenamento do Azure, cadeias de ligação a bases de dados com credenciais incorporadas e genéricas chave=valor padrões que correspondam a nomes de campos secretos comuns.
Exfiltração
Assim que as credenciais são recolhidas, a carga útil encripta todo o pacote antes de o enviar para qualquer lugar. Apenas o atacante, que possui a chave privada correspondente RSA , pode desencriptar o que é carregado. Isto significa que os dados roubados ficam à vista de todos na infraestrutura pública, mas são ilegíveis para qualquer outra pessoa.
O principal destino da exfiltração é um repositório público do GitHub cuja descrição contém a sequência«Shai-Hulud: Here We Go Again». À data da redação deste artigo, o GitHub contém cerca de 1 300 repositórios públicos que correspondem a essa sequência, servindo cada um deles como ponto de entrega do pacote de credenciais encriptadas da vítima.

Se o envio para o GitHub falhar, a carga útil recorre a https://npm-cache[.]com:443/router, um domínio registado em 22 de maio de 2026 que parece não ter qualquer finalidade legítima. Este domínio é obtido dinamicamente a partir de um contrato inteligente da Ethereum em 0xE1f2395ee43e45A1556EC6438a88c31B83493103, permitindo que o atacante altere a infraestrutura a qualquer momento sem alterar a carga útil.
Worm autorreplicante
Para além de roubar credenciais, a carga útil utiliza-as ativamente para propagar o malware a outros mantenedores e repositórios. Possui dois vetores de infeção distintos.
Infecção do ficheiro tarball do npm
Utilizando o token npm roubado, a carga útil chama https://registry.npmjs[.]org/-/npm/v1/tokens para listar todos os pacotes para os quais esse token tem direitos de publicação e, em seguida, descarrega e descompacta o ficheiro tar atual de cada um deles. Antes de voltar a publicar, efetua as seguintes alterações:
- Aumenta a versão do patch em um (por exemplo,
1.2.3torna-se1.2.4) - Adiciona
"preinstall": "node setup.mjs"para os scripts do pacote - Injeções
setup.mjsemath_init.js(funcionalmente idêntico aMath_Symbol.js) para dentro da embalagem
Em seguida, volta a compactar e publica o ficheiro tarball modificado no registo.
É assim que o worm se propaga para além do responsável original. Após o ataque inicial ao keyv Como responsáveis pela manutenção, observámos que mais de 400 pacotes foram 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 infetados pelo worm de injeção de ficheiros tarball do npm.
Infecção do repositório do GitHub
Quando a carga útil encontra um ghs_ token, efetua o commit em todos os ramos a que consegue aceder, até um máximo de 50 ramos por repositório, processando primeiro os ramos mais recentes e ignorando dependabot e copiloto ramificações. Adiciona ganchos maliciosos a .claude/settings.json e .vscode/tasks.json para que o código executável seja executado automaticamente da próxima vez que um programador abrir o repositório no VS Code ou iniciar uma sessão do Claude Code no seu interior, sem necessidade de executar o comando «npm install». Os commits são criados como claude por e-mail claude@users.noreply.github[.]com e transmitir a mensagem tarefa: atualizar a configuração, 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 Compromisso (IOCs)
Arquivos
setup.mjs- SHA-256
54dc7ea54a1317cca0e890a2770630cf7fa6c97813e0cb9d2caa93012b350668
- SHA-256
setup.mjs(versão de transmissão comunitária)- SHA-256
fd3ca4007b225fdf8de7af4345a19179d5efa8c4bb9205f88cda806e5684b1eb
- SHA-256
Math_Symbol.jsemath_init.js- SHA-256
9fc2570b7cef51c1b8df116d144d11ff4096357be7d2c4c6367cfc2509cf1bcc
- SHA-256
Rede
https://npm-cache[.]com:443/router— terminal de exfiltraçãoeth-mainnet.nodereal[.]iopedido que contém0xE1f2395ee43e45A1556EC6438a88c31B83493103
Outros
- Qualquer repositório público do GitHub cuja descrição contenha
«Shai-Hulud: Lá vamos nós outra vez»— estes são os repositórios controlados pelo atacante utilizados para a exfiltração de credenciais.

