Guardrails
Guardrails inspect the content of requests and responses in real time — before a prompt reaches a provider and before a response reaches the caller. A guardrail config bundles a set of built-in checks, the surfaces they run on, and the resource groups they apply to (group_ids). Multiple configs can apply to the same request; the strictest outcome wins.

Built-in checks
Section titled “Built-in checks”| Check | What it detects | Providers | Key settings |
|---|---|---|---|
| Prompt injection | Attempts to override instructions | built_in, lakera_guard |
prompt_injection_sensitivity (0.0–1.0) |
| Jailbreak | Role-play / policy-evasion attacks | built_in, lakera_guard |
— |
| PII | Personal data in traffic | built_in, presidio |
pii_categories, pii_threshold (Presidio score threshold) |
| Toxic content | Hate, harassment, violence, sexual content, self-harm | openai_moderation, built_in |
toxic_content_threshold, per-category thresholds |
| Secrets | Credentials leaking through prompts/outputs | built-in | secrets_categories, secrets_threshold |
| Banned words | Literal word/phrase list | built-in | banned_words, banned_words_match_mode (substring / word_boundary) |
| Banned patterns | Regex list | built-in | banned_patterns |
Category values you can select:
- PII (
pii_categories):email,phone,ssn,credit_card,iban,ipv4,ipv6,openai_api_key,anthropic_api_key,aws_access_key,jwt,private_key - Secrets (
secrets_categories):aws_access_key,aws_secret_key,github_token,openai_key,gcp_service_account,private_key_pem,jwt,generic_high_entropy - Toxicity per-category thresholds (
toxic_content_category_thresholds) use the OpenAI Moderation taxonomy:hate,hate/threatening,harassment,harassment/threatening,self-harm,self-harm/intent,self-harm/instructions,sexual,sexual/minors,violence,violence/graphic
Actions
Section titled “Actions”Each check has an action: block (reject the request/response), redact (mask the offending spans and let the traffic continue — PII and secrets are the typical redact candidates), warn (log a violation, let it pass), or allow.
The two-layer surface gate
Section titled “The two-layer surface gate”This is the most common source of “my guardrail isn’t firing” confusion, so read this twice.

A check runs on a surface only where BOTH layers enable it:
- Config-level
surfacesmap — turns each surface on/off for the whole config. - Per-check
*_surfaceslist (e.g.pii_surfaces) — the surfaces that specific check participates in. If unset, the check uses its built-in default surface set.
check fires on surface S ⇔ surfaces[S] == true AND S ∈ <check>_surfacesExample. This config enables the mcp_input surface, but the PII check lists only chat surfaces — so PII will not scan MCP tool arguments, even though the surface is on:
{ "surfaces": { "chat_input": true, "chat_output": true, "mcp_input": true }, "builtin": { "pii_enabled": true, "pii_action": "redact", "pii_surfaces": ["chat_input", "chat_output"] }}To scan MCP arguments too, add "mcp_input" to pii_surfaces. Conversely, a long per-check surface list is inert on any surface the config-level map leaves off.
Full surface list
Section titled “Full surface list”LLM surfaces: chat_input, chat_output, embeddings_input, image_gen_input, image_gen_output, audio_tts_input, audio_tts_output, audio_stt_input, audio_stt_output, video_gen_input, video_gen_output, batch_input, batch_output, moderation_input
Non-LLM surfaces: mcp_input, mcp_output, mcp_registration, skill_input, skill_output, a2a_inbound, a2a_outbound
Per-surface overrides exist for most checks (pii_per_surface, toxic_content_per_surface, secrets_per_surface, banned_words_per_surface, …) so you can, for example, run PII with redact on chat but block on MCP output. For banned words/patterns, a per-surface words/patterns field replaces the global list on that surface.
Streaming output modes
Section titled “Streaming output modes”Output checks on SSE streams need a strategy: you can’t redact a token that has already left the building. streaming_output_mode on the config controls this:
| Mode | Behavior |
|---|---|
auto (default) |
Uses sync whenever any active output check can block or redact; otherwise async |
sync |
Buffer-and-release — the stream is buffered, checked, then released. Supports redaction and guarantees nothing violating is emitted, at the cost of time-to-first-token |
async |
Async-interrupt — tokens flow immediately; the check runs concurrently and terminates the stream on a violation. Block-only (no redaction), minimal latency, but some content may reach the client before the interrupt |
On an async-mode block, the client receives an error event followed by [DONE]:
data: {"error":{"type":"guardrail_block","message":"Output blocked by guardrail policy"}}data: [DONE]External providers
Section titled “External providers”The providers array configures external engines used by the checks:
{ "providers": [ { "provider": "presidio", "enabled": true, "endpoint": "http://presidio-analyzer:3030" }, { "provider": "lakera", "enabled": true, "api_key": "..." }, { "provider": "openai_moderation", "enabled": true, "api_key": "..." } ]}Supported provider values: lakera, openai_moderation, presidio, bedrock (requires config.guardrail_id), custom (requires endpoint). Presidio requires an endpoint — the trial bundle ships a presidio-analyzer service behind the presidio compose profile. Provider api_key values are encrypted at rest and never returned by GET.

Per-check fail_open_overrides (keys: pii, prompt_injection, jailbreak, toxic_content, banned_words, banned_patterns, secrets) control what happens when an external provider is unreachable.
Creating a config
Section titled “Creating a config”
In the Admin UI: Guardrails → New config, pick surfaces, enable checks, assign resource groups. Via the API:
curl -X POST http://localhost:5050/v1/admin/guardrails/configs \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "default-safety", "description": "Baseline safety for all chat traffic", "enabled": true, "group_ids": ["9f2c..."], "surfaces": { "chat_input": true, "chat_output": true, "mcp_input": true }, "builtin": { "prompt_injection_enabled": true, "prompt_injection_action": "block", "jailbreak_enabled": true, "jailbreak_action": "block", "pii_enabled": true, "pii_action": "redact", "pii_provider": "presidio", "pii_threshold": 0.6, "pii_categories": ["email", "phone", "credit_card", "ssn"], "pii_surfaces": ["chat_input", "chat_output", "mcp_input"], "secrets_enabled": true, "secrets_action": "block", "secrets_categories": ["aws_access_key", "github_token", "openai_key", "private_key_pem", "jwt"] }, "providers": [ { "provider": "presidio", "enabled": true, "endpoint": "http://presidio-analyzer:3030" } ] }'Testing guardrails
Section titled “Testing guardrails”Test a config against sample content without sending real traffic — in the Admin UI (Guardrails → Test) or via the API:

curl -X POST http://localhost:5050/v1/admin/guardrails/test \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "content": "My card number is 4111 1111 1111 1111, please remember it", "surface": "chat_input", "config_id": "grc-..." }'{ "action": "redact", "blocked": false, "violations": [ { "type": "pii", "provider": "presidio", "confidence": 0.95, "action": "redact", "detail": "credit_card detected", "config_id": "grc-...", "config_name": "default-safety" } ], "duration_ms": 41.7, "surface": "chat_input", "direction": "input", "configs_evaluated": 1}Omit config_id to test what the tenant’s applicable configs would collectively do.
What a blocked request looks like
Section titled “What a blocked request looks like”Non-streaming chat completions return 403 in the caller’s native error shape:
{ "error": { "code": "guardrail_blocked", "message": "Prompt injection detected", "guardrail": "default-safety", "check": "prompt_injection", "direction": "input" }}(Anthropic-native callers get the same fields wrapped in Anthropic’s {"type": "error", ...} envelope.)
Every block writes exactly one audit row, visible in the proxy logs with guardrail_blocked = true, and increments the proxy_guardrail_blocks_total Prometheus metric labeled by surface and check.
Related pages
Section titled “Related pages”- Argument & semantic policies — structural tool-call rules and LLM-judge constraints, complementary to content guardrails
- Resource groups — how configs attach to your hierarchy
- Logs & audit trail — where guardrail decisions land
