flawopen.com/Incidents/shai-hulud-npm-worm-september-2025
Shai-Hulud: o worm de setembro de 2025 no npm e a confiança na instalação
A campanha Shai-Hulud de setembro de 2025 usou contas comprometidas de mantenedores do npm e hooks postinstall maliciosos para roubar credenciais e publicar mais pacotes infectados.[1]
Imagine uma fábrica recebendo uma caixa de peças que executa suas próprias instruções de abertura. Elas copiam os crachás de envio da fábrica e os usam para mandar caixas adulteradas a outras fábricas. Desativar as instruções automáticas fecha essa entrada, mas as peças ainda precisam de inspeção antes do uso.[1]
Conceitos Centrais e Termos
Lifecycle hook- Na campanha de setembro, o postinstall do npm executava código malicioso durante a instalação. É comportamento fornecido pelo pacote, não uma falha de memória do npm com CVE.
Publishing credential- Um token npm concede as permissões configuradas para a conta ou pacote. A autoridade de publicação roubada propagou o worm; prazo, escopo e exigência de MFA dependem da política.
Trusted publishing / OIDC- OIDC permite que um fluxo de CI autorizado obtenha credenciais breves de publicação sem token npm armazenado. Um fluxo autorizado comprometido continua perigoso.
Mapeamentos de frameworks
Linha do Tempo do Incidente
O GitHub diz que foi avisado sobre Shai-Hulud.[1]
O GitHub informou ter removido mais de 500 pacotes comprometidos e bloqueado envios que correspondiam aos indicadores do malware.[1]
Fluxo de Ataque Passo a Paso
Código-Fonte: Vulnerável vs. Seguro
Comparação segura de planos de instalação em Python: nenhuma função executa npm, lê credenciais ou contata o registro. O exemplo usa as regras do npm v10 documentadas nas fontes. O plano reforçado exige lockfile revisado, suprime scripts de ciclo de vida e não herda variáveis de ambiente. Um executor real precisa fornecer um binário npm conhecido e isolar diretório pessoal e configuração, sem credenciais ou volumes sensíveis. --ignore-scripts não torna seguras importações futuras nem scripts chamados explicitamente; lockfile não certifica código benigno.
def install_plan(reviewed_lockfile, inherited_env):
# Retorna apenas um plano: não instala pacotes nem executa comandos.
return {"argv": ["npm", "ci"],
"env": dict(inherited_env)}
def install_plan(reviewed_lockfile, inherited_env):
# Retorna apenas um plano: não instala pacotes nem executa comandos.
if reviewed_lockfile is not True:
raise ValueError("Review the lockfile before installation")
return {"argv": ["npm", "ci", "--ignore-scripts"],
"env": {}}
Lista de Verificação de Segurança para Engenharia
- ✓Exija lockfile revisado e npm ci --ignore-scripts na tarefa de instalação; testes de política CI devem confirmar o comando e ambiente sem credenciais. Execute hooks necessários somente após revisão em tarefa isolada.[3]
- ✓Mantenha credenciais de publicação e nuvem fora das tarefas de dependências, inclusive diretórios pessoais, arquivos montados e identidades do executor. Teste que a tarefa não consegue obter credenciais de publicação.[1], [2]
- ✓Use publicação confiável quando disponível, restrinja fluxo, ramo e ambiente autorizados e exija revisão das mudanças. Exija MFA resistente a phishing e remova tokens não usados.[1]
- ✓Após exposição confirmada, isole e reconstrua executores, revogue credenciais expostas e audite versões de pacotes e mudanças de fluxo. Revise o código das dependências: lockfile ou espera antes de atualizar, isoladamente, não certificam segurança.[1], [2]