Un chatbot de soporte para el inquilino (tenant) acme recibe una solicitud de reembolso. El usuario envía únicamente texto de chat; sin embargo, assist-api permite que el modelo genere una petición payments.refund y la envía utilizando las amplias credenciales de pago del servicio. El backend emite una propuesta de reembolso que u_123 nunca tuvo autorización para realizar. No se requirió nada complejo: texto no confiable pasó del mensaje del usuario a una acción, mientras que el modelo carecía de autoridad para decidir si dicha acción estaba permitida.
Un mecanismo de protección (guardrail) es un punto de control que restringe lo que una aplicación LLM acepta, gasta, devuelve o ejecuta. En este fallo, el mecanismo más sencillo y útil consiste en rechazar la solicitud de reembolso a menos que el sujeto autenticado cuente con el alcance (scope) requerido y un filtro de aprobación en el servidor acepte los parámetros reales del reembolso. La redacción del prompt no puede ofrecer esta protección, ya que el modelo se limita a seguir el texto que recibe; no autentica a los usuarios, no gestiona presupuestos ni autoriza el uso de herramientas.
El sistema en ejecución mantiene una ruta que no modificaremos. El usuario final u_123 pertenece al inquilino acme y llama a assist-api a través de llm-gateway. El servicio FastAPI construye un prompt, llama al proveedor providerA en la ruta chat utilizando $CHAT_MODEL y puede solicitar la ejecución de una herramienta. u_123 cuenta con permisos para chat:invoke y payments:refund:propose, pero no tiene autoridad ilimitada para realizar pagos.
El contrato de pago se mantiene acotado y explícito. La única herramienta de pago es payments.refund, que utiliza un invoice_id (como inv_987), un amount_cents como entero (como 1299) y un reason como cadena de texto. Una propuesta de reembolso no equivale a un permiso para ejecutarlo. El servidor verifica la propiedad del inquilino, el alcance, los argumentos y la aprobación antes de ejecutar cualquier acción de pago irreversible.
Cualquier límite o interfaz que transporte texto se considera no confiable, incluidos el mensaje del usuario, los documentos recuperados, los resultados de las herramientas y la salida del modelo. Un documento de soporte recuperado puede contener instrucciones que entren en conflicto con la política de la aplicación, y la salida del modelo puede incluir campos que resultarían inseguros si se enviaran a una API de pago sin validación previa. Esto corresponde a la vulnerabilidad LLM01 (Inyección de Prompt) del OWASP Top 10 para aplicaciones LLM de 2025, publicado por el proyecto OWASP GenAI Security en noviembre de 2024. La regla inmutable es clara: ninguna llamada a una herramienta puede ejecutarse con mayor autoridad que la otorgada originalmente por u_123.
[fuentes][/fuentes]
La ruta fija sitúa las entradas no confiables y los límites de aplicación en una misma vista.
La puerta de enlace (gateway) identifica quién realizó la llamada, mientras que assist-api aplica las restricciones relativas al inquilino (tenant) del usuario, los ámbitos (scopes), el contrato de la herramienta y los requisitos de aprobación. El proveedor providerA genera una salida utilizando sus propias credenciales de proveedor; sin embargo, dichas credenciales nunca deben otorgar autoridad para realizar reembolsos en nombre de u_123. Utilizar los permisos amplios del servicio para un usuario que carece de ellos crea una vulnerabilidad de tipo “delegado confundido” (confused deputy).
Regla de límite
El modelo puede sugerir
payments.refund; solo las comprobaciones realizadas en el servidor pueden autorizar o ejecutar dicha acción.
Dado que cada límite cumple una función distinta, el rechazo debe identificar la etapa que no pudo continuar de forma segura. llm-gateway devuelve un error 401 Unauthorized (No autorizado) si la credencial falta, es inválida, ha sido revocada o está comprometida. Tras la autenticación, la puerta de enlace o la aplicación devuelven un error 403 Forbidden (Prohibido) cuando quien realiza la llamada carece de un ámbito requerido. Un destino bloqueado para la recuperación de una herramienta también provoca un error 403 Forbidden, y dicho destino nunca llega a ser contactado.
Una vez que providerA responde, assist-api valida la salida del modelo antes de que esta llegue a un analizador sintáctico, a la API de pagos o a cualquier otro componente receptor posterior. Una salida que no cumple con el esquema devuelve un error 422 Unprocessable Content (Contenido no procesable), término de la norma RFC 9110 que sustituye al de “Entidad no procesable” (Unprocessable Entity) utilizado en documentación más antigua. Reutilizar una clave de idempotencia con parámetros de reembolso diferentes también devuelve 422 Unprocessable Content; reutilizar la misma clave mientras la primera solicitud sigue activa devuelve un error 409 Conflict (Conflicto).
Los resultados restantes describen un límite operativo más que una decisión del modelo.
202 Accepted (Aceptado) se devuelve cuando un reembolso irreversible queda pendiente de aprobación, junto con un identificador de dicha aprobación pendiente.429 Too Many Requests (Demasiadas solicitudes), acompañado de la cabecera Retry-After, se devuelve cuando se agota la cuota compartida o se supera el límite de tasa de peticiones (rate limit).503 Service Unavailable (Servicio no disponible) se devuelve cuando el almacén de políticas de control no está disponible y la aplicación no puede aplicar las políticas de forma segura.504 Gateway Timeout (Tiempo de espera agotado en la puerta de enlace) se devuelve cuando providerA supera el tiempo límite establecido para la llamada al proveedor.Estos resultados evitan que los clientes interpreten el rechazo simplemente como un fallo impreciso del modelo. Asimismo, indican dónde investigar: si el control faltante corresponde a la identidad en llm-gateway, a la validación en assist-api o a una llamada al proveedor que no se completó.
En el fallo inicial, el atacante solo dispone de un mensaje de chat, pero logra generar una propuesta de reembolso irreversible. ¿Qué etapa debería rechazar la solicitud en primer lugar: A, la autenticación del llamante y la asociación con el inquilino en llm-gateway; B, la autorización y aprobación de herramientas en assist-api; o C, las verificaciones de salida posteriores al modelo?
[fuentes][/fuentes]