Blog
35 artigos · atualizado semanalmente Veja nossas Ferramentas
Todos os artigos
Tutoriais

npm v12 vai bloquear scripts de instalação por padrão — prepare sua pipeline agora

npm v12 bloqueia postinstall, git deps e remote deps por padrão. Entenda o que muda, como usar npm approve-scripts e como preparar seu CI antes de julho de 2026.

COVER · Tutoriais

npm v12 vai bloquear scripts de instalação por padrão — prepare sua pipeline agora

Tem um npm install rodando na sua pipeline que executa código arbitrário da internet no seu servidor de CI. Não como bug — como comportamento documentado e esperado. Os scripts preinstall, postinstall e prepare de qualquer pacote na sua node_modules rodam com os seus privilégios, com acesso a ~/.ssh, variáveis de ambiente e tokens do npm.

O npm v12, previsto para julho de 2026, vai mudar isso. Scripts de instalação de dependências serão bloqueados por padrão. Git deps e remote URL deps também. Esta é a mudança de segurança mais substancial no npm em anos — e você tem uma janela de migração agora, antes de ela quebrar sua build.


Por que esse comportamento sempre foi um problema

Em março de 2026, um compromisso no Axios injetou um script postinstall malicioso que exfiltrava tokens de ambiente durante a instalação. Em 2025, a campanha Shai-Hulud explorou o mesmo vetor em dezenas de pacotes. O event-stream de 2018 já era assim. A mecânica não mudou em oito anos.

O ataque é sempre simples: um pacote confiável tem uma dependência com postinstall. Essa dependência é comprometida, ou publicada com nome similar ao original. Quando você roda npm install, o script executa. O código roda com as suas credenciais, no seu ambiente, sem nenhum aviso.

O pnpm resolveu isso no v10 — scripts de instalação em dependências são opt-in desde então. Deno também. O npm demorou mais, mas a decisão foi tomada.


O que muda no npm v12: três breaking changes

As três mudanças são independentes, mas seguem a mesma lógica: comportamento perigoso deve ser opt-in, não opt-out.

1. Scripts de instalação bloqueados por padrão

Scripts preinstall, install, postinstall e prepare de pacotes na sua árvore de dependências não vão rodar automaticamente. Para autorizar um pacote específico, você usa npm approve-scripts.

2. Git dependencies bloqueadas por padrão

# Isso para de funcionar sem configuração explícita
npm install github:user/repo
npm install git+https://github.com/user/repo.git

Requer --allow-git na linha de comando ou allow-git=true no .npmrc.

3. Remote URL dependencies bloqueadas por padrão

# Também bloqueado
npm install https://example.com/meu-pacote.tgz

Requer --allow-remote ou configuração equivalente.

Cada uma dessas fontes tem perfis de risco diferentes. Git deps e remote URLs não passam pelo registry do npm — não têm assinatura de provenance, não aparecem no audit, e podem mudar sem publicar uma nova versão. Bloquear por padrão faz sentido.


npm approve-scripts: o fluxo de autorização

O npm 11.16.0 (maio de 2026) introduziu o mecanismo que o v12 vai tornar mandatório. Por ora, o comportamento é advisory: os scripts ainda executam, mas o npm imprime um sumário de pacotes não revisados ao final do install.

O comando central é npm approve-scripts:

# Ver quais pacotes têm scripts pendentes de revisão (read-only, não modifica nada)
npm approve-scripts --allow-scripts-pending

# Aprovar um pacote específico
npm approve-scripts esbuild

# Aprovar tudo de uma vez — bom ponto de partida para projetos existentes
npm approve-scripts --all

O resultado fica registrado no package.json do projeto, no campo allowScripts:

{
  "allowScripts": {
    "esbuild@0.25.4": true,
    "sharp@0.34.1": true,
    "@prisma/client@5.22.0": true,
    "husky@9.1.7": true
  }
}

Perceba que as entradas são pinadas à versão por padrão — você aprovou esbuild@0.25.4, não esbuild em geral. Quando o pacote atualizar, você revisita. É mais trabalho, mas é o ponto: a revisão é explícita e registrada em código.

Se você prefere aprovação de nome sem pin (permite qualquer versão futura), passe --no-allow-scripts-pin:

npm approve-scripts --no-allow-scripts-pin esbuild
# escreve "esbuild": true sem versão

O contraponto é npm deny-scripts, que registra explicitamente que um pacote nunca deve rodar scripts — útil em pipelines mais restritivas onde você quer garantir que certas dependências não executem nada, independente de como o install foi chamado.


Quais pacotes precisam de scripts de instalação

A maioria dos pacotes não tem scripts de instalação. Os que têm geralmente compilam binários nativos ou fazem download de artefatos de plataforma:

Pacote Por que precisa de postinstall
esbuild Baixa binário nativo específico da plataforma
sharp Compila bindings do libvips
canvas Compila binding nativa via node-gyp
@prisma/client Roda prisma generate para gerar o client
husky Instala git hooks via prepare
playwright / puppeteer Baixam browsers no postinstall

Para projetos típicos de backend Node.js ou frontend React/Vue, a lista raramente passa de 5–10 pacotes. A maioria das dependências — express, lodash, zod, dayjs — não tem scripts de instalação nenhum.


O que quebra no CI se você não agir

O risco maior não é no seu ambiente local — é no CI.

Pipelines de CI rodam npm install em modo não-interativo, geralmente em imagens Docker com Node instalado. Quando o npm v12 bloquear scripts por padrão, qualquer pacote que dependa de compilação pós-install vai falhar silenciosamente ou com erro pouco diagnóstico.

O pior cenário: você atualiza a versão do Node na sua imagem Docker (de 22 para 24, por exemplo), o npm sobe junto para v12, e o build passa na etapa de install mas falha em runtime porque esbuild não tem o binário nativo — ou prisma generate nunca rodou.

Projetos que usam git dependencies para pacotes internos têm o mesmo problema. É um padrão comum em monorepos que ainda não migraram para um registry privado:

{
  "dependencies": {
    "@empresa/utils": "github:empresa/utils#main"
  }
}

Isso vai parar de funcionar no v12 sem --allow-git explícito.


Migração antes de julho de 2026

O npm está sendo razoável na transição: a versão 11.16.0 avisa mas não bloqueia. A janela de preparação existe.

Sequência recomendada:

# 1. Atualizar o npm para ver os warnings
npm install -g npm@latest  # 11.16.0+

# 2. Rodar install e observar o output
cd meu-projeto
npm install

# 3. Ver a lista de pacotes com scripts pendentes
npm approve-scripts --allow-scripts-pending

# 4. Revisar e aprovar (--all como ponto de partida)
npm approve-scripts --all

# 5. Commitar o allowlist
git add package.json
git commit -m "chore: add npm allowScripts for install-time deps"

O campo allowScripts no repositório garante comportamento consistente entre máquinas locais, CI e novos colaboradores — sem precisar rodar approve-scripts manualmente em cada ambiente.

Uma ressalva: npm approve-scripts não funciona com npm install -g. Para global installs, o workaround é usar --ignore-scripts combinado com instalação manual do passo de compilação. A equipe do npm está ciente disso — há issues abertas no repositório oficial.


O npm finalmente está certo aqui

Executar código arbitrário durante npm install devia ser opt-in desde o início. O pnpm mostrou que é viável sem quebrar o ecossistema — a adoção foi tranquila após uma fase de warnings. O npm está seguindo o mesmo caminho, com o mesmo período de transição.

A resistência vai vir de projetos que assumiram que postinstall sempre executa. Esses projetos têm um débito de segurança que o v12 vai tornar visível. Melhor resolver agora, revisando quais scripts você realmente precisa autorizar, do que ser pego de surpresa quando o Node LTS atualizar junto.


Nota: o conteúdo editorial acabou aqui. O que vem abaixo é uma indicação de ferramenta relacionada ao tema do post.


Ferramenta relacionada

O campo allowScripts que o npm adiciona ao package.json cresce rápido em projetos com muitas dependências nativas. Para revisar, formatar e validar o JSON antes de commitar — especialmente quando você quer garantir que não ficou trailing comma nem erro de sintaxe — o Quick Tools JSON Formatter faz isso no browser, sem precisar instalar nada.

RD
Autor
Rafael Duarte
Desenvolvedor backend com passagem por fintech e SaaS B2B — trabalhou em times que escalaram APIs de zero a milhões de requisições. Carrega cicatrizes de produção suficientes para ter opiniões fortes sobre ferramentas, padrões e decisões de arquitetura. Não é acadêmico: leu a RFC do UUID quando precisou escolher entre v4 e v7 para uma tabela de alta escrita.
Ver perfil