Guardrails
Scan a tenant's requests and responses for prompt injection, personal information, banned words and harmful content, and block, redact or log what is found.
4 min readUpdated for v2.4.0Edit on GitHub
Turn on guardrails for a tenant
- 1
Open the tenant's Guardrails section
On Tenants, open the tenant and go to Guardrails.
- 2
Start from a preset
FERPA / personal info redacts personal information both ways. Prompt-injection defense blocks injection attempts before they reach the model. Monitor only raises an alert when personal information appears and never blocks. Or choose the action and scanners yourself.
- 3
Pick a guard model if you use the harm scanner
The harmful-content scanner asks a model you choose. Its backend must return logprobs.
- 4
Save
The policy applies to every key of the tenant from the next request, whatever model it calls. Clients change nothing.
Through the Management API, PATCH /api/v1/tenants/{id}/guardrails sets the policy, and {"policy": null} removes it:
curl -X PATCH http://localhost:9180/api/v1/tenants/$TENANT_ID/guardrails \
-H "Authorization: Bearer $OBLETH_ADMIN_TOKEN" -H "Content-Type: application/json" \
-d '{"policy": {"action": "redact", "input_scanners": ["pii", "prompt_injection"],
"output_scanners": ["pii"], "guard_model": null, "ban_keywords": [], "fail_open": true}}'
| Field | Values |
|---|---|
action | block, redact or log_only |
input_scanners | Any of prompt_injection, pii, ban_keywords, harm |
output_scanners | Any of pii, ban_keywords, harm |
guard_model | The model for harm; required when harm is used |
ban_keywords | The tenant's word list for ban_keywords |
fail_open | true (default) passes content through when a scanner fails; false refuses with 503 |
Scanners and actions
| Scanner | How it works | Catches |
|---|---|---|
prompt_injection | Patterns, in the gateway | Jailbreak and instruction-override attempts |
pii | Patterns, in the gateway | Social security, email, phone and card numbers |
ban_keywords | Your word list, in the gateway | Whole words from the list, any case |
harm | One yes/no question to the guard model | Harmful content |
What happens on a match:
blockrefuses with 400. On input,request blocked by content policyis returned before admission, so nothing reaches the model and nothing is billed. On output,response blocked by content policy; the answer was already generated, so the request is billed its real usage.redactmasks the matches and lets the request continue. Onlypiiandban_keywordscan be redacted;prompt_injectionandharmstill block.log_onlychanges nothing and raises an alert, keyedguardrails_input_<tenant_id>orguardrails_output_<tenant_id>(with_harm_for a harm verdict). See Alerting.
The x-obleth-boons: off header turns off boons only. It does not skip a tenant's guardrails.
What is scanned
Input scanners run on every request from the tenant's keys, on every path:
- In
messages, every message except the model's own turns and tool output:user,system,developer, and messages with no role. - The text fields of other requests:
prompt(completions, image generation),input(embeddings, moderations, speech), andqueryanddocuments(rerank). - The text fields of multipart forms, such as the prompt of an image edit or a transcription. A redaction is written back into the forwarded form.
POST /v1/verdicts: the state and every question, before admission.
/v1/responses and /v1/messages are translated to chat and scanned as chat. Spellings with extra or trailing slashes are handled like their /v1 forms.
Not scanned: uploaded files (audio, images, video reference frames), token-id inputs, and tool output and assistant turns in messages. A request with nothing to scan is passed through without a guard-model call.
For a tenant with an input policy, the auto router's classifier is not called, because it would read the prompt before the scan.
Paths a block or redact policy refuses
A policy that blocks or redacts refuses, with 400, requests it cannot enforce:
| Policy | Refused | Why |
|---|---|---|
| Input | Completion prompt given as token ids | Token ids cannot be scanned |
| Input | A POST to a path the gateway does not recognise, such as /tokenize | Its body is not a format the scanners read |
| Output | /v1/completions, audio transcription and translation, unrecognised paths | Output scanners read chat responses only |
Endpoints that return no text (embeddings, images, speech, rerank, moderations, video jobs) are served. Use /v1/chat/completions, /v1/responses or /v1/messages for text. Under an input policy, embedding, rerank and moderation inputs go through every input scanner, so indexing a document that trips one returns 400. A log_only policy refuses nothing.
Output scanning that blocks or redacts needs the whole answer, so the gateway asks the backend for a non-streaming response and replays it as a stream to a client that asked for one. It also skips the response cache for that request.
When a scanner fails
The harm scanner reads p(unsafe) from the guard model's first token and flags content above 0.5. A reply that puts almost no probability on either answer, or no reply at all, is a scanner error, and fail_open decides:
fail_open: true(default) passes the content through unchanged.fail_open: falserefuses with503 content policy scanner unavailable.
This changed in v2.0.0. Earlier versions counted any guard-model reply that did not start with UNSAFE as safe, so a policy with fail_open: false let requests through when the guard model did not answer. It now blocks them. Check that your guard model's backend returns logprobs before upgrading a fail-closed policy.
Billing and traces
Harm classifications are helper calls billed to the tenant as request type guardrails_boon. The pattern scanners make no model call. With tracing on, scans record boon:guardrails_input and boon:guardrails_output spans. See Observability.
Gateway-owned probe keys are never scanned.
Monitoring streamed responses
A log_only policy with output scanners also monitors streamed responses. The gateway copies each chunk to a decoder as it forwards it, so the client's stream is never delayed or changed, and scans once the stream ends.
- Server-sent events are reassembled across chunk boundaries, so a match split across chunks or tokens is still found.
- Content and reasoning deltas are collected separately, so interleaving can neither create nor hide a match.
- Responses driven by the gateway tool loop are monitored across all their turns.
- Monitoring stops at 512 KiB of response body, or at an event that is not valid JSON. The gateway then logs a warning with the request id and the reason, and raises no alert for that response.
