Policy decisions
Every request through the Arbitex Gateway is evaluated against your organization’s policy chain before it reaches an upstream provider. This page documents how those decisions are returned to your application on the data plane: the response headers that carry the terminal action, the error body emitted on a block, and how content-security inspection (prompt guard, content filters, DLP) manifests at request time.
For configuring policy packs, rules, and chains, see the Policy Engine Admin Guide.
Policy response headers
Section titled “Policy response headers”After policy evaluation, the gateway attaches decision metadata to every response — including 403 error responses. Two headers are always present (or absent as noted):
| Header | Values | When present |
|---|---|---|
X-Policy-Action |
ALLOW, BLOCK, CANCEL, REDACT, ROUTE_TO |
Every response |
X-Matched-Rule |
rule ID string | Present when X-Policy-Action is not ALLOW |
X-Matched-Rule is intentionally omitted on ALLOW responses to avoid leaking policy structure to callers. When the action is anything other than ALLOW, the header is set so your application can programmatically detect and handle enforcement events.
Action semantics
Section titled “Action semantics”| Action | HTTP status | What happened |
|---|---|---|
ALLOW |
200 (or provider status) | No rule matched, or the first terminal match was an explicit ALLOW. The request was forwarded to the upstream provider. |
BLOCK |
403 | A rule matched and its action was BLOCK. The request was not forwarded. See 403 policy_block below. |
CANCEL |
200 (truncated stream) | The policy engine detected a violation in the output stream and halted it mid-response. The partial response is delivered; no retry is possible for the same request. |
REDACT |
200 | Detected entities were replaced with placeholder tokens in the prompt before forwarding to the provider. The upstream model received a sanitized version of the request. |
ROUTE_TO |
200 (or provider status) | The request was redirected to an alternate provider or model as specified by the matching rule. |
CANCEL behavior in streaming responses
Section titled “CANCEL behavior in streaming responses”CANCEL applies when a rule’s applies_to is output or both and a violation is detected in the model’s streamed response. The gateway emits a final output_blocked event in the SSE stream and closes the connection. The partially delivered content precedes the cancellation event. Because the provider round-trip already occurred, this action cannot be retried — the gateway logs the request with X-Policy-Action: CANCEL and records it in the audit log.
403 policy_block
Section titled “403 policy_block”When X-Policy-Action is BLOCK, the gateway returns HTTP 403 with the following JSON body:
{ "error": { "code": "policy_block", "message": "OpenAI access is not permitted for your group.", "type": "policy_error", "rule_id": "rule_01HZ_BLOCK_OPENAI" }}Error body fields
Section titled “Error body fields”| Field | Type | Description |
|---|---|---|
code |
string | Always "policy_block" for this error type |
message |
string | The optional message configured on the matched rule. If the rule has no custom message, a generic default is used. |
type |
string | Always "policy_error" |
rule_id |
string | The ID of the rule that produced the BLOCK action |
Do not retry policy blocks
Section titled “Do not retry policy blocks”A 403 policy_block response is deterministic: the same request will receive the same decision until the policy configuration changes. Do not implement automatic retry logic for this status code. Log the rule_id for diagnostics and surface a user-facing message from the message field.
Correlating to the audit log
Section titled “Correlating to the audit log”The rule_id in the error body matches the matched_rule_id field in the audit log entry for the same request. Use this to cross-reference enforcement events with the audit log when investigating a block that your application or users did not expect.
Content-security inspection at request time
Section titled “Content-security inspection at request time”Before policy chain evaluation, the gateway runs the request through two content-security stages that can independently produce enforcement actions.
Prompt guard (system prompt injection detection)
Section titled “Prompt guard (system prompt injection detection)”The gateway inspects the full message array — including the system role — for prompt injection attempts before forwarding to the upstream model. Injection patterns that are detected result in a BLOCK action with X-Policy-Action: BLOCK and a 403 policy_block response. The matched rule ID in this case refers to the injection-detection rule configured in the active policy chain.
Prompt injection detection is part of Tier 1 (Regex) and Tier 2 (NER) of the 5-tier DLP pipeline. It runs on the assembled message text, not per-message.
Content filters
Section titled “Content filters”Content filters are administrator-configured rules that operate at a lower layer than the policy chain:
| Filter type | Enforcement | Response |
|---|---|---|
keyword_block |
Prompt contains a prohibited keyword (case-insensitive substring match) | 403 with the filter’s configured message |
topic_block |
Prompt addresses a prohibited topic | 403 with the filter’s configured message |
custom_instruction |
Filter scope matches the requesting user | The filter’s instruction is prepended to the system message; the request continues normally |
Content filters are evaluated in ascending priority order (lower priority value = evaluated first). A keyword_block or topic_block match short-circuits all subsequent filter evaluation and the policy chain — the request is blocked immediately.
From the perspective of your application, a content filter block is indistinguishable from a policy chain block: you receive 403, X-Policy-Action: BLOCK, and a JSON error body with code: "policy_block". The rule_id field identifies the content filter that triggered.
DLP pipeline inspection
Section titled “DLP pipeline inspection”The 5-tier DLP pipeline (Tier 0: TF-IDF, Tier 1: Regex, Tier 2: NER, Tier 3: DeBERTa, Tier 4: CredInt) inspects both prompt input and model output. DLP findings are passed to the policy engine as entity match signals; the policy chain then decides the enforcement action based on which entities were detected and which rules match.
The DLP pipeline does not independently choose an action — it feeds signals to the policy chain. The X-Policy-Action header reflects the policy chain’s terminal decision, not a DLP-layer decision.
Example: inspecting policy headers
Section titled “Example: inspecting policy headers”curl -i https://api.arbitex.ai/v1/chat/completions \ -H "Authorization: Bearer $ARBITEX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "openai/gpt-4o", "messages": [{"role": "user", "content": "Summarize our Q1 results."}] }'Allowed response (excerpt):
HTTP/2 200x-policy-action: ALLOWBlocked response:
HTTP/2 403x-policy-action: BLOCKx-matched-rule: rule_01HZ_BLOCK_OPENAIcontent-type: application/json{ "error": { "code": "policy_block", "message": "OpenAI access is not permitted for your group.", "type": "policy_error", "rule_id": "rule_01HZ_BLOCK_OPENAI" }}Redacted response (excerpt):
HTTP/2 200x-policy-action: REDACTx-matched-rule: rule_01HZ_REDACT_CCThe response body in a REDACT case is the model’s completion based on the sanitized prompt — the model never saw the original sensitive content.
See also
Section titled “See also”- Policy Engine Admin Guide — configuring policy packs, rules, chains, and the combining algorithm
- Audit log —
matched_rule_idand the full audit record schema - Chat completions —
output_blockedanddlp_correctionSSE events for streaming responses