Saltar al contenido

OpenWAF Egress

Tus agentes de IA nunca tienen la clave del proveedor.

OpenWAF Egress se coloca entre tus agentes y los proveedores de modelos a los que llaman. El agente solo recibe un token de marcador. Cada petición se revisa contra inyección de prompt, fugas de datos y SSRF, y solo entonces la pasarela lee la clave real de OpenBao o HashiCorp Vault, la inyecta y reenvía la petición sin romper el streaming.

27 detectores, sin llamar a ningún modelo

84 µs por una petición de chat de 4 KB

Un binario de Go, imagen para amd64 y arm64

Respuestas reales del binario de la pasarela contra un OpenBao de demostración y un proveedor simulado: la clave inyectada (200) y después una inyección de prompt, un número de tarjeta y una petición a 169.254.169.254 rechazados (403).

Cómo funciona

Cinco comprobaciones antes de que la clave salga del almacén

El agente sigue usando su SDK de siempre. Solo cambian la URL base y la clave.

URL base http://127.0.0.1:8070/v1/agent/<agente>/proxy/<destino> · clave OWE_TOKEN_…

  1. 1

    Token del agente

    401

    El agente envía su marcador en Authorization: Bearer. Si falta o no coincide, la petición acaba aquí.

  2. 2

    Destinos permitidos

    403 egress_blocked

    El destino de la URL tiene que estar en los allowed_targets del agente.

  3. 3

    Comprobación de SSRF

    403 ssrf_blocked

    El host del destino solo puede resolver a direcciones públicas.

  4. 4

    Inspección del cuerpo

    403 injection_detected · data_leak_blocked

    Los detectores de inyección de prompt y los patrones de fuga de datos revisan el cuerpo, sin llamar a ningún modelo.

  5. 5

    Clave desde OpenBao

    → proveedor

    La clave real se lee de KV v2 y se pone en la petición de salida; la respuesta vuelve al agente en streaming.

Inyección de prompt

27 detectores deterministas, en inglés y en español

Expresiones regulares que buscan órdenes dirigidas a un modelo, no temas: hablar de prompts, de la terminal o de secretos no salta. Una petición bloqueada recibe 403 injection_detected con el id, la etiqueta y el texto encontrado de cada detección.

21 detectores de patrones

Anulaciones, jailbreaks, mensajes falsificados, abuso de herramientas y órdenes de exfiltración.

  • pi.override.enAnulación de instrucciones (en inglés)
  • pi.override.esAnulación de instrucciones (en español)
  • pi.sysprompt.enExtracción del prompt de sistema (en inglés)
  • pi.sysprompt.esExtracción del prompt de sistema (en español)
  • pi.jailbreak.personaPersonaje de jailbreak
  • pi.jailbreak.modeModo jailbreak
  • pi.fake_systemMensaje de sistema falso
  • pi.compliance_noticeAviso de cumplimiento falso
  • pi.concealOcultación al usuario
  • pi.chat_templateTokens de plantilla de chat
  • pi.fake_toolLlamada o resultado de herramienta falsificado
  • pi.fake_turnTurnos de conversación falsificados
  • pi.memoryEnvenenamiento de la memoria persistente
  • pi.tool_invokeOrden de invocar una herramienta
  • pi.no_confirmSaltarse la aprobación
  • agent.destructiveOrden de comando destructivo
  • exfil.pipe_shellScript remoto pasado a una shell
  • exfil.env_secretsRecolección de secretos
  • exfil.host_dataExfiltración de datos de la máquina
  • exfil.markdown_imageExfiltración con un enlace o una imagen renderizados
  • cost.amplificationOrden de multiplicar el gasto (se informa, no se rechaza)

6 detectores de texto oculto o codificado

Órdenes que una persona no ve al leer. Los comentarios, los elementos ocultos con CSS y los bloques codificados se decodifican y se revisan con los detectores de patrones.

  • hidden.zero_widthTexto oculto de ancho cero
  • hidden.tag_charsCaracteres de etiqueta Unicode ocultos
  • pi.html_commentÓrdenes en un comentario HTML
  • hidden.css_textÓrdenes en texto oculto con CSS
  • pi.base64Órdenes codificadas (base64)
  • pi.encodedÓrdenes codificadas (%xx o hexadecimal)

La detección es por patrones: frena formas conocidas de inyección y exfiltración, no demuestra que una petición sea segura. La pasarela rechaza cualquier detección salvo cost.amplification, que ignora. El mismo juego de detectores protege los endpoints de IA en el borde de OpenWAF.

Protecciones

Claves, datos y destinos

Cada comprobación se activa por agente. Cada rechazo es un error JSON que el agente puede leer.

  • Claves inyectadas desde OpenBao o Vault

    El agente lleva un marcador OWE_TOKEN_…. Tras las comprobaciones, la pasarela entra con AppRole, lee la clave de KV v2 (en caché 5 minutos) y la pone solo en la petición de salida.

  • Destinos permitidos por agente

    Cada agente enumera en allowed_targets los destinos a los que puede llegar. Cualquier otro destino configurado recibe 403 egress_blocked antes de leer el cuerpo.

  • Prevención de fugas de datos

    Con block_dlp, un cuerpo con un número de tarjeta válido por Luhn, una clave privada PEM, un identificador de clave de AWS, una clave sk- al estilo de OpenAI o un token de GitHub recibe 403 data_leak_blocked.

  • Protección contra SSRF

    Loopback, RFC 1918, CGNAT, enlace local (169.254.169.254 incluida), multidifusión, rangos reservados y sus equivalentes IPv6 se rechazan con 403 ssrf_blocked.

  • Sin seguir redirecciones

    Un 3xx del proveedor vuelve al agente tal cual, así que la clave inyectada nunca sigue una redirección hacia un host fuera de la lista.

  • Cuerpos enteros o nada

    Las imágenes, audios y vídeos en base64 en línea (URI data: y los campos "data" de OpenAI, Gemini y Anthropic) no cuentan como texto inspeccionado. El resto debe caber en la ventana de 1 MiB o la petición recibe 413; nada se reenvía sin inspeccionar ni recortado. El cuerpo tiene un tope de 8 MiB.

Rendimiento

La detección, medida en microsegundos

Lo que tarda en pasar todos los detectores por el cuerpo de una petición, según las pruebas de rendimiento del repositorio.

  • 84 µsPetición de chat de 4 KB
  • 1,3 msPetición de chat de 64 KB
  • 97 ms64 KB preparados para activar todos los detectores (el peor caso)

Medido con go test -bench . ./pkg/aiagents/ en un Mac con Apple Silicon (darwin/arm64). Cada detector solo se ejecuta si aparece alguna de sus palabras clave, así que el tráfico normal se salta casi todos. El binario estático ocupa unos 7 MB.

Inicio rápido

En marcha en dos pasos

Escribe un config.json con tus destinos y tus agentes, arranca el contenedor y cambia la URL base del agente.

  1. 1

    Arranca el contenedor en loopback

    Dentro del contenedor la imagen escucha en 0.0.0.0:8070. Publícala solo en 127.0.0.1 o en una red privada.

    docker run -d --name openwaf-egress -p 127.0.0.1:8070:8070 \
      -v "$PWD/config.json:/app/config.json:ro" \
      ghcr.io/openwaf-dev/egress:0.1.1
  2. 2

    Apunta el SDK a la pasarela

    Sirve cualquier SDK compatible con OpenAI: cambia la URL base y dale el token de marcador.

    import OpenAI from "openai";
    
    const client = new OpenAI({
      baseURL: "http://127.0.0.1:8070/v1/agent/my-support-agent/proxy/openrouter",
      // placeholder; the real key never reaches the agent
      apiKey: "OWE_TOKEN_SUPPORT_AGENT",
    });

Después: el inicio rápido (el secreto en OpenBao, la configuración y una primera petición) y todos los campos de la configuración.

Notas de seguridad

Hasta dónde llega

Qué hacer al desplegarla y qué no promete.

Antes de desplegar

  • La pasarela habla HTTP sin cifrar y los tokens de los agentes son fijos: mantenla en loopback o en una red privada, o pon TLS delante. Nunca la expongas a internet.
  • Cambia el token de ejemplo OWE_TOKEN_SUPPORT_AGENT por un valor largo y aleatorio para cada agente: el de ejemplo es público.
  • Da al AppRole de la pasarela permiso de lectura solo sobre las claves de los agentes.
  • La detección encarece las formas conocidas de inyección de prompt y de exfiltración; no demuestra que una petición sea segura.
  • Comunica vulnerabilidades a [email protected].

Preguntas

Preguntas sobre OpenWAF Egress

¿Llega a ver el agente la clave del proveedor?

No. El agente solo tiene su marcador OWE_TOKEN_…. La pasarela lee la clave real de OpenBao o Vault cuando la petición ha pasado las comprobaciones y la pone en la petición de salida. Al agente vuelve la respuesta del proveedor, no la clave.

¿Llama a un modelo para detectar la inyección de prompt?

No. Los detectores son expresiones regulares deterministas en inglés y español, y cada uno solo se ejecuta si aparece alguna de sus palabras clave. La detección tarda 84 µs en una petición de chat de 4 KB en un Mac con Apple Silicon.

¿Con qué proveedores funciona?

Con cualquier API HTTP que definas como destino: una URL base, un host y la cabecera que recibe la clave. Los ejemplos cubren OpenRouter, OpenAI, Anthropic (x-api-key), Gemini (x-goog-api-key) y Hugging Face.

¿Sigue funcionando el streaming?

Sí. La respuesta se copia al agente según llega y se vacía tras cada lectura, así que los tokens en streaming le llegan según los envía el proveedor.

¿Qué pasa con las peticiones grandes con imágenes?

Las imágenes, audios y vídeos en base64 en línea, como URI data: o como los campos JSON data de OpenAI, Gemini y Anthropic, quedan fuera del texto inspeccionado y se reenvían sin cambios. El resto del texto tiene que caber en 1 MiB o la petición recibe un 413, y ningún cuerpo puede pasar de 8 MiB.

¿Forma parte de OpenWAF Cloud?

Es un proyecto de código abierto aparte, con licencia Apache-2.0, que ejecutas tú junto a tus agentes. Usa el mismo juego de detectores que la protección de endpoints de IA del borde de OpenWAF.

Quítales las claves a tus agentes.

OpenWAF Egress es gratuito y de código abierto con licencia Apache-2.0. Arranca el contenedor junto a tus agentes y apunta su SDK a él.