OpenWAF Egress moves the provider keys out of your agents and checks what the agents send. This page describes what it protects against, how, and where it stops. It describes v0.1.1.
What it protects
| Risk | What the gateway does |
|---|---|
| A provider key in the agent's process, image or environment | The agent only holds a placeholder. The real key is read from OpenBao or Vault after the checks and set on the outgoing request only; it is never returned to the agent. |
| A prompt injection that makes the agent send instructions or data out | 27 deterministic detectors over the request body (enforce_injection). |
| Card numbers, private keys or API keys leaving in a request | Data-leak patterns over the request body (block_dlp). |
| An agent calling a destination it should not | Per-agent allowed_targets. |
| A target that points at internal addresses | SSRF check on the target's host. |
| A provider redirect that would carry the key elsewhere | Redirects are never followed. |
| Oversized bodies used to hide text past the inspection window | Refused with 413, never cut and forwarded. |
Order of checks
The checks run in this order and the first failure answers. Nothing is sent upstream and no secret is read before all of them pass:
- Agent identity and token. The agent comes from the URL (
/v1/agent/<agent>/…), theX-OpenWAF-Agentheader or, on/v1/proxy/…, the token itself. When the agent has atoken, the request must carryAuthorization: Bearer <token>, whatever route identified it. - Target. The alias must exist (
404 unknown_target) and be in the agent'sallowed_targets(403 egress_blocked). - SSRF. Every address the target's
hostresolves to must be public (403 ssrf_blocked). - Body. Read up to 8 MiB. With inspection on, the text outside inline media must fit 1 MiB. Then the prompt-injection detectors, then the data-leak patterns.
- Key. Read from KV v2 (
502 credential_resolution_failedif it cannot be read) and set in the target'sauth_header.
Credentials
- Keys live in OpenBao or Vault. The gateway reads them with an AppRole that only needs
readon the agents' secret paths. - A key is cached in memory for five minutes and is never written to disk or to the logs. A failed lookup is logged with its path and field name, not its value.
- The placeholder token is a credential for the gateway: whoever holds it can call that agent's allowed targets through the gateway, with the agent's checks. Give every agent its own long random token.
Destinations and redirects
403 ssrf_blockedcovers127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,169.254.0.0/16(including the cloud metadata address169.254.169.254),100.64.0.0/10,0.0.0.0/8,224.0.0.0/4,240.0.0.0/4,::1,fc00::/7,fe80::/10andff00::/8. IPv4-mapped IPv6 addresses are checked as IPv4. A host that does not resolve is refused too.- The check resolves the target's
host; the connection goes to the host ofbase_url. Targets come from your configuration, not from the agent, so keep both on the same public name. - Upstream redirects are never followed. The
3xxgoes back to the agent as it is, so the injected key never travels to a host that skipped the allowlist and the SSRF check.
Inspection
- Only the request body is inspected. Headers, the query string and the provider's responses are not; responses stream back unchanged.
- Inline media is left out of the inspected text and forwarded unchanged:
data:image/…;base64,…URIs (audio and video too) and JSON"data"members of at least 1 KiB of bare base64 (OpenAIinput_audio, GeminiinlineData, Anthropic base64 sources).data:text/…payloads and the text beside the media stay inspected. - The gateway never forwards a body it did not inspect in full: over 8 MiB, or over 1 MiB of text with inspection on, the answer is
413. - Detectors look for instructions addressed to a model, not topics. They cover English and Spanish, plus text hidden in zero-width or Unicode tag characters, HTML comments, CSS-hidden elements, base64 and percent or hex encoding.
cost.amplification(orders to repeat or generate without end) is detected but not refused by the gateway.
What it does not do
- It is not a proof of safety. Detection is deterministic pattern matching: it stops known injection and exfiltration shapes, not every possible one.
- It does not encrypt or authenticate the transport. The gateway speaks plain HTTP and tokens are static. Keep it on loopback or a private network, or put TLS in front of it. Never expose it to the internet.
- It does not limit spend or rate. An agent with a valid token can send as many allowed requests as it wants.
- It does not filter the agent's other headers. Every request header goes upstream except
X-OpenWAF-Agentand, when the agent has atoken, itsAuthorizationheader with the placeholder; the target'sauth_headerthen carries the real key. Keys in the query string (?key=) are not injected. - It does not inspect responses. What the provider answers reaches the agent as it is.
Reporting a vulnerability
Write to [email protected] with a description, the affected version or commit and steps to reproduce. In scope: the gateway in github.com/openwaf-dev/egress (external link) and the published ghcr.io/openwaf-dev/egress images (SECURITY.md (external link)).
Written from github.com/openwaf-dev/[email protected] (external link).