Blueprint: Privacy-First RAG
Fail-Closed Protection for Retrieved Context
Retrieval-Augmented Generation (RAG) often pulls data from internal knowledge bases that may contain stale PII (e.g., legacy customer data, emails). If this context is injected directly into the LLM prompt, it creates a privacy leak.
The Gateway deterministically denies retrieved context containing matched PII before it reaches the model. When the workflow must continue, the Python SDK masks matching spans in place on Claude Code or Gemini CLI and lets the redacted call proceed.
Architecture
1. Master Policy Definition
{
"name": "rag-privacy-policy",
"priority": 9000,
"rules": [
{
"id": "allow-rag-agent",
"effect": "allow",
"principals": ["agent:rag-bot"],
"actions": ["llm:generate"],
"resources": ["*"]
}
],
"content_policy": {
"enable_pii_detection": true,
"pii_action": "mask"
}
}
2. Implementation
LlamaIndex Prototype
import os
from openai import OpenAI
# A PII match at the Gateway returns a denial. Apply supported Python-SDK
# masking yourself before this call if the workflow must continue.
client = OpenAI(
api_key="ignored",
base_url="http://cz-gateway:8001/v1",
default_headers={"X-ControlZero-Agent-ID": "rag-bot"}
)
def answer_with_rag(query: str, retrieved_docs: list):
# Context retrieved from Chroma/Pinecone may contain SSNs or Emails
context_text = "\n".join(retrieved_docs)
prompt = f"Context: {context_text}\n\nQuestion: {query}"
try:
response = client.chat.completions.create(
model="gpt-5.4-mini",
messages=[{"role": "user", "content": prompt}]
)
return response.choices[0].message.content
except Exception as e:
return f"Policy Intervention: {e}"
# Scenario: Vector DB returns a document with an SSN
context = ["The client Jane Doe has SSN 123-45-6789 and is located in NY."]
print(answer_with_rag("What is Jane Doe's location?", context))
# Result: The PII match returns a denial and the model is not called.
# Only send redacted context after supported Python-SDK masking.
3. Validation Checklist
- Augmentation Check: Verify that PII within the
Context:block causes a DLP denial. - Utility preserved: If continuation is required, mask through the supported Python SDK before forwarding and verify the LLM receives only redacted context.
- Audit Review: Verify that the audit findings contain no raw PII.