Triaje de bugs
Llega un mensaje al chat del equipo:
Creo que los clientes pueden ver los pedidos de otros clientes.
Eso podría ser urgente. Podría ser un malentendido. Todavía nadie lo sabe.
El triaje de bugs es el trabajo que ocurre entre "alguien encontró algo" y "el equipo sabe qué hacer a continuación".
Para los bugs de seguridad, el triaje responde cuatro preguntas:
- ¿Podemos reproducirlo?
- ¿Qué daño causa?
- ¿Qué tan difícil es explotarlo?
- ¿Qué pasa después?
Reproduce el bug
Un hallazgo de seguridad es solo una afirmación hasta que alguien logra reproducirlo a propósito.
Empieza por la ruta vulnerable:
app.get('/orders/:id', async (req, res) => {
const order = await db.orders.findById(req.params.id)
res.json(order)
})Ahora escribe la reproducción:
# Con sesión iniciada como cliente 4102
curl -i https://app.example.com/orders/88213 \
-H "Cookie: sid=<sesión del cliente 4102>"
# Esperado: 403 o 404
# Real: 200, con el pedido de otro clienteUna buena reproducción incluye la cuenta, la solicitud, el resultado esperado y el resultado real.
"Cambias el id y se rompe" es una nota. El bloque de arriba es algo que otro desarrollador puede ejecutar.
Prueba solo donde tengas permiso
Ejecuta reproducciones únicamente contra sistemas que sean tuyos, que mantengas, o para los que tengas permiso escrito de hacer pruebas.
Hacer la misma solicitud contra la app de otra persona no es triaje.
Escribe la cuenta, la solicitud, qué debería haber pasado y qué pasó en realidad. Si otro desarrollador puede seguirla sin tener que preguntar nada, tienes un reporte útil.
Explica el impacto
Impacto significa qué termina obteniendo o haciendo la persona que usa el bug.
Para el bug del pedido, el impacto podría ser:
Cualquier cliente con sesión iniciada puede leer la dirección de entrega y el historial de pedidos de otro cliente.
Esa frase es mejor que:
IDOR en
/orders/:id.
IDOR es el nombre técnico de seguridad: referencia directa insegura a un objeto (insecure direct object reference). Significa que una solicitud incluye el id de un objeto y el servidor no verifica si quien la hace tiene permiso de usar ese objeto.
El nombre ayuda a los ingenieros a clasificar el bug. El impacto ayuda a todos a entender por qué importa.
Pregunta:
- ¿Qué dato o acción queda expuesto?
- ¿De quién son esos datos o esa acción?
- ¿A cuántas personas podría afectar?
- ¿Qué podría habilitar esto después?
La severidad empieza por el daño, no por lo ingenioso que sea el bug.
Los nombres técnicos de seguridad son útiles, pero no bastan por sí solos. "Cualquier cliente puede leer la dirección de otro cliente" le dice a más gente por qué importa que "IDOR".
Evalúa la explotabilidad
El impacto te dice qué puede hacer el bug. La explotabilidad te dice qué se necesita para lograrlo.
Para el bug del pedido, el atacante necesita:
- una cuenta de cliente normal
- un id de pedido válido o adivinable
- una solicitud
Eso es altamente alcanzable. Un bug que requiere una cuenta de administrador, acceso físico, un momento preciso y que la víctima haga clic en algo es muy distinto.
Anota las condiciones previas. Eso mantiene concreta la conversación sobre la severidad.
| Condiciones previas | Qué significa |
|---|---|
| Anónimo | Cualquiera en internet puede intentarlo. |
| Con sesión iniciada | Se necesita una cuenta normal. |
| Rol privilegiado | Se necesita un rol de staff o administrador. |
| Acción de la víctima | Otra persona debe hacer clic o enviar algo. |
| Id adivinable | El objetivo se puede encontrar probando valores. |
| Ventana de tiempo | El bug solo funciona durante un momento acotado. |
Anónimo es más fácil de alcanzar que con sesión iniciada. Con sesión iniciada es más fácil de alcanzar que administrador. Una sola solicitud es más fácil de alcanzar que una cadena que necesita sincronización y que otra persona haga clic en algo.
Decide qué pasa después
Ahora combina las piezas:
| Campo | Ejemplo |
|---|---|
| Reproducción | El cliente 4102 solicita el pedido 88213 y recibe el pedido de otro cliente. |
| Impacto | Cualquier cliente con sesión iniciada puede leer la dirección de entrega y el historial de pedidos de otro cliente. |
| Explotabilidad | Cuenta normal, id adivinable, una sola solicitud. |
| Categoría OWASP | A01 Control de acceso roto. |
| Próxima acción | Corregir antes del lanzamiento, agregar una prueba de propiedad, revisar rutas similares. |
La categoría OWASP ayuda a clasificar el bug. La próxima acción convierte el reporte en trabajo concreto.
Para este bug, la solución es verificar la propiedad antes de devolver el pedido:
app.get('/orders/:id', async (req, res) => {
const order = await db.orders.findById(req.params.id)
if (!order || order.userId !== req.user.id) {
return res.status(404).json({ error: 'Order not found' })
}
res.json(order)
})La prueba correspondiente debe demostrar el camino incorrecto, no solo el camino esperado.
Una buena nota de triaje genera trabajo de seguimiento
Corregir este endpoint.
Agregar una prueba de regresión.
Buscar el mismo patrón en rutas cercanas.
Para este bug del pedido, la decisión debería ser directa: corregirlo antes del lanzamiento, agregar una prueba, y revisar rutas cercanas por si les falta la misma verificación de propiedad.
Ponlo en práctica
Llega un reporte de bug con una sola línea: "El enlace para restablecer la contraseña sigue funcionando después de haberlo usado."
Hazle el triaje. Completa los cinco campos: reproducción, impacto, explotabilidad, categoría OWASP, próxima acción.
Compara tus respuestas
| Campo | Una respuesta razonable |
|---|---|
| Reproducción | Solicita un restablecimiento, sigue el enlace, define una contraseña y luego abre el mismo enlace otra vez. Todavía se acepta y permite definir otra contraseña. |
| Impacto | Cualquiera que vea ese enlace, aunque sea una sola vez, puede tomar el control de la cuenta después. Los enlaces de restablecimiento permanecen mucho tiempo en bandejas de entrada, historial del navegador y correos reenviados. |
| Explotabilidad | No se necesita ninguna cuenta ni adivinar nada. Requiere tener acceso al enlace, así que la dificultad depende por completo de a dónde haya viajado ese enlace. |
| Categoría OWASP | A07 Fallas de autenticación. La aplicación no puede establecer de forma confiable quién es alguien cuando una credencial ya usada sigue funcionando. |
| Próxima acción | Invalidar el token en el primer uso y agregar una expiración si no la tiene. Luego revisar si la verificación de correo y los enlaces de invitación tienen la misma falla. |
Vale la pena resaltar dos cosas.
El impacto no es "un token no se invalida", es "alguien puede tomar el control de la cuenta". Un campo que solo repite el bug no aporta nada; el campo existe para decir a quién se perjudica.
Y la próxima acción termina mirando hacia los lados. Los tokens de un solo uso normalmente se generan con código compartido, así que un bug en un flujo suele estar presente también en los demás. Un triaje que corrige exactamente una ruta y se detiene ahí solo hizo la mitad del trabajo.
Hacia dónde va esto
El triaje de bugs cierra la primera sección. Ahora ya puedes preguntarte qué podría salir mal, nombrar bugs comunes en producción, y convertir un hallazgo en trabajo concreto.
A continuación, el manual pasa a la seguridad de entradas y datos, empezando por nunca confíes en la entrada del usuario.

