O relatório chega como um PDF com capa, um resumo executivo e trinta achados a vermelho, laranja e amarelo. É fácil tratá-lo como um artefacto de compliance: arquivá-lo, abrir alguns tickets, esperar pelo próximo ano. Isso desperdiça a maior parte do que pagou.
Leia-o como leria uma exportação de um bug tracker. Cada achado é um bug com uma reprodução. O seu trabalho é percebê-lo, corrigir a causa e impedir que volte.
Triage: a severidade é um ponto de partida
Os testers classificam os achados com um esquema como o CVSS mais o seu critério. É uma primeira ordenação útil, mas não conhecem o seu contexto tão bem como a sua equipa. Reclassifique cada achado com três perguntas:
- Quem lhe consegue chegar? Um utilizador anónimo da internet, qualquer cliente com sessão iniciada, ou um admin interno?
- O que é que lhes dá? Dados de uma conta, dados de todas as contas, execução de código, ou uma página de erro ligeiramente enganadora?
- Com que é que se encadeia? Uma fuga de informação classificada como baixa pode ser o primeiro passo que torna explorável um bug classificado como médio.
Agrupe os achados em três buckets: corrigir já, corrigir neste sprint, e aceitar ou agendar com uma razão escrita. Os riscos aceites devem ter um responsável e uma data de revisão, não apenas um comentário numa folha de cálculo.
Reproduza antes de corrigir
Não corrija o que não viu falhar. Use as evidências do tester, normalmente pedidos e respostas HTTP, para reproduzir cada achado num ambiente que não seja de produção.
# Example: IDOR finding, reproduced with two test accounts
# Account A's session, requesting Account B's invoice
curl -s -H "Authorization: Bearer $TOKEN_USER_A" \
https://staging.example.test/api/invoices/10432 | jq .owner_id
Se não o consegue reproduzir, não o feche. Pergunte aos testers. O achado pode depender de um papel, de uma feature flag ou de dados que não tem em staging. Fechar um achado não reproduzido como "não reproduzível" é a forma como os bugs reais sobrevivem.
A reprodução também lhe diz onde o bug vive realmente. O relatório nomeia um endpoint; o seu debugger diz-lhe que função partilhada falhou.
Corrija a causa raiz, não a linha
Um tester tem tempo limitado. Se encontrou falta de autorização num endpoint, há provavelmente outros a que não chegou. Pergunte: que padrão permitiu que isto acontecesse?
| Achado conforme reportado | Correção pontual | Correção da causa raiz |
|---|---|---|
IDOR em /invoices/{id} | Adicionar uma verificação de owner a esse handler | Restrinja todas as pesquisas de objetos por tenant na camada de dados |
| XSS refletido na pesquisa | Escapar esse parâmetro | Ative o auto-escaping de templates em todo o lado; acrescente uma CSP |
| Stack trace verboso | Apanhar essa exceção | Handler de erros global que nunca devolve detalhes internos em produção |
| Política de passwords fraca | Aumentar o comprimento mínimo | Seguir os requisitos de autenticação do OWASP ASVS; acrescentar rate limiting |
Quando conhece o padrão, procure-o. Uma regra Semgrep ou um simples grep pela chamada insegura encontra muitas vezes os casos irmãos que o tester nunca viu.
Peça um reteste que signifique alguma coisa
A maioria dos trabalhos inclui uma janela de reteste. Aproveite-a bem:
- Envie aos testers uma lista de IDs de achados, a correção e o commit ou release que a contém.
- Indique onde corrigiu a classe e não a instância, para que também possam testar os casos irmãos.
- Peça-lhes que confirmem com a mesma técnica que usaram originalmente, mais uma variação.
- Obtenha o resultado do reteste por escrito e anexe-o ao ticket.
Um reteste que só verifica o pedido original exato é um sinal fraco. Uma alteração de um carácter num payload contorna muitas vezes uma correção estreita.
Transforme cada achado num teste de regressão
Este é o passo que a maioria das equipas salta, e é o que se acumula. Um achado de pentest é um caso de teste perfeito: um input conhecido como mau e um resultado conhecido como correto. Codifique-o para que a linha rejeite o bug automaticamente da próxima vez.
# tests/security/test_invoice_access.py
import pytest
@pytest.mark.security
def test_user_cannot_read_another_users_invoice(client, user_a, user_b):
invoice = user_b.create_invoice()
resp = client.get(
f"/api/invoices/{invoice.id}",
headers=user_a.auth_headers(),
)
# Pentest finding PT-2026-07: was 200 with user B's data
assert resp.status_code in (403, 404)
Marque estes testes para os poder correr como uma suite e mantenha o ID do achado num comentário, para que quem vir uma falha saiba porque é que o teste existe. Ao fim de alguns trabalhos, terá uma suite de regressão de segurança moldada por ataques reais ao seu próprio produto.
O que fazer na segunda-feira
- Reavalie os achados com as perguntas de alcance, impacto e encadeamento.
- Reproduza os cinco primeiros em staging e anote a causa raiz de cada um.
- Procure no código casos irmãos de cada causa raiz.
- Escreva um teste de regressão por achado como parte da correção, não depois.
- Marque o reteste com uma lista clara do que mudou.
O relatório do próximo ano deve ser mais curto e deve conter bugs novos, não os antigos em sítios novos. Mais sobre como fazemos testes na página de pentest.