El informe llega en PDF con portada, un resumen ejecutivo y treinta hallazgos de color rojo, naranja y amarillo. Es fácil tratarlo como un artefacto de cumplimiento: archivarlo, abrir unos cuantos tickets y esperar al año que viene. Eso desperdicia casi todo lo que pagaste.
Léelo como leerías una exportación de un bug tracker. Cada hallazgo es un bug con su reproducción. Tu trabajo es entenderlo, arreglar la causa y evitar que vuelva.
Triage: la severidad es un punto de partida
Los testers puntúan los hallazgos con un esquema como CVSS más su criterio. Es un buen primer filtro, pero no conocen tu contexto tan bien como tú. Vuelve a puntuar cada hallazgo con tres preguntas:
- ¿Quién puede llegar hasta ahí? ¿Un usuario anónimo de internet, cualquier cliente con sesión iniciada o un administrador interno?
- ¿Qué les da? ¿Datos de una cuenta, datos de todas las cuentas, ejecución de código o una página de error ligeramente engañosa?
- ¿Con qué se encadena? Una fuga de información de severidad baja puede ser el primer paso que haga explotable un bug de severidad media.
Agrupa los hallazgos en tres cubos: corregir ya, corregir este sprint, y aceptar o planificar con una razón por escrito. Los riesgos aceptados deben tener un responsable y una fecha de revisión, no solo un comentario en una hoja de cálculo.
Reproduce antes de arreglar
No arregles lo que no has visto fallar. Usa la evidencia del tester, normalmente peticiones y respuestas HTTP, para reproducir cada hallazgo en un entorno que no sea de producción.
# 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
Si no puedes reproducirlo, no lo cierres. Pregunta a los testers. El hallazgo puede depender de un rol, un feature flag o datos que no tienes en staging. Cerrar un hallazgo no reproducido como "no se puede reproducir" es como sobreviven los bugs reales.
Reproducir también te dice dónde vive realmente el bug. El informe nombra un endpoint; tu debugger te dice qué función compartida falló.
Corrige la causa raíz, no la línea
Un tester tiene tiempo limitado. Si encontró autorización ausente en un endpoint, probablemente hay otros a los que no llegó. Pregunta: ¿qué patrón permitió que pasara?
| Hallazgo tal como se reportó | Corrección acotada | Arreglo de la causa raíz |
|---|---|---|
IDOR en /invoices/{id} | Añade una comprobación de propietario a ese handler | Acota por tenant todas las consultas de objetos en la capa de datos |
| XSS reflejado en la búsqueda | Escapa ese parámetro | Activa el auto-escaping de plantillas en todas partes; añade un CSP |
| Stack trace detallado | Captura esa excepción | Manejador global de errores que nunca devuelve detalles internos en producción |
| Política de contraseñas débil | Subir la longitud mínima | Sigue los requisitos de autenticación de OWASP ASVS; añade rate limiting |
Cuando conoces el patrón, búscalo. Una regla de Semgrep o un simple grep de la llamada insegura suele encontrar a las hermanas que el tester nunca vio.
Pide un retest que signifique algo
La mayoría de los engagements incluyen una ventana de retest. Aprovéchala bien:
- Envía a los testers una lista de IDs de hallazgos, la corrección y el commit o la release que la incluye.
- Anota dónde corregiste la clase y no la instancia, para que puedan probar también las hermanas.
- Pídeles que lo confirmen con la misma técnica que usaron originalmente, más una variación.
- Consigue el resultado del retest por escrito y adjúntalo al ticket.
Un retest que solo comprueba la petición original exacta es una señal débil. Un cambio de un carácter en un payload suele sortear un arreglo estrecho.
Convierte cada hallazgo en un test de regresión
Este es el paso que la mayoría de los equipos se salta, y el que se acumula con el tiempo. Un hallazgo de pentest es un caso de prueba perfecto: una entrada mala conocida y un resultado correcto conocido. Codifícalo para que la línea rechace el bug automáticamente la 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)
Etiqueta estos tests para ejecutarlos como suite y deja el ID del hallazgo en un comentario, para que quien vea un fallo sepa por qué existe el test. Tras varios proyectos tendrás una suite de regresión de seguridad moldeada por ataques reales a tu propio producto.
Qué hacer el lunes
- Vuelve a puntuar los hallazgos con las preguntas de alcance, impacto y encadenamiento.
- Reproduce los cinco primeros en staging y anota la causa raíz de cada uno.
- Busca en el código los hermanos de cada causa raíz.
- Escribe una prueba de regresión por hallazgo como parte del arreglo, no después.
- Reserva el retest con una lista clara de lo que cambió.
El informe del año que viene debería ser más corto y contener bugs nuevos, no los viejos en sitios nuevos. Más sobre cómo hacemos las pruebas en la página de pentest.