PII Redaction & Guardrails at the Gateway

10 min read Module 7 of 10 Lesson 20 of 28

What you'll learn

  • Explain why PII redaction belongs at the gateway rather than in each application's own code
  • Detect and redact common PII entity types from a prompt before it's sent to any provider using Presidio
  • Configure a guardrail (via Portkey's gateway config pattern) that runs before or after a model call
  • Distinguish pre-call guardrails (blocking bad input) from post-call guardrails (checking model output before it reaches the caller)
Building this at your company? For enterprise and company teams taking this to production: book a 30-minute session with our AI engineers for architecture guidance, code review, and a rollout plan for your use case.
Book a Team Session

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.

Knowledge Check

3 questions to test your understanding

1 Why is redacting PII at the gateway architecturally better than requiring every application team to redact it themselves before calling an LLM?

2 What is the functional difference between a pre-call guardrail and a post-call guardrail in a gateway pipeline?

3 A Presidio-based redaction pass replaces a detected phone number in a prompt with a placeholder like <PHONE_NUMBER> before forwarding the request to a cloud provider. What problem does this solve that a pure network-level control (like blocking certain destination IPs) could not?

Go further with expert guidance

Ready to build production AI?
Talk to our R&D team.

These courses give you the foundation. Our embedded AI teams take you from prototype to production in 30–90 days, with your team, your codebase, your goals. Book a free strategy call to see how we can accelerate your AI initiative.

30 minutes · No obligation · Expert AI engineers, not sales reps

AI Architecture Review

Audit your current stack and identify high-impact improvements

Project Review

Get expert feedback on your AI implementation and codebase

Team Mentoring

Upskill your engineers with hands-on AI coaching sessions

AI Strategy

Define your AI roadmap, prioritization, and implementation plan