Você rodou npm install hoje? Então talvez queira sentar antes de continuar lendo.
No dia 4 de agosto de 2026, um worm batizado de Shai-Hulud (sim, o nome do verme gigante de Duna) se alastrou pelo registro do npm como um incêndio em palheiro seco. Em menos de uma hora, o malware saltou de organização em organização, infectando 868 pacotes que somam mais de 2 bilhões de instalações mensais. O alvo? Tudo que você tem de mais precioso como desenvolvedor: tokens do GitHub, credenciais da AWS, secrets do Kubernetes, chaves SSH e até carteiras de criptomoedas.
Eu acompanho supply chain attacks há anos e já perdi a conta de quantos textos escrevi sobre pacotes npm comprometidos. Mas esse aqui é diferente. O Shai-Hulud não é um malware estático plantado num pacote obscuro. É um worm autorreplicante que usa as credenciais roubadas de uma vítima para infectar todos os pacotes que ela mantém, gerando uma reação em cadeia que se espalhou para mais de 400 pacotes em questão de minutos.
O que aconteceu (e por que você deveria se preocupar)
Tudo começou com o keyv, aquela biblioteca de armazenamento key-value que quase todo projeto Node.js usa, direta ou indiretamente. Com 127 milhões de downloads semanais, o keyv é uma daquelas dependências invisíveis: você provavelmente nem sabe que ela está no seu node_modules, mas está.
Os atacantes comprometeram a conta do GitHub do mantenedor principal do keyv. Com acesso à conta, eles fizeram push de commits maliciosos direto na branch main e dispararam releases novas usando o pipeline legítimo de GitHub Actions. O resultado é assustador: as versões infectadas vieram com assinaturas OIDC e proveniência SLSA válidas. O commit apareceu com o selo verde “Verified” do GitHub, assinado pelo github-actions[bot].
Por isso, nenhuma ferramenta de verificação de proveniência detectou o problema. A assinatura provou que o build foi legítimo, que passou pelo pipeline correto. O que ela não provou é que o código-fonte era seguro.
Os pacotes comprometidos
O mantenedor do keyv também é responsável por uma família inteira de pacotes de cache:
| Pacote | Downloads mensais | Versão infectada |
|---|---|---|
| keyv | 604 milhões | 6.0.0 |
| flat-cache | 580 milhões | 6.1.24 |
| file-entry-cache | 571 milhões | 11.1.6 |
| cacheable-request | 137 milhões | 13.0.20 |
| cacheable | 30 milhões | 2.5.1 |
| @cacheable/memory | 28 milhões | 2.2.1 |
| cache-manager | 16 milhões | 7.2.10 |
| @cacheable/node-cache | 6 milhões | 3.1.2 |
| @cacheable/utils | 34 milhões | 2.5.1 |
| ecto | 4.500 | 5.0.1 |
Depois da infecção inicial, o worm se propagou para organizações como Deliveroo, Picsart e Qlik, republicando namespaces inteiros em segundos. Pesquisadores da SafeDep documentaram que organizações foram comprometidas a cada dois a sete minutos, com todo o burst cross-organization levando apenas meia hora.
Anatomia do ataque: como o Shai-Hulud funciona
Quando você instala uma versão infectada, o ataque segue três estágios muito bem orquestrados.
Estágio 1: o dropper silencioso
O package.json da versão maliciosa inclui um script preinstall aparentemente inofensivo:
{
"preinstall": "node setup.mjs"
}
Esse setup.mjs é um loader ofuscado que verifica se o runtime Bun está instalado na máquina. Se não estiver, ele baixa a versão 1.3.13 do Bun diretamente do GitHub. Por que Bun e não Node? Porque o Bun executa código compilado em formato que dificulta análise estática.
Estágio 2: o payload de 728 KB
Com o Bun disponível, o dropper executa um arquivo chamado Math_Symbol.js, um bundle compilado de 727.680 bytes que faz jus ao nome “Shai-Hulud”: ele devora tudo no caminho.
O payload varre o sistema inteiro procurando credenciais. São cerca de 200 padrões glob diferentes escaneando:
npm e gerenciadores de pacotes:
~/.npmrce qualquer.npmrcem subdiretórios- Extrai e valida tokens
authTokencontraregistry.npmjs.org
Cloud e infraestrutura:
- AWS: arquivos de credenciais, variáveis de ambiente, metadata do EC2/ECS, Secrets Manager em múltiplas regiões
- Kubernetes: service account tokens, certificados CA, queries na API para secrets de namespaces
- HashiCorp Vault: variáveis de ambiente, tokens locais, auth via Kubernetes e AWS IAM
Git e desenvolvimento:
- GitHub PATs clássicos (
ghp_...), tokens OAuth (gho_...), App tokens (ghs_...) ~/.config/gh/hosts.ymle variáveis de ambiente- Em runners do GitHub Actions: dump de memória do store inteiro de secrets, roubo de tokens OIDC
Chaves e segredos:
- Chaves privadas (PEM, P12, PFX, JKS)
- Chaves SSH e configs
- Stripe keys (teste e produção)
- Slack tokens
- Terraform state e variáveis
- Credenciais de registries Docker
- Bancos KeePass
- Configurações de VPN
- Arquivos de configuração de IDEs
Estágio 3: exfiltração criativa
Aqui o ataque fica realmente engenhoso. Em vez de mandar dados para um servidor C2 tradicional (que seria bloqueado rápido), o Shai-Hulud encripta os dados com RSA e faz upload para repositórios públicos no GitHub.
Sim, você leu certo. Os pesquisadores encontraram cerca de 1.300 repositórios no GitHub com a descrição “Shai-Hulud: Here We Go Again”, cada um funcionando como drop point para credenciais roubadas. Como são repositórios públicos em uma plataforma legítima, firewalls corporativos nem piscam.
O endpoint de fallback é npm-cache[.]com:443/router, com rotação de infraestrutura via smart contract Ethereum no endereço 0xE1f2395ee43e45A1556EC6438a88c31B83493103. Blockchain para C2. Estamos em 2026.
O worm que se multiplica sozinho
Eu já cobri ataques de supply chain antes, como o caso do Axios no npm, mas o Shai-Hulud está em outro patamar. Ele não depende de um atacante humano para se espalhar. É um worm autônomo.
Assim que rouba um token npm com permissão de publicação, o malware:
- Lista todos os pacotes que aquele token pode publicar
- Baixa o tarball atual de cada pacote
- Faz bump da versão patch (ex:
1.2.3para1.2.4) - Injeta os arquivos maliciosos e o script
preinstall - Republica o pacote modificado
O resultado é uma cadeia exponencial de infecção. Cada vítima se torna vetor de novos ataques. É por isso que o número saltou de 11 pacotes iniciais para 868 em poucas horas.
Infecção via Claude Code e VS Code
O Shai-Hulud não para no preinstall. O malware também planta hooks em repositórios do GitHub usando tokens ghs_ roubados:
No Claude Code: cria .claude/settings.json com um hook SessionStart que executa o payload quando alguém abre o projeto no Claude Code.
No VS Code: cria .vscode/tasks.json com uma task Environment Setup configurada com runOn: folderOpen, executando automaticamente ao abrir o diretório.
Os commits são assinados como claude com email claude@users.noreply.github.com, numa tentativa de parecer que foram gerados por uma sessão legítima de coding assistido por IA.
A boa notícia? O VS Code bloqueia tasks automáticas em workspaces não confiáveis por padrão, e o Claude Code aplica workspace trust a settings de repositórios. Mas se você já confia no repositório (porque é o repositório da sua empresa, por exemplo), o payload executa sem perguntar.
Como saber se você foi afetado
Primeiro, respire. Depois, verifique.
Checklist imediata
# Verificar se alguma versão infectada está no seu lockfile
grep -E "keyv@6\.0\.0|flat-cache@6\.1\.24|file-entry-cache@11\.1\.6" package-lock.json yarn.lock pnpm-lock.yaml 2>/dev/null
# Procurar os arquivos maliciosos em node_modules
find node_modules -name "setup.mjs" -o -name "Math_Symbol.js" -o -name "math_init.js" 2>/dev/null
# Verificar hashes dos arquivos suspeitos
sha256sum node_modules/*/setup.mjs 2>/dev/null
# Hash malicioso: 54dc7ea54a1317cca0e890a2770630cf7fa6c97813e0cb9d2caa93012b350668
Indicadores de comprometimento (IOCs)
| Tipo | Valor |
|---|---|
| Arquivo | setup.mjs em qualquer pacote |
| Arquivo | Math_Symbol.js (728 KB) |
| SHA-256 (setup.mjs) | 54dc7ea54a1...b350668 |
| SHA-256 (Math_Symbol.js) | 9fc2570b7ce...9cf1bcc |
| Domínio C2 | npm-cache[.]com:443/router |
| Contrato Ethereum | 0xE1f2395ee43e45A1556EC6438a88c31B83493103 |
| Git author | claude@users.noreply.github.com |
| GitHub repos | Descrição contendo “Shai-Hulud: Here We Go Again” |
Se você foi comprometido
A SafeDep faz um alerta crítico que vale repetir: remova o watcher de revogação de credenciais ANTES de rotacionar seus tokens. O malware instala um monitor que detecta quando tokens são revogados e dispara handlers locais controlados pelo atacante. Se você revogar primeiro, pode estar dando ao atacante uma última chance de agir.
A sequência correta é:
- Isolar a máquina ou runner comprometido
- Remover o malware e o watcher de revogação
- Rotacionar todos os tokens e credenciais (npm, GitHub, AWS, Vault, K8s, SSH)
- Auditar repositórios para commits de
claude@users.noreply.github.com - Verificar lockfiles e versões resolvidas contra a lista de pacotes afetados
O que o npm está fazendo (e o que ainda falta)
O npm despublicou as versões maliciosas e restaurou as versões limpas como latest. Mas aqui vai o problema: se o seu package-lock.json já tinha pinado uma versão infectada antes da remoção, o npm ci vai falhar em vez de instalar uma versão limpa. Você precisa atualizar manualmente o lockfile.
Uma mudança positiva: o npm 12+ agora bloqueia scripts de lifecycle de dependências por padrão, a menos que você explicitamente os autorize. Isso teria impedido o preinstall de executar. Mas versões anteriores do npm e outros gerenciadores (yarn, pnpm em certas configurações) ainda permitem esses scripts sem restrição.
Sabe o que é frustrante? A comunidade Node.js discute há anos se deveria desabilitar scripts de install por padrão. O argumento contra sempre foi “vai quebrar pacotes legítimos que dependem de compilação nativa”. A ironia é que, enquanto debatiam, atacantes usaram exatamente esse vetor diversas vezes: o event-stream em 2018, o ua-parser-js em 2021, o Axios em 2026, e agora o Shai-Hulud.
Lições que ninguém quer ouvir
Esse ataque expõe problemas estruturais que a indústria insiste em ignorar.
Proveniência não é segurança. As assinaturas SLSA e OIDC estavam perfeitas. O commit tinha selo verde. O build veio do GitHub Actions legítimo do projeto. Tudo “verificado”, tudo comprometido. Proveniência prova que o código passou por um pipeline específico. Ela não prova que o código é seguro.
Monocultura de mantenedores. Um único mantenedor controlava pacotes com 2 bilhões de downloads mensais. Quando a conta dele foi comprometida, o blast radius foi catastrófico. Não é culpa dele: open source funciona assim. Mas empresas que dependem desses pacotes em produção deveriam estar contribuindo financeiramente e operacionalmente para a segurança deles.
Scripts de install são uma superfície de ataque absurda. Um preinstall roda com as mesmas permissões do seu usuário. Ele pode ler suas credenciais, acessar a rede, modificar arquivos. E na maioria das configurações, roda silenciosamente durante um npm install sem nenhum aviso.
A solução não é simples, mas o primeiro passo é: desabilite scripts de lifecycle de dependências que você não auditou. O npm 12+ faz isso por padrão. Se você está em versões anteriores:
# Desabilitar scripts de install globalmente
npm config set ignore-scripts true
# Permitir seletivamente para pacotes que precisam compilar
npx --ignore-scripts=false node-gyp rebuild
Como se proteger daqui pra frente
Algumas medidas práticas que você pode aplicar hoje:
1. Atualize para npm 12+ ou use flags de proteção
npm --version # Se < 12, considere atualizar
npm config set ignore-scripts true
2. Audite seus lockfiles regularmente
# Socket.dev e Aikido oferecem scanning gratuito
npx socket-security audit
3. Ative MFA em todas as plataformas de desenvolvimento
Isso inclui npm, GitHub, registries Docker, provedores cloud. Se a conta do mantenedor do keyv tivesse MFA resistente a phishing (como WebAuthn), esse ataque provavelmente não teria acontecido.
4. Monitore publicações dos seus pacotes
Se você mantém pacotes npm, configure alertas para qualquer publicação não autorizada. O SafeDep e o Socket oferecem monitoramento contínuo.
5. Restrinja permissões de tokens npm
Use tokens com escopo limitado. Um token read-only para CI de projetos que apenas consomem pacotes. Tokens de publicação com escopo restrito ao pacote específico.
O nome não é coincidência
“Shai-Hulud” é o nome do verme gigante de Arrakis no universo de Duna. No livro, os Fremen dizem que o verme é atraído por vibração rítmica na areia. No npm, o “verme” é atraído por algo igualmente previsível: tokens de publicação sem MFA, scripts de install com execução automática e a confiança cega em proveniência criptográfica.
Os pesquisadores da JFrog identificaram sobreposição com um ataque anterior ao PyPI (pacote lightning) em abril de 2026, sugerindo que o Shai-Hulud é uma campanha contínua e multiplataforma. O próximo alvo pode não ser npm. Pode ser PyPI de novo. Ou crates.io. Ou qualquer registro que permita publicação automatizada com tokens de longa duração.
A gente costuma dizer que supply chain attacks são o “novo normal”. Mas normal implica que a gente se acostumou. E se acostumar com um worm que rouba suas credenciais e infecta seus pacotes automaticamente é, no mínimo, a definição de insanidade.
Fontes: Aikido Security, The Hacker News, SafeDep













