Multi-Agent Debate para Triage de Vulnerabilidades
Hace unos meses cerramos un finding como falso positivo. Era un endpoint que parecía vulnerable a SSRF: aceptaba una URL del usuario, la procesaba en backend, devolvía contenido. Nuestro pipeline single-model lo marcó como "likely false positive — la URL parece validarse contra una allow-list". Lo dejamos pasar.
Tres semanas después, el cliente nos escribió: un investigador externo había reportado exactamente ese endpoint. El bypass de la allow-list era trivial (un truco con @ en el userinfo de la URL). Daño en imagen, conversación incómoda, y la lección: un solo modelo es un mal triager, sobre todo cuando la evidencia es ambigua.
Por qué un solo modelo es un mal triager
- Sycophancy hacia el contexto. Sharma et al. (2023) muestra que los modelos modernos asienten incluso cuando el usuario está objetivamente equivocado.
- Anclaje en la primera hipótesis. Liang et al. (2023) llaman a esto Degeneration-of-Thought: una vez fijada una solución plausible, el modelo no genera alternativas reales.
- Ausencia de adversarial check. Un triager humano piensa "¿cómo rompería yo esta validación?". Un LLM zero-shot piensa "¿es esto razonable?".
Self-consistency (Wang et al., 2022) mitiga ruido pero no el sesgo sistemático.
Multi-agent debate: Du et al. (2023)
Improving Factuality and Reasoning through Multiagent Debate propone: varias instancias responden independientemente; después cada agente recibe las respuestas de los demás y genera una nueva respuesta condicionada. Se repite N rondas. Salida: consenso o voto.
Lo interesante es que no requiere fine-tuning, ni jueces externos, ni arquitectura especial. Es prompting. La mejora viene de que cada agente, al ver argumentos contrarios, revisa partes de su razonamiento que en aislamiento daba por sentadas.
Nuestra implementación: tres roles, tres rondas, un juez
- Gandalf — modo crítico. Asume que el finding es real y construye el peor escenario de explotación.
- Beorn — modo evidencial. Solo razona sobre artefactos: HTTP responses, headers, body, traces. Le prohibimos inferir comportamiento no demostrado.
- Gwaihir — modo técnico. Razona sobre la arquitectura: stack, framework, defensas conocidas, contexto del sector.
Los tres reciben el mismo paquete. Generan veredicto independiente en ronda 1. En rondas 2-3 cada uno ve los otros y produce una versión revisada. Un agente juez emite el cierre: true_positive, false_positive, needs_manual.
Si tras ronda 2 los tres convergen, saltamos ronda 3. Si tras ronda 3 sigue habiendo desacuerdo, escalamos a humano. Esa regla es deliberada — el desacuerdo persistente entre roles ortogonales es señal informativa.
Ejemplo trazado: SSRF candidato
Ronda 1 — veredictos independientes:
Gandalf: "Posible SSRF.Server: gunicorndistinto del frontend (nginx) sugiere backend hace la petición.?url=http://169.254.169.254/dio 403, pero?url=http://localhost:8080dio 200 con HTML. True positive alta confianza."
Beorn: "Dos requests: una con bypass (200), otra contra metadata (403). El 403 puede ser allow-list o firewall del cloud. Needs manual."
Gwaihir: "Stack Python + gunicorn detrás de nginx en AWS. El 403 es consistente con IMDSv2 forzado, no con mitigación del endpoint. Probable true positive."
Ronda 2:
Gandalf: "Beorn tiene razón en que el 403 no es prueba de mitigación. Pero el 200 contra localhost:8080 sí demuestra acceso interno. Mantengo true positive."
Beorn: "Reviso. La response del 200 incluye HTML de un panel admin interno. Cambio a true positive alta confianza."
Gwaihir: "Coincido. El payload@-trick también pasaría la allow-list. Recomiendo añadir prueba al reporte."
Convergencia en ronda 2. Juez: true_positive. Report con tres líneas de evidencia distintas.
Métricas
3 meses, 1.847 findings (412 ground-truth):
- Precision en true positives: 0.71 (single) → 0.89 (debate).
- Recall: 0.68 → 0.83. El recall importa más que la precision.
- Latencia mediana: 8s → 47s por finding.
- Coste en tokens: ~4.2x single-model.
- Escalado a humano: 3% → 11%. El debate detecta más casos genuinamente ambiguos.
Cuándo NO usar debate
- Severidad baja con evidencia clara (headers de seguridad faltantes). Check determinista basta.
- Decisiones binarias triviales (¿es una API key?). Regex o single-call con critique.
- Pipelines de alta frecuencia. El coste se acumula.
Comparativa rápida
CoT-SC: bueno para ruido, malo para sesgo sistemático.
Tree of Thoughts: excelente para espacios estructurados (Game of 24). Overkill para triage.
Single-call con self-critique: el mismo modelo critica las mismas hipótesis, colapsa al mismo punto fijo.
Multi-agent debate: ganamos cuando hace falta pluralidad de roles y la evidencia es ambigua.
Cierre
El SSRF del cliente nunca debió cerrarse en falso. Lo que aprendimos no es que los LLMs sean malos triagers — es que un solo LLM, por bueno que sea, tiene un único modo de mirar. Forzar pluralidad mediante roles bien definidos no es elegante; es ingeniería pragmática. Si tu pipeline cierra findings ambiguos sin debate, probablemente estás dejando ir vulnerabilidades reales.
Bibliografía
- Du, Y. et al. (2023). Improving Factuality and Reasoning through Multiagent Debate. arXiv:2305.14325.
- Wang, X. et al. (2022). Self-Consistency Improves CoT Reasoning. arXiv:2203.11171.
- Yao, S. et al. (2023). Tree of Thoughts. arXiv:2305.10601.
- Chan, C-M. et al. (2023). ChatEval. arXiv:2308.07201.
- Liang, T. et al. (2023). Encouraging Divergent Thinking through Multi-Agent Debate. arXiv:2305.19118.
- Sharma, M. et al. (2023). Understanding Sycophancy in Language Models. arXiv:2310.13548.