Lesson 19 restricted which providers a given caller can reach. This lesson addresses a different question entirely: even for an allowed provider, does the content of this specific request contain something that shouldn’t be sent externally at all? This is exactly Lesson 1’s fourth failure mode, “a security review finds a service sending customer PII to a provider nobody approved for that data”, and it needs a control that inspects request content, not just request destination.
Detecting and Redacting PII Before It Leaves the Gateway
Microsoft’s open-source Presidio library is the standard tool for this: it detects PII entities (names, phone numbers, emails, credit card numbers, and more) in text and can replace them with placeholders before the text is forwarded anywhere.
from presidio_analyzer import AnalyzerEngine
from presidio_anonymizer import AnonymizerEngine
analyzer = AnalyzerEngine()
anonymizer = AnonymizerEngine()
def redact_pii(text: str) -> tuple[str, list[str]]:
results = analyzer.analyze(text=text, language="en")
anonymized = anonymizer.anonymize(text=text, analyzer_results=results)
detected_types = [r.entity_type for r in results]
return anonymized.text, detected_types
user_message = "Hi, my name is Priya Sharma, my number is 555-014-2837, can you check my order status?"
redacted_text, found = redact_pii(user_message)
print(redacted_text)
# "Hi, my name is <PERSON>, my number is <PHONE_NUMBER>, can you check my order status?"
print(found)
# ['PERSON', 'PHONE_NUMBER']
Wired into the request lifecycle, this runs as a pre-call guardrail, before routing (Lesson 4, stage 5), so a redacted request is what actually gets sent to whichever provider the routing engine picks:
def gateway_pre_call_hook(request: dict) -> dict:
for message in request["messages"]:
if message["role"] == "user":
redacted, detected = redact_pii(message["content"])
message["content"] = redacted
if detected:
log_pii_redaction_event(detected_types=detected, request_id=request.get("id"))
return request # continues to routing (Lesson 4, stage 5) with sensitive content already scrubbed
Logging every redaction event, not just performing the redaction silently, matters for the audit trail Lesson 21 builds next: a security team should be able to answer “how often are we catching PII in requests, and from which team” without that history being invisible.
Guardrails as a Broader Category
PII redaction is one instance of a general pattern: a check that runs before or after the actual model call and can block, modify, or flag a request or response. Portkey’s open-source gateway ships this as a first-class, composable concept in its Gateway Config, the same JSON structure used for load balancing and fallback (Lesson 9’s Portkey equivalent):
{
"before_request_hooks": [
{"type": "pii_redaction", "action": "redact"}
],
"after_request_hooks": [
{"type": "content_moderation", "action": "block", "categories": ["violence", "self-harm"]}
],
"targets": [
{"provider": "anthropic", "api_key": "sk-ant-..."}
]
}
before_request_hooks run pre-call, exactly like the PII redaction above; after_request_hooks run post-call, inspecting what the model actually generated before it reaches the caller, catching a different failure mode entirely: not bad input, but a bad or policy-violating output the model produced on its own.
flowchart LR
Req["Incoming request"] --> Pre["Pre-call guardrails\n(PII redaction, topic blocking)"]
Pre --> Route["Routing + provider call\n(Module 4)"]
Route --> Post["Post-call guardrails\n(content moderation,\noutput validation)"]
Post --> Client["Response to caller"]
style Req fill:#EEF0F7,stroke:#6366F1,color:#0F172A,rx:8px,ry:8px
style Pre fill:#4338CA,stroke:#4338CA,color:#ffffff,rx:8px,ry:8px
style Route fill:#F7F8FC,stroke:#0D9488,color:#0F172A,rx:8px,ry:8px
style Post fill:#4338CA,stroke:#4338CA,color:#ffffff,rx:8px,ry:8px
style Client fill:#EEF0F7,stroke:#6366F1,color:#0F172A,rx:8px,ry:8px
Portkey’s gateway ships over 50 built-in guardrails covering categories like PII detection, content moderation, prompt injection detection, and schema validation on structured outputs, the point of centralizing them at the gateway is identical to every governance control in this module: written and tested once, applied consistently to every caller, regardless of what any individual application remembered to implement. Lesson 21 closes Module 7 by making every one of these events, redactions, blocked requests, budget rejections, permanently recorded in an auditable log.