Uma Defesa Simples Contra Ataques à Cadeia de Suprimentos do npm
Toda vez que você executa npm install, está confiando em código de centenas de pacotes que nunca leu. É exatamente essa confiança que os atacantes exploram. No worm Shai-Hulud de setembro de 2025, scripts maliciosos de instalação coletaram credenciais silenciosamente e republicaram pacotes comprometidos em larga escala — tudo antes do prompt de comando retornar. O comprometimento do Axios em março de 2026 seguiu o mesmo padrão, em que versões maliciosas (1.14.1 e 0.30.4) traziam uma dependência com um hook postinstall que executava um payload de acesso remoto.
Você não precisa de ferramentas pesadas para reduzir essa exposição. Uma única alteração de configuração endereça diretamente o vetor de ataque mais comum.
Principais Pontos
- Os scripts de ciclo de vida do npm (
preinstall,install,postinstall,prepare) executam automaticamente com privilégios totais do usuário, tornando-os o caminho de menor atrito para ataques à cadeia de suprimentos. - Definir
ignore-scripts=trueno.npmrcbloqueia o vetor de ataque mais comum com uma única linha de configuração. - Pacotes com binários nativos como
sharp,bcryptesqlite3ainda podem ser construídos seletivamente usandonpm rebuildapós uma instalação sem scripts. - Uma verificação de CI no
package-lock.jsonpara novas entradas"hasInstallScript": truesinaliza dependências que precisam de revisão antes do merge. - Combinar
ignore-scripts=truecommin-release-age=7adiciona um atraso que ajuda a evitar versões de pacotes recém-comprometidas.
Por Que Scripts de Ciclo de Vida São o Risco Central
Quando você instala um pacote npm, o Node executa automaticamente quaisquer scripts definidos em seu package.json — preinstall, install, postinstall e prepare. Esses hooks executam com seus privilégios totais de usuário, concedendo acesso a ~/.ssh, ~/.aws/credentials, tokens em ~/.npmrc e a todas as variáveis de ambiente do seu shell.
Sem confirmação. Sem sandbox. Apenas execução silenciosa.
No ataque ao Axios, uma dependência transitiva maliciosa chamada plain-crypto-js usou um hook postinstall para depositar um trojan de acesso remoto. No ataque de personificação do Bitwarden CLI, um hook preinstall carregava um grande payload ofuscado que coletava credenciais de nuvem e tentava se propagar pelo acesso de publicação npm da vítima.
A segurança de scripts de ciclo de vida importa porque representa o caminho de ataque de menor atrito em todo o cenário de segurança de dependências JavaScript.
A Defesa Central: npm ignore-scripts
Adicione uma linha ao .npmrc do seu projeto:
ignore-scripts=true
Isso diz ao npm para pular todos os scripts de ciclo de vida durante a instalação. Um hook postinstall malicioso simplesmente não executa.
Para uma instalação pontual sem modificar o .npmrc:
npm install --ignore-scripts
Ressalva importante: Esta não é uma solução completa. O ataque ao Bitwarden registrou um binário malicioso via o campo bin no package.json, o que significa que o payload ainda executava quando o usuário invocava o comando bw — mesmo com --ignore-scripts ativo. Nenhuma flag isolada elimina todos os riscos.
O Que Quebra e Como Lidar
Alguns pacotes legítimos requerem scripts de ciclo de vida para compilar binários nativos. Os mais comuns incluem sharp, bcrypt, sqlite3, canvas e puppeteer (que baixa o Chromium).
Verifique se seu projeto usa algum deles:
npm ls --all | grep -E "(sharp|bcrypt|sqlite3|canvas|puppeteer|node-gyp)"
Se houver correspondências, recompile apenas esses pacotes específicos após instalar:
npm install --ignore-scripts
npm rebuild sharp --ignore-scripts=false
npm rebuild bcrypt --ignore-scripts=false
Essa abordagem mantém os scripts desabilitados globalmente enquanto permite seletivamente a compilação para pacotes que você revisou explicitamente.
Discover how at OpenReplay.com.
Detectando Novos Scripts de Instalação Antes Que Executem
Em vez de reagir após o fato, sinalize novas dependências com scripts de instalação antes do merge. Adicione esta verificação ao seu pipeline de CI:
# Detect newly added packages with install scripts in PRs
if git diff origin/main -- package-lock.json | \
grep -E '^\+\s*"hasInstallScript": true' > /dev/null; then
echo "⚠️ New install script detected—manual review required"
exit 1
else
echo "✅ No new install scripts"
fi
No ataque ao Axios, plain-crypto-js era uma dependência totalmente nova com um hook postinstall. Esta verificação a teria sinalizado antes do merge do PR.
Para detalhes sobre como o npm registra scripts de instalação em lockfiles, consulte a documentação oficial do package-lock.json.
O Que Essas Defesas Não Cobrem
Seja honesto sobre os limites:
- Lockfiles não previnem ataques se um desenvolvedor executou
npm installdurante a janela de comprometimento e contaminou o lockfile antes de você perceber. npm auditsó captura pacotes maliciosos conhecidos — ataques inéditos não aparecerão em seu banco de dados.- 2FA em contas npm não protege consumidores contra um pacote publicado legitimamente por um mantenedor comprometido.
--ignore-scriptsnão bloqueia código malicioso embutido no próprio JavaScript de runtime do pacote.
Uma abordagem em camadas ajuda. Combine ignore-scripts=true com min-release-age=7 no .npmrc (requer npm v11.10.0 ou posterior) para evitar instalar pacotes publicados na última semana — a janela em que a maioria dos ataques está ativa e ainda não detectada. Esta configuração está documentada nos docs de configuração do npm em min-release-age.
Comece Por Aqui
Adicione isto ao seu .npmrc hoje:
ignore-scripts=true
min-release-age=7
Em seguida, adicione a verificação de CI para novas entradas hasInstallScript em cada PR que toca o package-lock.json. Essas duas mudanças endereçam o padrão de ataque usado em ataques recentes à cadeia de suprimentos do npm — sem exigir novas ferramentas, serviços pagos ou mudanças significativas de fluxo de trabalho.
Conclusão
Você não pode ler cada linha de cada pacote do qual depende, mas pode limitar drasticamente o que esses pacotes têm permissão de fazer durante a instalação. Desabilitar scripts de ciclo de vida por padrão, recompilar apenas os pacotes nativos em que você confia e sinalizar novas entradas hasInstallScript no CI, em conjunto, neutralizam o vetor de ataque mais explorado no ecossistema npm. Nenhuma dessas medidas exige novos fornecedores ou orçamento — apenas algumas linhas no .npmrc e uma única verificação de CI. Adote-as hoje, e o próximo ataque ao estilo Shai-Hulud se tornará muito menos impactante para o seu projeto.
Perguntas Frequentes
Pode quebrar pacotes que compilam binários nativos durante a instalação, como sharp, bcrypt, sqlite3, canvas e puppeteer. Depois de executar npm install com scripts desabilitados, use npm rebuild seguido pelo nome do pacote com --ignore-scripts=false para compilar apenas os pacotes confiáveis que você revisou. A maioria das dependências em JavaScript puro funcionará sem nenhuma alteração.
Não. Bloqueia o vetor mais comum — hooks de ciclo de vida como postinstall — mas não impede código malicioso no JavaScript de runtime de um pacote ou um binário malicioso registrado pelo campo bin. O ataque de personificação do Bitwarden CLI contornou o ignore-scripts dessa forma. Combine-o com min-release-age, revisão de lockfile e auditoria de dependências para uma defesa em camadas.
A configuração min-release-age requer a versão 11.10.0 ou posterior do npm. Verifique sua versão com npm --version e atualize se necessário usando npm install -g npm@latest. Verifique se a configuração está ativa usando npm config get min-release-age após configurá-la.
Faça commit do seu arquivo .npmrc com ignore-scripts=true no repositório para que o CI herde a configuração automaticamente. Para builds que genuinamente precisam de compilação nativa, adicione comandos npm rebuild explícitos (com --ignore-scripts=false) para os pacotes específicos necessários. Isso mantém o padrão seguro em vigor enquanto documenta exatamente quais pacotes têm permissão para executar código de instalação.
Gain control over your UX
See how users are using your site as if you were sitting next to them, learn and iterate faster with OpenReplay. — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.