El human-in-the-loop es teatro si nadie lee el prompt

Botón grande de aprobación desgastado por el uso en una consola oscura, con una cola de tarjetas de pedidos pendientes apilándose detrás
5 1 voto
Valora la Publicación

Resumen de la publicación

Un experimento con 40.000 sesiones y 409.000 decisiones midió qué tan bien aprueban los humanos los comandos que les pide un agente de IA: el supervisor promedio deja pasar 1 de cada 3 amenazas. Las mismas semanas dejaron dos casos reales (Rovo de Atlassian y agentes de código en pipelines) donde el humano ni siquiera estaba en el circuito.

La frase «hay un humano que aprueba» descansa sobre dos supuestos que acaban de caer con datos: que el humano lee lo que aprueba, y que el humano está. La salida no es pedir más atención: es rediseñar la aprobación.

Cada vez que alguien plantea un riesgo de los agentes de IA, la respuesta llega sola y suena razonable: «hay un humano que aprueba». La usé yo también, y está en las presentaciones de todos los proveedores y en las políticas internas que vi este año.

Es el famoso human-in-the-loop (el humano en el circuito): la práctica de exigir que una persona revise y apruebe cada acción sensible del agente antes de que se ejecute. Suena a control fuerte porque nos imaginamos a alguien leyendo con atención cada pedido.

Pero esa frase descansa sobre dos supuestos que casi nunca hacemos explícitos:

  • Que el humano lee y entiende lo que está aprobando.
  • Que el humano está efectivamente en el circuito cuando la acción ocurre.

Las últimas semanas dejaron evidencia de que los dos fallan, cada uno por su lado. Desde que leí esos números, la frase la uso con bastante más cuidado: la aprobación humana, tal como la practicamos en muchos equipos, corre el riesgo de parecerse más a un teatro de seguridad que a un control: tranquiliza al que firma el diagrama, pero no siempre frena al que ataca.

El primer supuesto: alguien lee lo que aprueba

El ingeniero de software Alex Wauters armó un juego de navegador que te pone del otro lado del mostrador: jugás de supervisor, te llegan los comandos que un agente quiere ejecutar y tenés que aprobarlos o rechazarlos contrarreloj, como en una sesión real de trabajo.

No es un paper académico, pero el volumen le da peso: se recolectaron 40.000 sesiones y 409.000 decisiones. Cerca del 34% de los comandos eran efectivamente amenazas, una proporción pensada para medir la detección más que para imitar una jornada real, así que los porcentajes importan menos que la tendencia.

El jugador promedio dejó pasar una de cada tres amenazas. Y solo el 20,8% logró el pleno que describe el trabajo real: detectarlas todas sin bloquear de más, porque si rechazás de más, el agente no sirve y el equipo termina desactivando la aprobación.

El desglose por tipo de amenaza es lo que convierte esto de dato curioso en algo accionable:

  • Comandos destructivos obvios: 11,7% de omisión.
  • Cambios permanentes en el sistema: 23,8%.
  • Fuga de datos y ejecución de código: 33,4%.
  • Salirse del alcance autorizado: 35,0%.

Fijate la progresión. Somos bastante buenos frenando un rm -rf (el comando que borra todo) y bastante malos frenando lo que se parece a trabajo normal.

El ejemplo estrella es npm run analyze, un comando de lo más común en proyectos de Node.js: ejecuta un script que define el propio proyecto, o sea que puede hacer literalmente cualquier cosa. En el juego, ese comando venía con el código malicioso visible en el historial de la sesión: bastaba con mirar los pasos anteriores para ver qué iba a ejecutar.

Se aprobó el 64,7% de las veces. Eso es, literalmente, el «nadie lee el prompt» del título: la evidencia estaba a un scroll de distancia, y un comando que parece rutina no dispara la revisión.

Esa es exactamente la brecha que un atacante necesita. No tiene que esconder nada: le alcanza con envolverlo en algo que se parezca al décimo comando aburrido del día.

Si esto te suena, es porque ya lo viviste con otro nombre: es la misma mecánica de aprobar la notificación de MFA sin mirar el número, o de cerrar la alerta del monitoreo que «siempre es falsa». Un control cuya respuesta correcta es «sí» la mayoría de las veces no es un control, es un trámite.

El segundo supuesto: hay alguien en el circuito

Hasta acá se podría discutir cuánto se parece un juego de navegador al trabajo real. Pero el juego mide el escenario optimista: el primer supuesto fallando con el humano sentado ahí, mirando.

Las últimas semanas dejaron dos casos reales donde falló el segundo supuesto, que es previo y más grave: el humano directamente no estaba.

Rovo: un click alcanzó para que el asistente trabaje para otro

Rovo es el asistente de IA de Atlassian, y viene activado por defecto en los planes Standard, Premium y Enterprise de Jira y Confluence. Varonis Threat Labs, el equipo de investigación de la empresa de seguridad Varonis, encontró que un parámetro de la URL precargaba instrucciones en el chat de Rovo, y bautizó el ataque RovoBlast.

El ataque completo es humillante de tan simple. El atacante arma un link con las instrucciones maliciosas adentro, se lo manda a alguien de la organización, y con un solo click de esa víctima ya autenticada, Rovo se pone a trabajar con los privilegios de ella: busca tickets de Jira, páginas de Confluence, claves API, hasta lo que alcanzan los conectores de SharePoint y Outlook, y manda todo a un servidor ajeno.

Atlassian lo parcheó en sus servidores el 8 de julio (no tenés que actualizar nada), y existen controles de administración para restringir qué aplicaciones y grupos pueden usar Rovo.

Pero fijate qué aprobó el humano en ese flujo: hacer click en un link. En ningún momento apareció un diálogo que dijera «Rovo quiere exportar datos a un dominio externo, ¿autorizás?». La aprobación que suponíamos que existía no estaba en el circuito.

Agentes en el pipeline: nadie mira a las 3 de la mañana

El segundo caso salió de Black Hat, la conferencia de seguridad de Las Vegas. La empresa Novee Security presentó fallas en Claude Code y Gemini CLI cuando corren como agentes automáticos en pipelines de CI/CD (los procesos que compilan y despliegan código sin intervención manual).

La peor es CVE-2026-12537 en Gemini CLI, con severidad 10 sobre 10: un archivo de configuración preparado permite ejecutar comandos en el servidor de CI antes de que arranque el sandbox (el entorno aislado donde se supone que corre el código del agente). El escenario de explotación es un repositorio público donde el agente responde issues: un desconocido abre uno, el pipeline se dispara solo, y el código del atacante corre de madrugada sin que nadie lo vea.

Los dos proveedores ya parchearon (Gemini CLI desde la versión 0.39.1, Claude Code desde la 2.1.163): si tenés agentes corriendo en pipelines, actualizá.

Acá el humano no falló: no existe por diseño, porque el punto de poner un agente en el pipeline es que corra solo. Y está bien que corra solo. Pero apostaría a que más de uno de esos equipos declara «tenemos human-in-the-loop» en su matriz de riesgos, porque el flujo interactivo lo tiene y el nocturno (justo el que cualquiera puede disparar con un issue) no.

Qué haría en lugar de pedir más atención

La conclusión fácil sería «capacitemos mejor a la gente», y me parece la equivocada: los dos supuestos no fallan por ignorancia, fallan por diseño. Y lo que falla por diseño se arregla en el diseño.

  • Bajar el volumen antes que subir la atención. Si el agente pide veinte aprobaciones por hora, el problema es el alcance del agente, no la vista del que aprueba. Con seis decisiones por día se puede leer; con doscientas, no: esto ataca directo el primer supuesto.
  • Mostrar el efecto, no el comando. «Ejecutar npm run analyze» no dice nada. «Este script va a conectarse a un dominio que no está en la lista permitida» sí. La decisión hay que tomarla sobre consecuencias, que es lo único que un humano puede evaluar en cinco segundos.
  • Aislar en vez de aprobar. Para los flujos donde el humano no está (el pipeline de madrugada), la respuesta no es inventarle un aprobador: es que el peor caso no importe. Docker Sandboxes le da a cada agente su propia máquina virtual desechable. Ese enfoque escala; la atención humana no.
  • Medir la tasa de aprobación. Las aprobaciones quedan registradas en los logs de la plataforma que uses: son dos líneas de SQL sobre datos que ya tenés. Si se aprueba el 98% de los pedidos, eso solo no condena al control, pero es la señal para investigar: o el agente pide puras cosas benignas (y el control sobra) o nadie está mirando (y el control miente).

Un control que no medimos no es un control

Lo que más me molesta no es que la supervisión humana funcione mal, sino que la pusimos en los diagramas como si funcionara bien y nunca la medimos. Ningún equipo serio aceptaría un firewall del que no tiene métricas, y aceptamos sin chistar un control de aprobación del que no sabemos ni la tasa ni el tiempo promedio de decisión.

No estoy diciendo que saquemos al humano del circuito. Estoy diciendo que dejemos de contarlo como el control principal, cuando atrapa dos de cada tres cosas en el mejor caso, las que se le escapan son justamente las que un atacante elegiría, y en los flujos más automatizados ni siquiera está.

El teatro no está en tener un humano que aprueba. El teatro está en ponerlo en el diagrama, no medirlo nunca, y dormir tranquilos igual.

Lo que cambié en mi propio flujo: DDW

Y esa molestia terminó en una decisión de diseño propia. DDW (Dilux Development Workflow) es un framework open source (licencia Apache 2.0) que estoy construyendo: un pipeline de desarrollo que el agente tiene que atravesar en seis fases: clasificar, definir, planificar, codificar, verificar y cerrar.

Cada fase procesa un solo tipo de tarea, produce su artefacto documentado (la clasificación del pedido, un documento de requerimientos, una especificación técnica, el código, el reporte de pruebas, el cierre) y deja su progreso registrado en disco. Entre fase y fase hay una compuerta (un gate): el agente no avanza hasta que yo apruebo explícitamente el artefacto de la fase anterior.

¿No es contradictorio, después de todo lo anterior, basar mi propio flujo en aprobaciones humanas? No, y la diferencia es el punto central de esta nota: el experimento no condena la aprobación humana en sí, condena un tipo de aprobación (frecuente, sin contexto y contrarreloj). Los gates de DDW cambian exactamente esas variables:

  • Pocas aprobaciones. Seis por funcionalidad, no veinte comandos por hora. Con ese volumen, el primer supuesto (que el humano lee) vuelve a ser realista.
  • Sobre artefactos, no sobre comandos. Al salir de la fase de definición, por ejemplo, lo que apruebo es el documento de requerimientos: texto que se lee con café de por medio, no un npm run analyze bajo presión de tiempo.
  • Garantizadas por código, no por el modelo. Un hook (un programa aparte que corre automáticamente antes de cada acción del agente) lee el estado y se niega a avanzar si la aprobación no está registrada. Es justo lo que faltaba en los pipelines del caso anterior: la regla no es una promesa que el agente recuerda, es código que la exige.

La regla de diseño detrás de todo DDW es una sola: si una regla importa, tiene que ser ejecutable. Una regla escrita en un prompt es una promesa: el modelo puede olvidarla, malinterpretarla o decidir que esta vez no cuenta. Una regla ejecutada por un hook es una garantía.

En la práctica se siente así: si el agente intenta escribir código sin que la especificación esté aprobada, la escritura no ocurre. No es la escena que cualquiera que usó agentes conoce de memoria (el agente pide disculpas y sigue haciendo lo mismo): el hook rechaza la operación antes de que toque el disco.

Hoy está verificado de punta a punta con Claude Code y OpenCode, con soporte parcial o en pruebas para Copilot CLI, Codex CLI, Cursor y Gemini CLI. Lo único que escribís vos es un archivo de configuración con las reglas y el contexto de tu proyecto.

Y para ser coherente con esta nota, lo digo antes de que lo descubras vos: DDW también tiene partes que son promesa y no garantía. Los artefactos aprobados quedan sellados con un hash (una huella digital que delata cualquier edición posterior) y los commits los verifica git, pero las atestaciones que genera certifican que el registro está completo, no que el trabajo esté bien hecho. Y hay comandos de shell que pueden evadir la validación: ahí DDW avisa, en vez de fingir un control que no puede sostener. Exactamente el tipo de distinción que este artículo pide que hagamos explícita.

Tampoco tengo resuelto el otro hueco: los gates revisan las transiciones entre fases, no los cientos de comandos que el agente ejecuta entre gate y gate. Para eso no confío en mi atención: confío en el sandbox y en las listas de comandos permitidos.

Cuando diseñaba DDW me hice la pregunta que dejaría sobre la mesa en tu próxima reunión de arquitectura: si mañana sacáramos la aprobación humana del diseño, ¿qué otro control quedaría en pie? En mi caso la respuesta fue el hook, el sandbox y las fases.

Si en tu caso la respuesta es «ninguno», entonces no hay controles. Hay uno solo, y encima es el más débil.

Escrito por

Pablo Ariel Di Loreto

Profesor. Informático. Fanático del helado de dulce de leche. Director de Ingeniería en MODO, y Secretario del Microsoft Users Group Asociación Civil. Además, soy owner de iniciativas como ConoSurTech y Aprender IT.

Ver todas las entradas de Pablo Ariel Di Loreto →
Suscribirse
Notificarme de
guest

0 Comentarios
Viejos
Nuevos Más votados
Scroll al inicio
0
Nos encantaría conocer tu opinión: ¡comenta!x