OBLETHdocs

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

Set perTenant. On when the tenant has a policy
Turn it onA tenant's page › Guardrails
It costsNothing, except a guard-model call for the harm scanner

Turn on guardrails for a tenant

  1. 1

    Open the tenant's Guardrails section

    On Tenants, open the tenant and go to Guardrails.

  2. 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. 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. 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}}'
FieldValues
actionblock, redact or log_only
input_scannersAny of prompt_injection, pii, ban_keywords, harm
output_scannersAny of pii, ban_keywords, harm
guard_modelThe model for harm; required when harm is used
ban_keywordsThe tenant's word list for ban_keywords
fail_opentrue (default) passes content through when a scanner fails; false refuses with 503

Scanners and actions

ScannerHow it worksCatches
prompt_injectionPatterns, in the gatewayJailbreak and instruction-override attempts
piiPatterns, in the gatewaySocial security, email, phone and card numbers
ban_keywordsYour word list, in the gatewayWhole words from the list, any case
harmOne yes/no question to the guard modelHarmful content

What happens on a match:

  • block refuses with 400. On input, request blocked by content policy is 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.
  • redact masks the matches and lets the request continue. Only pii and ban_keywords can be redacted; prompt_injection and harm still block.
  • log_only changes nothing and raises an alert, keyed guardrails_input_<tenant_id> or guardrails_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), and query and documents (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:

PolicyRefusedWhy
InputCompletion prompt given as token idsToken ids cannot be scanned
InputA POST to a path the gateway does not recognise, such as /tokenizeIts body is not a format the scanners read
Output/v1/completions, audio transcription and translation, unrecognised pathsOutput 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: false refuses with 503 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.