Supply chain: lockfile, npm audit, Snyk, Dependabot/Renovate, signed commits
7 min de leitura
Em 2018, o pacote event-stream no npm
(usado por milhoes de projetos) foi
sequestrado pelo autor original, que
transferiu o pacote pra um attacker. O
attacker injetou codigo que roubava
bitcoins de wallets. Detectado 2 meses
depois. Ate la, milhoes de downloads
estavam comprometidos.
Em 2021, Log4Shell (CVE-2021-44228)
no log4j (Java) afetou milhoes de
apps. Patch saiu em 48h - mas a maioria
das empresas levou semanas/meses pra
atualizar.
Em 2024, ua-parser-js (usado por milhares de projetos) foi sequestrado, injetando crypto miner e credential stealer. Versoes 0.7.29, 0.8.0, 1.5.0 estavam comprometidas.
Supply chain attacks estao em alta. Voce nao precisa ter uma vulnera velidade propria - basta ter uma dependencia com vulnera velidade, e o atacante explora seu app via sua dependencia. E' a maior ameaca de seguranca em 2026, e a mais subestimada por times frontend.
Se voce entende package-lock.json (e
porque commit-lo), npm audit + Snyk
como baseline, Renovate/Dependabot como
automacao, e signed commits pra defender
a cadeia inteira, voce sai de "a gente
usa 200 deps e reza" pra "a gente
sabe o que tem, atualiza em 24h, e
verifica origem".
O essencial 🟢
O que e' supply chain attack. Em vez de atacar seu codigo, o atacante ataca uma dependencia sua (de terceiros que voce confia). O ataque escala: 1 dependencia vulnera vel = milhoes de apps vulnera veis.
Os 3 vetores classicos:
- Dependencia abandonada sequestrada: o mantenedor original "vende" ou perde o acesso ao pacote. Attacker publica versao maliciosa. (event-stream 2018, ua-parser-js 2024, node-ipc 2022).
- Vulnera velidade conhecida nao-patchada: o pacote tem um CVE, mas o time nao atualiza. (Log4Shell, Lodash CVE-2020-28500).
- Typosquatting: atacante publica
pacote com nome similar (
react-domvsreactd-dom), desenvolvedor instala por engano.
package-lock.json - o "DNA" do seu
projeto. Quando voce roda pnpm install,
o pnpm/npm le package.json (lista de
deps) e gera package-lock.json (versao
exata de cada dep, incluindo deps
de deps):
// package.json
{
"dependencies": {
"react": "^18.2.0"
}
}
// package-lock.json (resumido)
{
"packages": {
"node_modules/react": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
"integrity": "sha512-..." // SHA-512
}
}
}
O integrity e' o hash SHA-512 do
tarball. Se o tarball publicado for
diferente (atacante republicou com malware),
o npm/pnpm se recusa a instalar.
SEMPRE commite o package-lock.json.
Ele garante que todo dev / CI / prod
instala exatamente as mesmas versoes.
Sem ele, pnpm install pode resolver pra
versao diferente (mesmo com ^18.2.0,
pode pegar 18.2.5 ou 18.3.0 se sair
nova minor). Em prod, isso e' desastre:
o CI pode estar testando uma versao e
prod roda outra.
npm audit - o scanner de CVE
integrado. Roda contra o package-lock.json
e lista vulnera velidades conhecidas:
pnpm audit
# Produz:
# Package: lodash
# Severity: high
# CVE: CVE-2020-28500
# Title: Prototype Pollution
# Patched in: 4.17.21
# Path: lodash > 4.17.20
E' rapido (~5s) e baseado no GitHub
Advisory Database. Use em CI como
baseline. Atenção: pnpm audit
nao bloqueia por padrao, so reporta.
Pra bloquear, use --failing high ou
similar (configuracao de CI).
Snyk - o scanner mais agressivo. Snyk (open source free tier) tem banco de vulns proprio (mais atualizado que GitHub) e faz deep analysis:
# Install Snyk CLI
pnpm add -D snyk
# Test
npx snyk test
# Lista vulns com:
# - Severity (low/medium/high/critical)
# - Caminho exato no lockfile
# - Recomendacao de upgrade
# - Informacoes adicionais
# Monitor (snapshots em Snyk app)
npx snyk monitor
# Envia lockfile pro Snyk, recebe alertas de novas vulns via email
Snyk tem free tier (200 tests/mes pra projetos open source). Em CI, Snyk bloqueia PR com deps vulnera veis.
Renovate e Dependabot - a automacao de updates. Os 2 mantem suas deps atualizadas automaticamente, abrindo PR quando ha nova versao:
| Ferramenta | Vantagem |
|---|---|
| Dependabot | Built-in no GitHub, free |
| Renovate | Mais flexivel, agrupa updates, schedule custom |
Exemplo .github/dependabot.yml:
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
groups:
minor-and-patch:
update-types: ["minor", "patch"]
major:
update-types: ["major"]
Dependabot abre PRs automaticamente com a versao nova. Voce revisa, testa, merge. PR de dependencia nao vira "novidade"
- e' rotina. Times que adotam dependabot
ficam com
pnpm outdatedlimpo; times que nao adotam ficam com deps de 2020.
npm ci vs npm install em CI. Em
CI, sempre use npm ci (ou pnpm install --frozen-lockfile):
# ERRADO: pode mudar resolucao
npm install
# CERTO: falha se lockfile nao bate
npm ci # ou pnpm install --frozen-lockfile
npm ci le o lockfile e instala
exatamente o que esta la. Se package.json
e package-lock.json estao dessincronizados,
falha. Em prod, isso impede de instalar
versoes inesperadas.
Signed commits - defendendo o "outro lado". Supply chain nao e' so deps externas. Seus proprios commits podem ser comprometidos (GitHub account hackeada, dev machine infectada). Signed commits (GPG ou SSH key) provam que o commit veio de voce:
# Configurar GPG key (uma vez)
git config --global user.signingkey <KEY_ID>
# Assinar commit
git commit -S -m "feat: ..."
# Output: commit assinado com sua chave
# Branch protection: "Require signed commits"
# Em GitHub: Settings > Branches > Branch protection rules
Em 2026, SSH signing e' mais popular que GPG (mais simples):
# Gerar SSH signing key
ssh-keygen -t ed25519 -C "you@example.com" -f ~/.ssh/git_signing
# Configurar
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/git_signing.pub
# Commits assinados com SSH
git commit -S
GitHub valida a assinatura e mostra
"Verified" no commit. Se sua conta for
hackeada, o atacante nao pode assinar
commits sem acesso a sua chave privada
(que fica em ~/.ssh com permissao 600).
npm ci + signature + lockfile = o
triangulo de defesa. Combinado:
- lockfile commitado: versao exata de cada dep.
npm ciem CI: instala exato.- Dependabot/Renovate: mantem atualizado.
- Snyk/npm audit: detecta CVEs.
- Signed commits: prova origem.
Aprofundamento 🟡
npm audit signatures - verificar
autenticidade do registry. O npm 9+
verifica assinaturas dos pacotes publicados.
Se alguem republica o pacote no registry
(mesmo com mesmo nome e versao), o hash
nao bate e o install falha. Defesa
contra typosquatting + registry hijacking.
npm install --ignore-scripts - bloquear
postinstall scripts. Muitos pacotes
rodam scripts no install (postinstall
hook). Esses scripts rodam com suas
permissoes, podem ler env, fazer
network. Pacotes maliciosos abusam disso.
# Padrao em CI
pnpm install --ignore-scripts
# Roda manualmente depois (se necessario)
pnpm rebuild pacote-especifico
Em prod, --ignore-scripts e' a defesa
contra scripts maliciosos. Trade-off:
libs que dependem de postinstall pra
build (ex: node-gyp) quebram. Avalie
caso a caso.
Renovate com auto-merge. Renovate pode ser configurado pra auto-merge PRs de patch/minor que passam no CI:
// renovate.json
{
"packageRules": [
{
"matchUpdateTypes": ["minor", "patch"],
"automerge": true,
"automergeType": "pr",
"requiredStatusChecks": ["ci/test"]
}
]
}
Em 2026, auto-merge com CI verde e' o padrao pra deps de patch/minor. Major updates exigem revisao manual.
Socket.dev e Snyk Advisor - deteccao
de pacotes maliciosos antes de instalar.
Antes de adicionar uma dep, checar:
- socket.dev: analisa comportamento do pacote (acesso a network, env, fs, crypto suspeito). Detecta typosquatting e comportamento anomalo.
- snyk.io/advisor: score de qualidade do mantenedor, vulnerabilidades conhecidas, popularidade.
Use antes de pnpm add. 5 minutos de
pesquisa economiza incidentes de seguranca.
Subresource Integrity (SRI) - o hash
pra scripts de CDN. Cobertura em
csp-e-headers, mas vale repetir: SRI
e' a defesa contra CDN compromise:
<script
src="https://cdn.example.com/lib.js"
integrity="sha384-abc123..."
crossorigin="anonymous">
</script>
Se o lib.js for modificado (mesmo 1 byte),
o hash nao bate, browser se recusa a
executar. E' a defesa mais forte contra
supply chain attack em tempo de execucao.
sbom (Software Bill of Materials).
SBOM e' o "manifesto" de tudo que esta
no seu app. Formatos padrao: SPDX, CycloneDX.
Use em apps regulados (healthcare, gov,
finance):
# Gerar SBOM com syft
npx syft . -o spdx-json > sbom.spdx.json
# Ou com cyclonedx
npx @cyclonedx/cyclonedx-npm --output-file sbom.cdx.json
SBOM destrava rastrear qual app usa qual dep afetada por um CVE. Em 2026, EU Cyber Resilience Act exige SBOM em software vendido na Europa.
npm audit signatures e provenance.
npm 9+ tem npm provenance - pacote
publicado via GitHub Actions tem metadata
criptografica que prova de onde veio.
Garanta que seus pacotes tenham provenance
(ou use deps que tem):
# Publicar com provenance
npm publish --provenance
Em 2026, npm view <pacote> signatures
mostra se a versao e signed. Use signed
versions quando disponivel.
Pra quem quer ir mais alem 🔴
Lockfile poisoning - o ataque novo.
Cenario: atacante consegue commitar no
package-lock.json (CI comprometido, dev
hackeado). Lockfile agora aponta pra
versao maliciosa. CI instala malware
sem alerta (lockfile e confiavel por
design). Mitigacao: revisar PRs que mexem
em lockfile (a maioria dos bots de auto-merge
excluem lockfile do auto-merge -
Dependabot e Renovate tem flag).
Dependabot groups para reduzir
PR noise. Configurar pra agrupar updates
por dominio (ex: testing deps, build
deps):
groups:
testing:
patterns: ["vitest", "@testing-library/*", "playwright"]
build:
patterns: ["vite", "rollup", "esbuild"]
Em vez de 20 PRs por semana, 3-4 PRs agupados. Mais facil de revisar.
Socket.dev e a analise comportamental.
Socket nao olha so o codigo - executa
em sandbox e observa o que o pacote
faz. Comportamentos flagged:
- Acesso a
process.env(rouba env vars). - Network requests durante install.
- Crypto operations (mining, credential encoding).
- Spawn de subprocessos.
Em 2026, Socket tem free tier pra OSS e flagou centenas de pacotes antes de serem reportados manualmente.
pnpm audit --prod em CI - ignorar
devDependencies. A maioria das CVEs
em dev deps nao afeta prod (vite, jest,
etc - nao vao pro bundle). Em CI:
# Ignora devDeps
pnpm audit --prod
# Ou em Snyk
npx snyk test --prod
Reduz falsos positivos em apps onde devs adicionam deps "experimentais".
openssf scorecard - score de saude
do projeto open source. O OpenSSF
Security Scorecard da um score 0-10
pro projeto open source baseado em:
- Branch protection ativado.
- 2FA no mantenedor.
- Signed releases.
- CI com testes.
- License + community.
- Resposta a issues de seguranca.
Antes de adicionar uma dep nova, checar
scorecard.dev/viewer?uri=github.com/<owner>/<repo>.
Score < 5 = red flag.
npm install --dry-run - ver o que
instalaria sem instalar. Util pra
auditar antes de commitar:
pnpm install --dry-run
# Lista o que seria adicionado/atualizado
Em code review, git diff package-lock.json
mostra o diff de versoes - revisa se
faz sentido.
provenance attestation - SLSA levels.
SLSA (Supply-chain Levels for Software
Artifacts) e' o framework do Google/OpenSSF
pra defender supply chain. Em 2026:
- SLSA L1: build automatizado.
- SLSA L2: signed provenance.
- SLSA L3: hardened build (isolated).
- SLSA L4: two-party review.
GitHub Actions + npm provenance ja te da SLSA L2. Pra L3+, precisa de builds isolados (GitHub Reuse Actions, etc).
Leitura recomendada:
- npm - package-lock.json - doc oficial do npm.
- GitHub - Dependabot security updates - doc oficial Dependabot.
- Snyk - Vulnerability DB - database de vulns (free, sem login).
- OpenSSF - Supply Chain Security guide - recursos OpenSSF.
Dica: o erro mais comum em supply chain e' tratar como "outro time" resolve. "A gente tem 200 deps, nao da pra auditar cada uma." Real. Mas da pra:
- Lockfile commitado (1 commit).
pnpm audit --prodem CI (1 job).- Dependabot/Renovate (1 config file).
- Snyk ou Socket (1 servico).
4 mudancas, 1 dia de trabalho. Cobre 90% dos ataques reais (Log4Shell, ua-parser-js, etc). O ultimo 10% exige SBOM, signed commits, e SLSA - mas isso e' pra apps regulados. Pra 95% dos apps, o baseline ja resolve.
No proximo no, vamos ao projeto final: pegar uma SPA real, fazer threat model, aplicar os 6 controles (XSS prevention, CSP, CORS, SameSite cookies, storage seguro, headers de hardening), validar contra OWASP Top 10, e gerar relatorio.
// Quiz
Por que SEMPRE commitar o package-lock.json e usar `npm ci` em CI?