Audite Dependências em Busca de Vulnerabilidades
Pegue um projeto pequeno com dependências propositalmente desatualizadas, rode uma auditoria de vulnerabilidades, leia o relatório como um engenheiro de segurança, corrija os pacotes vulneráveis e confirme que a auditoria volta limpa — exatamente o passo "audit" do Ralph Loop do DARE.
Problema
Toda aplicação que você entrega é construída em cima de centenas de pedaços de código que você não escreveu: suas dependências, e as dependências *delas* (as "transitivas", que você nunca escolheu diretamente). Qualquer uma delas pode carregar uma vulnerabilidade conhecida e publicamente divulgada — um CVE (Common Vulnerabilities and Exposures) — que um atacante pode explorar assim que sua aplicação estiver acessível numa rede. Este não é um risco hipotético. Ataques de supply chain e dependências com vulnerabilidades conhecidas são uma das formas mais comuns de sistemas de produção reais serem comprometidos, precisamente *porque* são invisíveis no dia a dia da revisão de código — ninguém lê o diff de um `package-lock.json` linha por linha. A correção não é "confiar cegamente nas dependências" nem "revisar cada linha de cada biblioteca" (inviável). É a **auditoria automatizada de dependências**: ferramentas que cruzam cada pacote e versão do seu projeto contra um banco de dados de vulnerabilidades e te dizem, em segundos, exatamente quais são perigosos, o quanto, e o que fazer a respeito. Neste lab você vai trabalhar com um projeto de exemplo pequeno que tem algumas dependências fixadas propositalmente em versões antigas e vulneráveis. Você vai rodar uma ferramenta de auditoria, aprender a ler o relatório dela (severidade, identificador CVE, o caminho de dependência que trouxe o pacote vulnerável), corrigir cada achado atualizando ou substituindo a dependência, e rodar a auditoria de novo até ficar limpa. Você vai terminar conectando isso diretamente ao método DARE: audit é o quarto e último portão do **Ralph Loop** (build → test → lint → audit), e uma task nunca está DONE enquanto restar um CVE HIGH/CRITICAL aberto. > Este lab é stack-agnóstico. As instruções são dadas tanto para uma amostra > em Node.js (usando `npm audit`) quanto para uma amostra em Python (usando > `pip-audit`) — escolha a stack que você já tiver instalada. Trabalhe só > contra seu próprio projeto de exemplo local; nunca escaneie ou ataque um > projeto que não é seu.
Objetivos
Ao final deste lab você será capaz de:
- Explicar o que é um CVE, como funcionam as pontuações de severidade
(CVSS: low/moderate/high/critical) e por que dependências transitivas
importam tanto quanto as diretas. - Rodar
npm auditoupip-auditcontra um projeto real e ler o relatório:
nome do pacote, versão instalada, faixa vulnerável, versão corrigida,
severidade e o caminho de dependência. - Distinguir uma dependência vulnerável direta de uma transitiva, e
conhecer as diferentes estratégias de correção para cada uma. - Corrigir vulnerabilidades atualizando uma versão, usando um corretor
automatizado (npm audit fix), ou substituindo um pacote inteiramente
quando não existe versão corrigida. - Rodar a auditoria de novo para confirmar que zero achados HIGH/CRITICAL
restam, e explicar por que um achado moderate/low pode ser aceito com um
motivo documentado em vez de bloquear um release. - Conectar a auditoria de dependências ao Ralph Loop do DARE e explicar por
que "audit" é um portão obrigatório, não-opcional, antes de marcar uma
task como DONE.
Pré-requisitos
- Node.js 18+ com
npmou Python 3.9+ compip(só uma stack é
necessária; escolha a que você já tiver). -
pip-auditinstalado se você escolher o caminho Python:
pip install pip-audit. - Um terminal e um editor de texto simples.
- Acesso à internet (as ferramentas de auditoria consultam um banco de
dados público de vulnerabilidades). - Nenhuma experiência prévia em segurança é exigida — este lab ensina o
fluxo do zero.
O que você vai construir
Um projeto de exemplo minúsculo (Node.js ou Python, à sua escolha) com
algumas dependências fixadas em versões antigas e conhecidamente
vulneráveis. Você vai auditá-lo, corrigi-lo e provar — com saída de
ferramenta, não achismo — que ele está limpo.
Por que "audit" é seu próprio passo do Ralph Loop
O Ralph Loop do DARE é build → test → lint → audit. Os três primeiros
passos te dizem que o seu próprio código funciona. O audit te diz se o
código sobre o qual você está em pé é seguro. São preocupações
ortogonais:
- Um projeto pode buildar, passar em todo teste e estar perfeitamente
lintado — e ainda assim entregar um cliente Redis com um CVE de execução
remota de código porque ninguém atualizou a versão em catorze meses. - Achados de auditoria não são "seu bug" no sentido de que você escreveu a
falha, mas são sua responsabilidade no momento em que você os entrega
— a vulnerabilidade roda com os privilégios da sua aplicação, no seu
ambiente de produção, contra os dados dos seus usuários.
É por isso que a regra do DARE é direta: um CVE classificado como HIGH ou
CRITICAL na sua árvore de dependências significa que a task está FAILED, não
DONE, até ser corrigido. Achados moderate/low às vezes podem ser aceitos
com uma justificativa escrita (ex.: "só alcançável num caminho de código
exclusivo de dev"), mas HIGH/CRITICAL nunca passa.
Anatomia de um relatório de vulnerabilidade
Toda ferramenta de auditoria reporta aproximadamente o mesmo formato de
informação por achado:
| Campo | Significado |
|---|---|
| Pacote | O nome da dependência vulnerável |
| Versão instalada | A versão atualmente no seu lockfile |
| Faixa vulnerável | A faixa de versões afetada (ex.: < 4.17.21) |
| Versão corrigida | A primeira versão onde a correção chegou |
| Severidade | low / moderate / high / critical (derivada de uma pontuação CVSS) |
| Identificador | Um CVE ID (ex.: CVE-2021-23337) ou advisory ID (ex.: GHSA-...) |
| Caminho | A cadeia de dependências que trouxe esse pacote — é direto ou transitivo? |
O caminho é o campo mais útil para decidir sua estratégia de correção.
Se o seu package.json lista o pacote vulnerável diretamente, muitas vezes
você mesmo pode simplesmente subir a versão. Se ele está três níveis dentro
da dependência de outra pessoa, talvez você precise atualizar o pacote pai
em vez disso, ou esperar o mantenedor lançar uma versão corrigida.
Como trabalhar neste lab
Escolha uma stack (Node.js ou Python) e siga essa trilha pelos cinco
passos — o projeto de exemplo, as dependências vulneráveis e os comandos
exatos variam um pouco por stack, mas o fluxo (auditar → ler → corrigir →
reauditar → conectar ao Ralph Loop) é idêntico nas duas.
Passos
-
Monte um projeto de exemplo com dependências vulneráveis
Crie um diretório local novo e fixe algumas dependências em versões
antigas e conhecidamente vulneráveis de propósito. Escolha sua stack.Trilha Node.js
mkdir audit-lab && cd audit-lab npm init -y npm install lodash@4.17.15 minimist@1.2.5 axios@0.21.0Essas três versões antigas específicas são uma escolha deliberada:
-
lodash@4.17.15— prototype pollution (corrigido na 4.17.21). -
minimist@1.2.5— prototype pollution (corrigido na 1.2.6). -
axios@0.21.0— Server-Side Request Forgery via tratamento de
redirect (corrigido em versões posteriores 0.21.x/1.x).
Trilha Python
mkdir audit-lab && cd audit-lab python -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate pip install "requests==2.25.1" "urllib3==1.26.4" "Jinja2==2.11.2" pip freeze > requirements.txtEstas também são propositalmente antigas:
-
requests==2.25.1eurllib3==1.26.4— vários CVEs em torno do
tratamento de proxy/credenciais e comportamento de retry naquela era. -
Jinja2==2.11.2— uma classe de vulnerabilidade de escape de
sandbox, corrigida em versões posteriores 2.11.x/3.x.
Checkpoint
Confirme que os pacotes realmente instalaram nas versões antigas
fixadas:# Node npm ls lodash minimist axios # Python pip show requests urllib3 Jinja2Você deve ver exatamente os números de versão antigos que especificou —
se o npm ou o pip resolveram silenciosamente algo mais novo, refixe
com a sintaxe de versão exata mostrada acima.Entregável deste passo: um diretório de projeto local com um
lockfile (package-lock.jsonourequirements.txt) que fixa essas
versões antigas e vulneráveis, confirmado pela saída do comando de
checkpoint. -
-
Rode a auditoria e leia o relatório bruto
Agora rode a ferramenta de auditoria da sua stack e olhe a saída
bruta, sem filtro antes de fazer qualquer outra coisa — resista à
vontade de pular direto para--fix. Você precisa conseguir ler esse
relatório manualmente.Trilha Node.js
npm auditVocê vai ver, para cada achado, algo como:
# npm audit report lodash <4.17.21 Severity: high Prototype Pollution in lodash - https://github.com/advisories/GHSA-... fix available via `npm audit fix` node_modules/lodash axios <=0.21.1 Severity: moderate Server-Side Request Forgery in axios - https://github.com/advisories/GHSA-... fix available via `npm audit fix` node_modules/axios 2 vulnerabilities (1 moderate, 1 high)Para uma versão legível por máquina (útil para CI ou scripting):
npm audit --json > audit-report.jsonTrilha Python
pip-audit -r requirements.txtA saída fica assim:
Name Version ID Fix Versions -------- -------- ------------------- ------------ requests 2.25.1 PYSEC-2021-136 2.25.1... (veja fix versions) urllib3 1.26.4 PYSEC-2021-108 1.26.5 Jinja2 2.11.2 PYSEC-2021-66 2.11.3Para saída em JSON:
pip-audit -r requirements.txt -f json > audit-report.jsonLeia cada coluna antes de tocar em qualquer coisa
Para cada achado do seu relatório, anote (no papel ou num arquivo
de rascunho) estas quatro coisas:- Pacote + versão instalada — o que você realmente tem.
- Severidade — low / moderate / high / critical.
-
Identificador — o CVE ou GHSA/PYSEC ID, para você poder buscar o
advisory completo se precisasse de mais detalhe. -
É direto ou transitivo? Confira seu
package.json/requirements.txt
— se o pacote está listado lá pelo nome, é direto; se ele só aparece
no lockfile trazido por outra coisa, é transitivo.
Checkpoint
Você deve conseguir responder, sem rodar a ferramenta de novo: "Qual
achado é o mais severo, e é um pacote que eu instalei diretamente ou um
que veio de carona?" Se você não conseguir responder isso a partir das
suas notas, releia o relatório.Entregável deste passo: uma lista curta escrita de cada achado
(pacote, severidade, ID, direto/transitivo) mais o arquivo de relatório
JSON salvo. -
Corrija cada achado — atualize, auto-corrija ou substitua
Existem três estratégias de correção, em ordem de preferência. Tente
nesta ordem para cada achado.Estratégia 1 — corretor automatizado
As ferramentas de auditoria trazem um corretor que sobe para a menor
versão corrigida que satisfaz sua faixa semver existente, e reinstala.# Node npm audit fix # Python não tem equivalente direto; atualize manualmente (Estratégia 2)npm audit fixé seguro para bumps patch/minor dentro da sua faixa
declarada. Ele não vai cruzar um bump de versão major sozinho (isso
precisa denpm audit fix --force, que você deve tratar como uma
atualização de verdade — leia o changelog antes, pode ser uma mudança
que quebra compatibilidade).Estratégia 2 — bump manual de versão
Quando o corretor não alcança longe o suficiente, ou você está em
Python, suba a versão explicitamente para (ou além de) a versão
corrigida do relatório.# Node — sobe uma dependência direta além da versão corrigida npm install lodash@^4.17.21 axios@^0.21.4 # Python — edite requirements.txt, depois reinstale pip install --upgrade "requests>=2.31.0" "urllib3>=1.26.18" "Jinja2>=3.1.3" pip freeze > requirements.txtSempre releia o código real do seu projeto depois de um bump de versão
— especialmente através de uma versão major — para checar mudanças
de API que quebram compatibilidade. É aqui que sua suíte de testes se
justifica (veja o checkpoint abaixo).Estratégia 3 — substitua a dependência
Às vezes não existe versão corrigida (o pacote foi abandonado) ou a
versão corrigida exige um runtime que você ainda não pode adotar. Nesse
caso:- Procure um fork ativamente mantido ou um pacote alternativo que cubra
a mesma funcionalidade. - Se o caminho de código vulnerável não é realmente alcançável a partir
da sua aplicação (ex.: uma ferramenta exclusiva de dev), você pode
fazer vendor de um patch ou aceitar o risco com uma justificativa
escrita — nunca silenciosamente.
Corrija os achados do seu lab agora
Aplique o corretor/atualização para cada pacote que você auditou no
Passo 2. Para os pacotes específicos deste lab:# Node npm audit fix npm install lodash@^4.17.21 # se o audit fix não alcançou # Python pip install --upgrade "requests>=2.31.0" "urllib3>=1.26.18" "Jinja2>=3.1.3" pip freeze > requirements.txtCheckpoint
Depois de cada correção, rode o que servir de "testes" no seu projeto
de exemplo (mesmo um script de smoke trivial que importa/requer cada
pacote e chama uma função) para confirmar que nada quebrou:# Node node -e "console.log(require('lodash').chunk([1,2,3,4],2))" # Python python -c "import requests, jinja2; print('ok')"Uma auditoria limpa que quebrou sua aplicação não está de fato pronta —
ela só moveu o problema. É exatamente por isso que "audit" fica depois
de "test" no Ralph Loop, não antes: você roda test de novo depois de
cada correção, não só no final.Entregável deste passo: lockfile/
requirements.txtatualizado com
versões corrigidas, mais a confirmação de que o smoke check ainda passa. - Procure um fork ativamente mantido ou um pacote alternativo que cubra
-
Rode a auditoria de novo e confirme um relatório limpo
Rode exatamente o mesmo comando de auditoria do Passo 2 de novo. Este é
o passo de verificação — você não está pronto porque acha que
corrigiu, está pronto porque a ferramenta diz que sim.# Node npm audit # Python pip-audit -r requirements.txtSaída limpa esperada:
# npm audit report found 0 vulnerabilitiesNo known vulnerabilities foundSe algum achado permanecer
-
Recheque a severidade. Se for HIGH/CRITICAL, volte ao Passo 3 —
isso não é opcional sob a regra do Ralph Loop do DARE. -
Se for moderate/low e ainda não existir correção, este é o único
caso em que você pode prosseguir — mas só com uma nota escrita e
datada explicando: qual pacote, qual CVE, por que não é alcançável
ou por que o risco é aceito, e um lembrete para reverificar na próxima
vez que mexer nas dependências. Nunca deixe uma nota de risco aceito
sem escrever — um "resolvo depois" não documentado é como
vulnerabilidades sobrevivem por anos.
Configure o gate de CI de verdade
Num projeto real, essa checagem deveria rodar automaticamente e falhar
o build em HIGH/CRITICAL, para que ninguém consiga mesclar uma
dependência recém-vulnerável por acidente:# Node — sai com código diferente de zero se achar HIGH ou acima npm audit --audit-level=high # Python — pip-audit sai com código diferente de zero em qualquer achado por padrão pip-audit -r requirements.txtTente rodar
npm audit --audit-level=highvocê mesmo agora e confira o
código de saída:npm audit --audit-level=high; echo "exit code: $?"Um código de saída
0significa limpo; qualquer outra coisa significa
que o gate de auditoria bloquearia um pipeline de CI — exatamente o
comportamento que você quer.Checkpoint
Você deve ter agora:
- Um relatório "antes" (do Passo 2) mostrando pelo menos um achado
HIGH/moderate. - Um relatório "depois" mostrando zero achados HIGH/CRITICAL (ou uma
nota documentada de risco aceito para o que restar). - Um comando (
npm audit --audit-level=highoupip-audit) que sai
com0— o comando exato que você conectaria ao CI.
Entregável deste passo: a saída limpa da auditoria, salva lado a
lado com o relatório "antes" do Passo 2, mais o comando de gate de CI e
seu código de saída. -
Recheque a severidade. Se for HIGH/CRITICAL, volte ao Passo 3 —
-
Conecte o audit ao Ralph Loop do DARE (submissão)
Você praticou o fluxo completo manualmente. Agora formalize-o como o
quarto passo do seu Ralph Loop, do jeito que uma task DARE real o
definiria na sua Definition of Done.Escreva a sequência de comandos do Ralph Loop
Para o seu projeto de exemplo, escreva os quatro comandos que a DoD de
uma task exigiria, em ordem — é exatamente o que uma IA executando uma
task DARE rodaria antes de marcar qualquer coisa como DONE:# 1. Build # (Node) — nenhum passo de compilação necessário para JS puro, ou: npm run build # (Python) — python -m py_compile *.py, ou o passo de build do seu framework # 2. Test # (Node) — npm test # (Python) — python -m pytest # 3. Lint # (Node) — npx eslint . # (Python) — ruff check . # 4. Audit <-- o que você praticou neste lab npm audit --audit-level=high # ou pip-audit -r requirements.txtEscreva a regra da DoD em linguagem simples
Adicione esta linha a um
NOTES.md(ou oTASKS.mddo seu projeto, se
tiver um) — é a regra que você vai aplicar a partir de agora em toda
task futura:## Definition of Done — auditoria de dependências Uma task está DONE somente se: - `npm audit --audit-level=high` (ou `pip-audit`) sai com código 0, E - Qualquer achado moderate/low restante tem uma justificativa escrita e datada explicando por que não é alcançável ou por que o risco é aceito. Um achado HIGH ou CRITICAL em qualquer lugar da árvore de dependências significa que a task está FAILED, não importa quão completo esteja o código da feature.Por que isso vai no fim do loop, não no início
O audit roda por último porque deveria funcionar como portão para
tudo o resto — não faz sentido auditar dependências antes mesmo do
seu código buildar. Mas ele ainda precisa rodar em toda task que
mexe em dependências, não só uma vez na configuração do projeto: um
novo PR que adiciona um único pacote novo é uma nova superfície de
auditoria, e pular isso é como dependências vulneráveis entram em
bases de código "confiáveis".Critério de submissão
Submeta quando tudo o que segue for verdade:
- Um par de relatórios antes/depois de auditoria do seu projeto de
exemplo (Passo 2 e Passo 4), mostrando pelo menos um achado
HIGH ou moderate corrigido. - O comando exato de gate de CI para sua stack
(npm audit --audit-level=highoupip-audit -r requirements.txt)
com um código de saída0confirmado. - Um
NOTES.mdcurto com a sequência de quatro comandos do Ralph Loop
e a regra da Definition of Done para auditorias de dependências,
escrita com suas próprias palavras. - Se algum achado permanecer sem resolução, uma justificativa escrita
e datada para ele — nunca um achado silenciosamente ignorado.
- Um par de relatórios antes/depois de auditoria do seu projeto de