Skip to main content

Microsoft Presidio Guardrails

The Presidio guardrail detects and anonymizes sensitive data with Microsoft Presidio, an open-source PII engine you run yourself. AISIX calls your Presidio analyzer for each request or response. Detected entities are either blocked or anonymized with an operator you choose, and anonymized traffic continues with the rewritten text.

Compared with the built-in PII guardrail, Presidio adds:

  • NER/ML entities a regex cannot express, such as PERSON, LOCATION, NRP, and the rest of Presidio's recognizer set.
  • Anonymization operators: replace with an entity placeholder, mask with asterisks, hash with SHA-256, or redact the span entirely.
  • Self-hosted analysis: content is analyzed inside your own network, with no vendor key.

In this guide, you will run Presidio locally, create a Presidio guardrail with per-entity actions, and verify anonymization and blocking.

Prerequisites

Before starting, prepare the following:

  • Review Guardrail Behavior for hook points, enforcement modes, and remote failure handling.
  • A self-hosted AISIX gateway with the admin and proxy listeners available.
  • The admin key from the gateway config.yaml.
  • A working model alias and caller API key that can send chat-completions requests.
  • Docker, to run the Presidio analyzer and anonymizer containers used in this guide.

Start Presidio

Start the two Presidio services:

docker run -d --name presidio-analyzer -p 5002:3000 mcr.microsoft.com/presidio-analyzer:latest
docker run -d --name presidio-anonymizer -p 5001:3000 mcr.microsoft.com/presidio-anonymizer:latest

Both containers must be reachable from the gateway. Confirm the analyzer responds:

curl -sS -X POST "http://127.0.0.1:5002/analyze" \
-H "Content-Type: application/json" \
-d '{
"text": "my email is alice@example.com",
"language": "en"
}'

The response lists the detected EMAIL_ADDRESS entity with its offsets and score.

Create a Presidio Guardrail

Set the values used by the example requests:

# Replace with your values
export AISIX_ADMIN_KEY="YOUR_ADMIN_KEY"
export AISIX_API_KEY="YOUR_CALLER_API_KEY"
export AISIX_MODEL="gpt-4o-mini"

Create a guardrail that anonymizes emails and person names but blocks US Social Security Numbers, on both hooks:

curl -sS -X POST "http://127.0.0.1:3001/admin/v1/guardrails" \
-H "Authorization: Bearer ${AISIX_ADMIN_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "presidio-pii-policy",
"enabled": true,
"hook_point": "both",
"fail_open": false,
"kind": "presidio",
"analyzer_url": "http://127.0.0.1:5002",
"anonymizer_url": "http://127.0.0.1:5001",
"entities": [
{
"type": "EMAIL_ADDRESS"
},
{
"type": "PERSON"
},
{
"type": "US_SSN",
"action": "block"
}
],
"default_action": "mask",
"operator": "replace",
"score_threshold": 0.5,
"language": "en"
}'

entities limits detection to the listed Presidio entities. An empty list analyzes with Presidio's full recognizer set.

default_action: "mask" anonymizes listed entities unless an entry overrides the action. This example blocks US Social Security Numbers with action: "block".

operator: "replace" substitutes masked values with entity placeholders such as <EMAIL_ADDRESS>. Use hash when downstream systems need a stable pseudonym instead of a placeholder.

score_threshold drops analyzer results below the given confidence. Omit it to accept every result the analyzer returns.

Because this guardrail uses hook_point: both, AISIX applies the same anonymization to model responses before they reach the caller. Original request values do not reach the provider, and original response values do not reach the caller. For streamed model responses, see Streaming Output.

Matched values are also kept out of gateway logs and usage records. Usage records contain only per-entity mask counts with entity names.

For the complete request and response schema, see Create Guardrail in the Admin API Reference.

Verify Anonymization

Send a prompt containing an email address:

curl -sSi -X POST "http://127.0.0.1:3000/v1/chat/completions" \
-H "Authorization: Bearer ${AISIX_API_KEY}" \
-H "Content-Type: application/json" \
--data-binary @- <<EOF
{
"model": "${AISIX_MODEL}",
"messages": [
{
"role": "user",
"content": "email alice@example.com about the order"
}
]
}
EOF

If the upstream model succeeds, the response starts with HTTP/1.1 200 OK. AISIX anonymizes the prompt before calling the upstream model, so the provider receives:

email <EMAIL_ADDRESS> about the order

Verify Blocking

A request containing a blocked entity is rejected:

curl -sSi -X POST "http://127.0.0.1:3000/v1/chat/completions" \
-H "Authorization: Bearer ${AISIX_API_KEY}" \
-H "Content-Type: application/json" \
--data-binary @- <<EOF
{
"model": "${AISIX_MODEL}",
"messages": [
{
"role": "user",
"content": "my ssn is 123-45-6789"
}
]
}
EOF

The response starts with HTTP/1.1 422 Unprocessable Entity and includes the standard content-filter error:

{
"error": {
"message": "request blocked by content policy (guardrail 'presidio-pii-policy')",
"type": "content_filter"
}
}

The matched value is not echoed back.

Rewrite Limits

On endpoints that cannot rewrite request text in place, such as audio, images, and passthrough, a maskable detection blocks instead. AISIX never releases content its policy says should have been anonymized. If the analyzer finds PII but the anonymizer call fails, the remote failure policy applies rather than releasing the un-anonymized text.

Next Steps

You have now configured Microsoft Presidio and verified anonymization and blocking. Use these guides to tune behavior or compare related guardrails: