Worm no npm: quando instalar uma dependência vira incidente de segurança
O que aconteceu na semana passada
Em 4 de agosto de 2026, atacantes comprometeram a conta no GitHub do mantenedor do keyv, uma biblioteca de armazenamento chave-valor com cerca de 127 milhões de downloads semanais no npm. A partir desse acesso, publicaram versões maliciosas que se espalharam por mais de 400 pacotes de publicadores diferentes — incluindo flat-cache e cache-manager, segundo o levantamento da Microsoft Threat Intelligence.
O payload é uma variante do worm conhecido como Shai-Hulud: um ladrão de credenciais auto-replicante, fortemente ofuscado, que executa através do hook de ciclo de vida preinstall — ou seja, antes mesmo de a instalação do pacote terminar. Ele coleta segredos do ambiente e usa esses segredos para publicar novas versões maliciosas de outros pacotes, fechando o ciclo sozinho.
Não foi um caso isolado. Em março de 2026, uma conta de mantenedor comprometida transformou o axios em veículo de malware por cerca de três horas: qualquer instalação limpa nesse intervalo puxava um RAT multiplataforma direto para o build. Em junho, ao menos 32 pacotes do namespace @redhat-cloud-services foram comprometidos.
E o pano de fundo é pior que qualquer incidente individual: o relatório da Sonatype de 2026 contou mais de 454 mil novos pacotes open source maliciosos publicados em 2025, levando o acumulado bloqueado a passar de 1,2 milhão — alta de 75% em um ano.
Por que a defesa tradicional não pega isso
Ataques assim não dependem de uma falha no seu código. Eles exploram três premissas que quase todo pipeline aceita sem questionar:
- Que o registry entrega o que o mantenedor pretendia entregar. Uma conta comprometida quebra isso.
- Que instalar um pacote é uma operação de leitura. Não é — scripts de ciclo de vida executam código arbitrário na sua máquina e no seu CI.
- Que o CI é um ambiente descartável. Ele costuma ser o lugar com os segredos mais valiosos da empresa: tokens de deploy, chaves de cloud, credenciais de registry.
Scanner de vulnerabilidade não ajuda aqui. Não existe CVE para "esta versão publicada há quarenta minutos contém um worm".
O que dá para fazer nesta semana
Em ordem de custo/benefício:
- Desative scripts de ciclo de vida por padrão no CI.
npm ci --ignore-scriptscorta o vetor de execução mais usado. Alguns pacotes precisam de build nativo — trate essas exceções explicitamente em vez de liberar tudo. - Instale sempre a partir do lockfile.
npm ci, nuncanpm install, em qualquer ambiente automatizado. Sem lockfile respeitado, um range^puxa a versão comprometida no primeiro build depois da publicação. - Adote um período de quarentena para versões novas. A maioria dos pacotes maliciosos é despublicada em horas. Atrasar a adoção de versões com menos de alguns dias elimina quase toda a janela de exposição, com custo praticamente zero.
- Tire segredos de longa duração do CI. Troque tokens estáticos por credenciais efêmeras via OIDC. Se um worm rodar no seu pipeline, ele leva embora um token que expira em minutos, não a chave mestra.
- Separe o job de instalação do job que tem segredos. Instalar dependências e fazer deploy não precisam acontecer no mesmo ambiente com as mesmas permissões.
- Habilite 2FA obrigatório e chaves de publicação com escopo nos seus próprios pacotes. O ataque começou numa conta de mantenedor — a sua também é uma.
O ponto que costuma passar batido
A reação instintiva depois de um incidente desses é reduzir dependências. É uma boa intenção com retorno baixo: o problema raramente está na quantidade de pacotes, e sim em quantos deles conseguem executar código no seu ambiente mais privilegiado.
Um projeto com 800 dependências instaladas sem scripts, a partir de lockfile, num runner sem segredos, está em situação muito melhor do que um projeto com 80 dependências instaladas com npm install num runner que tem a chave de produção no ambiente.
A pergunta certa não é "quantas dependências eu tenho?". É "o que exatamente acontece quando eu rodo install, e com quais permissões?".
Posts relacionados
CI/CD para quem tem um time pequeno: um pipeline que cabe numa tarde
CI/CD não precisa de um time de plataforma dedicado. Precisa de um pipeline mínimo, honest...
Como diferenciar conteúdo gerado por IA do conteúdo real
Texto, imagem, voz e vídeo gerados por IA já enganam gente atenta. Não dá para confiar só...