Guardrail Behavior
Guardrails add content-policy checks before AISIX forwards supported gateway traffic, after an upstream responds, or at both points. Their shared runtime controls determine which routes and content are checked, whether a match blocks traffic, and what callers and operators observe.
Built-in keyword and PII guardrails evaluate content inside the gateway. Semantic screening calls a configured embedding model, while custom scripts run operator-defined logic. Provider integrations send extracted content to a moderation service and apply its decision. Choosing a Guardrail Provider compares these options.
All categories use the behavior described on this page. The failure settings normally decide what happens when an applicable check cannot complete; some stream and decode paths have stricter or fixed handling.
Guardrail Hook Point
The hook point controls where AISIX runs a guardrail and what happens when it blocks content:
| Hook Point | What AISIX Checks | Effect When Blocked |
|---|---|---|
input | The caller request before AISIX sends it upstream. | The upstream is not called. |
output | Response content before AISIX returns it to the caller. | The caller does not receive the blocked response. |
both | Both request and response content. | AISIX applies the same guardrail on both sides where the route supports it. |
Input guardrails cover the text-bearing parts of standard inference routes. These include chat completions, completions, responses, messages, embeddings, image generation and editing, video generation, audio speech, and rerank requests. AISIX also scans optional audio transcription and translation prompts, Realtime text frames, MCP tools/call arguments, and A2A message text. The same input checks cover Batch and Fine-tuning request bodies and passthrough route bodies.
Output guardrails scan returned text from chat completions, completions, responses, messages, and audio transcription and translation. They also scan Realtime text frames, MCP tools/call results, Batch and Fine-tuning response bodies, and passthrough route bodies. A2A, embeddings, image generation and editing, video generation, audio speech, rerank, and Count Tokens run only the input hook. Realtime binary frames are relayed without a guardrail content check.
On native /v1/responses, the output scan covers message text and each tool call's name, arguments, and input. Hosted-tool results, such as mcp_call.output, File Search results, and Code Interpreter logs, are not scanned or masked, and neither are refusal parts or a hosted tool's code or action text.
Guardrails never scan tool-call IDs, in either direction, on /v1/chat/completions, /v1/messages, /v1/messages/count_tokens, /v1/responses, or a passthrough route carrying a recognized envelope. An ID is the id, call_id, tool_use_id, or tool_call_id that ties a tool call to its result, including a Gemini thought signature carried in it. Function names, arguments, and tool results are still scanned. A rule that matches only text inside a tool-call ID therefore does not fire.
On passthrough routes, guardrails attach through the passthrough_route attachment scope, alongside the caller's API key, team, and environment scopes. The scanned text follows the detected body envelope. Requests carrying a recognized LLM envelope (chat, completions, Responses) scan the extracted message or prompt text and ordinary JSON strings forwarded alongside those fields. Tool-call IDs and the other opaque handles that Guardrail Scan Coverage lists are left out. The extraction includes tool-call arguments and the content of Anthropic Messages traffic; Guardrail Scan Coverage lists what is read for each envelope.
If AISIX recognizes an envelope but cannot decode it, AISIX does not fall back to scanning the raw body. This prevents typed opaque media from being reinterpreted as text. For a passthrough route carrying a recognized Responses envelope, output scanning covers only recognized visible text, refusal, and tool fields. Known media, reasoning, and unknown output items remain opaque. Malformed recognized buffered output cannot be evaluated and follows the configured failure policy. Unknown Responses stream events remain opaque.
Opaque buffered traffic scans decoded JSON string values when the body is JSON and otherwise scans the textual body. An opaque SSE stream can scan only a bare JSON string. Other content-bearing payload shapes cannot be evaluated because AISIX cannot reliably associate their text with the preceding stream content.
The request is scanned before dispatch. A blocking verdict returns 422 without contacting the upstream. The built-in pii guardrail cannot write a mask back to a provider-native body, so a mask-action-only match is forwarded unchanged and recorded as described in Surfaces That Cannot Apply a Mask. Use a block action when that content must not reach the upstream. Guardrail kinds such as Presidio and Lakera instead return a blocking verdict when a maskable result has no write-back channel. One case overrides all this. A mask hit inside an Anthropic thinking block is forwarded unchanged for every guardrail kind, because the block is signed. See Reasoning and Thinking Content.
A non-streaming response is buffered in full before relay, and AISIX scans its eligible content. A blocking verdict returns 422 with the upstream body withheld. Streaming responses relay incrementally under the chain's streamed-output policy. Hold-back guardrails buffer frames, either windowed or in full, and release them only after the scanned text clears. A blocking verdict ends the stream with a terminal SSE error frame while held frames are dropped. Each surface uses its own protocol's error shape rather than one canonical frame. Chat completions carry content_filter. /v1/messages uses the nested Anthropic shape, with an Anthropic-legal error type and an error.code of content_filter or guardrail_unavailable. A passthrough route follows the protocol of the stream it relays: the Anthropic shape for an Anthropic Messages stream, and the chat completions shape otherwise. /v1/responses splits by upstream. Where the provider serves the Responses API natively, the held-back stream is refused with a 422 rather than a frame. Where AISIX bridges a provider that does not, the refusal is the flat Responses error event. See Guardrail Refusals.
Surfaces That Cannot Apply a Mask
Some surfaces relay content that AISIX has no channel to rewrite:
- Passthrough route requests and responses.
/a2amessages.- Batch and Fine-tuning request bodies and the upstream bodies returned for them.
/v1/realtimetext frames, in both directions.- The
/v1/videosprompt.
When a pii mask rule matches on one of these surfaces, the content passes unmodified and AISIX records the match on the usage record:
| Enforcement mode | What AISIX records |
|---|---|
block | An enforced hit with action mask_unsupported and the detector counts. guardrail_blocked stays false, and redacted_entity_counts does not count the match because nothing was redacted. |
monitor | A monitor hit with action would_mask_unsupported in place of would_mask, because enforcing the rule would not mask anything either. |
Use a block action where the matched content must not pass. Presidio, Lakera, AWS Bedrock, Alibaba Cloud AI Guardrails, and custom scripts do not forward a mask outcome on these surfaces; they refuse the content instead. The other surfaces that run guardrails rewrite masked content, with the exceptions described elsewhere on this page.
The Decision Endpoints Are Not Screened
Guardrails do not run on the decision endpoints, /v1/systemone and /v1/decisions. Neither input nor output checks apply, whatever is attached in the request's scope, and nothing is redacted. The usage events of these requests carry no guardrail evidence.
The Files Routes Are Not Screened
Guardrails do not apply to the Files API at all. POST /v1/files, GET /v1/files, GET /v1/files/{id}, DELETE /v1/files/{id}, and GET /v1/files/{id}/content run no input and no output guardrail check, whatever is attached in the request's scope and whatever fail_open says. An uploaded file leaves the gateway exactly as the caller wrote it, and a downloaded one reaches the caller exactly as the provider stored it. A keyword, PII, or remote guardrail that would refuse the same text in a chat message does not see it here.
Telemetry does not report the gap. A Files usage event carries no marker for the missing guardrail pass: the guardrail evidence fields remain empty. Attaching a fail-closed guardrail to the environment therefore produces no signal that these routes are uncovered. An empty guardrail evidence section on a Files event does not confirm guardrail coverage. Where uploaded content must be screened, screen it before it reaches the gateway.
/v1/batches and /v1/fine_tuning/jobs are not affected. Their request bodies are structured JSON the caller submits rather than an uploaded blob, and both those bodies and the responses are still scanned.
Reasoning and Thinking Content
Reasoning is split by direction, and the two halves are not symmetrical. Plan a PII or blocklist policy around the boundary rather than assuming a guardrail covers everything a reasoning-capable model touches.
Reasoning the caller sends is in scope. Replayed reasoning is caller-supplied text entering the model like any other, so it is scanned, and masked at the same slots:
| Route | Scanned and masked |
|---|---|
/v1/responses | A reasoning item's content[].text and its summary[].text |
/v1/chat/completions | An assistant turn's reasoning_content |
/v1/messages | A thinking block's text — scanned, but see the exception below |
Anthropic thinking blocks are never rewritten. A mask-action hit inside a thinking block is forwarded unchanged. This holds for every guardrail kind, not only the built-in pii one, because rewriting the block would invalidate the signature the provider issued for it.
Block-action rules still fire on a thinking block, so use a block action where such content must not reach the upstream. A redacted_thinking block is a separate case. It carries only encrypted provider data and contributes no text to the scan, so no rule can match inside it. It is likewise relayed untouched.
Reasoning the model generates is out of scope. It is neither scanned nor masked on any route — not on /v1/chat/completions, /v1/messages, or /v1/responses, streaming or buffered.
Generated reasoning used to be scanned incidentally on three paths: buffered /v1/messages, /v1/responses, and passthrough routes carrying one of those envelopes. It no longer is. A block rule whose term appears only inside model-generated reasoning, and nowhere in the answer the model returned, blocked those responses before and does not block them now. The visible answer is scanned exactly as before.
If you relied on that, move the rule to the input hook. Otherwise, accept that generated reasoning is outside the output guardrail's scope.
One exception is not worth relying on either. When the request does not match a recognized envelope, a buffered JSON response is handled as raw traffic, so its decoded string values can include reasoning. That is raw-content scanning, not reasoning-aware handling. A malformed recognized response does not fall back to this path. In a raw SSE stream, only a bare JSON string can be scanned.