FlawOpen

flawopen.com/Incidents/shai-hulud-npm-worm-september-2025

● npm ecosystem · CWE-506 / CWE-829 · September 2025 · Crítica
Pesquisa · FlawOpen

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]

💡 Explicação em Linguagem Simples (ELI5)

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

2025-09-14

O GitHub diz que foi avisado sobre Shai-Hulud.[1]

2025-09-22

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

Passo 1

Lançamento comprometido

Uma conta de mantenedor publicou pacote modificado. Phishing é hipótese para a entrada inicial, não explicação comprovada para todas as contas.[1], [2]

Passo 2

Execução na instalação

O postinstall de setembro rodava no contexto do desenvolvedor ou da CI. O preinstall de novembro não deve ser atribuído retrospectivamente a esta onda.[1], [3], [2]

Passo 3

Exposição de credenciais

O malware procurava configurações e ambiente de desenvolvimento por credenciais npm, GitHub e serviços de nuvem; o risco ia além dos tokens de publicação.[1], [2]

Passo 4

Replicação

Credenciais de publicação roubadas permitiam alterar e publicar outros pacotes que a vítima mantinha, expandindo a campanha.[1], [2]

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.

IMPLEMENTAÇÃO VULNERÁVEL
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)}
PATCH SEGURO E ROBUSTO
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

Fontes