Um mantenedor de um pacote com milhões de downloads semanais abre um email que parece ser do suporte do npm, digita suas credenciais e, no dia seguinte, o pacote dele publica uma versão que rouba tokens de todo mundo que a instala. Não é roteiro de filme: é o padrão que se repete trimestre após trimestre, com phishings cada vez mais bem feitos. E você não precisa ter um pacote famoso para se dar mal: basta uma dependência que se atualiza sozinha no seu CI.
O GitHub passou meses lançando mudanças no npm e no Actions para quebrar essas cadeias de ataque, e esta semana publicou um resumo de tudo que já está em produção. A boa notícia: a maioria dessas defesas é gratuita e se ativa com configuração, não com infraestrutura nova.
A má: muitas são opt-in, e se ninguém ativar no seu projeto, elas não existem. Então, em vez de resumir a notícia, aqui vai o que você pode aplicar hoje, ponto por ponto, com os links da documentação oficial de cada medida. Se só tiver dez minutos, vá direto ao item 1.

Como roubam seu pacote: a cadeia de ataque em 30 segundos
O padrão se repete: o atacante compromete a conta de um mantenedor ou infiltra código em um workflow de CI, exfiltra credenciais a partir daí (tokens do npm, secrets do pipeline) e usa essas credenciais para publicar versões maliciosas que se espalham por centenas de projetos antes que alguém reaja. O GitHub divide isso em três fases: comprometimento inicial, exfiltração de credenciais e propagação. Cada medida abaixo quebra uma dessas fases.
1. Publique pacotes sem tokens: trusted publishing com OIDC
A medida com a melhor relação esforço/impacto: eliminar o token de longa duração do npm que vive nos secrets do seu CI. Com o trusted publishing, seu workflow se autentica no npm via OIDC: tokens efêmeros, assinados, válidos apenas para aquele workflow específico. Não há nada para roubar.
Funciona com GitHub Actions, GitLab CI/CD e, desde abril, CircleCI. Você precisa do npm CLI 11.5.1+ e Node 22.14.0+. A configuração tem dois passos: no npmjs.com (Settings do pacote → Trusted Publisher) você declara organização, repositório e nome do arquivo de workflow; e no workflow você adiciona a permissão OIDC:
permissions:
id-token: write # obrigatório para OIDC
contents: read
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: '24'
registry-url: 'https://registry.npmjs.org'
- run: npm ci
- run: npm publish # sem NODE_AUTH_TOKEN, sem secrets
Dois detalhes importantes da documentação: publicando assim a partir de um repositório público, o provenance é gerado automaticamente (prova criptográfica de onde e como o pacote foi construído), e depois da migração você deve ir em Settings → Publishing access e marcar “Require two-factor authentication and disallow tokens” para que os tokens clássicos parem de funcionar naquele pacote. Ah, e só é permitido um trusted publisher por pacote.
2. Staged publishing: credenciais de CI não devem bastar para publicar
Se você quiser ir além, o staged publishing (opt-in, disponível desde maio) desacopla “ter credenciais” de “publicar”: o pacote fica em staging até que um mantenedor o aprove com 2FA pela CLI ou pelo npmjs.com. A combinação que a própria documentação do npm recomenda é configurar o trusted publisher apenas com a permissão npm stage publish (sem npm publish), de modo que tudo que sai do CI precise de aprovação humana antes de ficar público. Se roubarem seu pipeline, o atacante fica a um passo de nada.
3. npm v12: os scripts de instalação ficam desligados por padrão
O caminho favorito de propagação desse malware não é o código do pacote em runtime, mas os scripts preinstall/postinstall: eles rodam assim que você digita npm install, antes que qualquer pessoa tenha lido qualquer coisa. Com o npm v12, três padrões mudam:
allowScriptspassa para off: nenhuma dependência executa scripts de instalação, exceto as que você aprovar explicitamente. Isso inclui os builds implícitos denode-gyp.--allow-gitpassa paranone: dependências via Git não são resolvidas, exceto com opt-in.--allow-remotepassa paranone: o mesmo para tarballs por URL remota.
Para se preparar, atualize para o npm 11.16.0 ou superior e revise os warnings da sua instalação normal. O fluxo é:
# Ver quais pacotes têm scripts pendentes de aprovação
npm approve-scripts --allow-scripts-pending
# Aprovar os que você confia / negar o resto
npm approve-scripts
npm deny-scripts
A lista resultante é gravada no package.json e commitada, então a decisão fica auditável em code review. Se você já instala com --ignore-scripts no CI por hábito, o v12 simplesmente transforma essa cautela no padrão para todo mundo.
4. GitHub Actions: feche os pwn requests
No lado do CI, as mudanças de junho atacam o padrão de “pwn request”: um workflow com pull_request_target que faz checkout do código do fork e o executa com permissões elevadas. Três coisas para revisar:
- O actions/checkout não baixa mais código de forks por padrão nos triggers habitualmente explorados; é preciso fazer opt-out explícito para voltar ao comportamento inseguro. Se o seu workflow dependia disso, ele precisa de revisão: é quase certo que você estava exposto.
- Políticas de execução de workflows: no nível de repositório, organização ou empresa, você pode limitar quem dispara workflows e quais tipos de trigger são permitidos. Se nenhum workflow seu precisa de
pull_request_target, desative tudo de uma vez. - Cache do Actions em modo somente leitura para triggers não confiáveis: um workflow de baixo privilégio não pode mais envenenar o cache que compartilha com seu workflow de release.
E o básico de sempre, que continua gratuito: declare permissions: mínimas em cada workflow (o GITHUB_TOKEN nasce com permissões demais se você não disser nada), fixe as actions por SHA de commit e não por tag, e revise quem pode modificar .github/workflows/. Está tudo no guia oficial de hardening do Actions.
5. Dependabot: o cooldown de três dias já vem de fábrica
Desde 14 de julho, o Dependabot espera pelo menos três dias após a publicação de uma versão antes de abrir o PR de atualização. A lógica é que esses ataques dependem de velocidade: se uma versão maliciosa é detectada e removida em 48 horas, um cooldown de 3 dias te salva sem você fazer nada. As atualizações de segurança continuam abrindo na hora.
Se quiser outro valor (mais dias, ou diferente por tipo de bump), configure a opção cooldown no dependabot.yml:
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
cooldown:
default-days: 5
semver-major-days: 10
6. Para quando algo dá errado
Duas ferramentas de resposta que vale conhecer antes de precisar: a API de revogação de credenciais agora cobre também tokens de OAuth e de GitHub Apps (nasceu em 2025 só para PATs), e administradores de empresa têm revogação self-service de todas as credenciais de um usuário. Além disso, o npm coloca contas de alto impacto em modo somente leitura por 72 horas quando o email muda ou um código de recuperação de 2FA é usado — exatamente a janela que os phishings usam para publicar antes de o mantenedor reagir.
E se você gerencia uma organização, dê uma olhada no firewall de rede para Actions (technical preview): ele registra todo o tráfego de saída dos seus workflows, que é exatamente onde uma exfiltração aparece.
O checklist, resumido
- Migrar a publicação para trusted publishing (OIDC) e proibir tokens no pacote.
- Ativar staged publishing se o pacote for crítico.
- Atualizar para o npm 11.16+, revisar warnings e gerar a allowlist de scripts com
npm approve-scripts. - Revisar workflows com
pull_request_target; aplicar políticas de execução epermissions:mínimas. - Configurar
cooldownnodependabot.ymlse o padrão de 3 dias não servir. - Guardar os links de revogação de credenciais no seu runbook de incidentes.
Nada disso custa dinheiro nem exige ferramentas novas: é configuração que já está disponível na sua conta. A diferença entre sair no noticiário como vítima ou nem ficar sabendo que houve uma tentativa é, literalmente, uma tarde de configuração. O próximo ataque à cadeia de suprimentos não vai esperar você encaixar isso na sprint, então eu começaria pelo item 1 ainda esta semana. Se quiser reforçar outras camadas de segurança, confira também como bloquear bots de IA na Cloudflare sem perder SEO e como proteger aplicações web de graça com o SafeLine WAF.
Perguntas frequentes
O trusted publishing funciona com runners self-hosted?
Não. Por enquanto, só com runners hospedados pelo GitHub, runners compartilhados do GitLab.com e CircleCI cloud, segundo a documentação do npm. O suporte a self-hosted está previsto, mas sem data.
O npm v12 vai quebrar meus builds?
Se suas dependências usam scripts de instalação (esbuild, sharp, bcrypt e outros pacotes com binários nativos), sim: você vai precisar aprová-los com npm approve-scripts. Por isso vale atualizar para o 11.16+ já, ler os warnings e commitar a allowlist antes de atualizar para o v12.
O cooldown do Dependabot atrasa patches de segurança?
Não. O cooldown de três dias vale apenas para atualizações de versão. As atualizações de segurança abrem imediatamente, como antes.



O que você achou?
Deixe sua opinião, pergunta ou sugestão. Os comentários são sincronizados com GitHub Discussions .