When PII redaction is enabled, the security proxy scans outbound HTTP and HTTPS request bodies for sensitive data before they reach external APIs. Detected PII is replaced with opaque tokens. If rehydrate_response=True, the tokens in API responses are transparently replaced back with the original values before they reach your agent code.
Basic configuration
from declaw import Sandbox, SecurityPolicy, PIIConfig
sbx = Sandbox.create(
security=SecurityPolicy(
pii=PIIConfig(
enabled=True,
types=["ssn", "credit_card", "email", "phone_number"],
action="redact",
rehydrate_response=True,
)
)
)
PIIConfig model
| Field | Type | Default | Description |
|---|
enabled | bool | False | Activate PII scanning |
types | list[PIIType] | all types | Which PII categories to detect |
action | RedactionAction | "redact" | What to do when PII is found |
rehydrate_response | bool | False | Replace redaction tokens in responses with originals |
PIIType enum
| Value | Description | Example |
|---|
ssn | US Social Security Numbers | 123-45-6789 |
credit_card | Credit card numbers (Luhn-validated) | 4111 1111 1111 1111 |
email | Email addresses | user@example.com |
phone_number | Phone numbers (E.164 and local formats) | +1-555-867-5309 |
person_name | Full person names (NER-based) | John Smith |
api_key | API key patterns | sk-abc123... |
ip_address | IPv4 and IPv6 addresses | 192.168.1.1 |
person_name requires the optional Guardrails Service. Structured types (SSN, credit card, email, phone) work with the built-in regex scanner.
RedactionAction enum
| Value | Behavior |
|---|
redact | Replace PII with a [PII_TYPE_token] placeholder. Supports response rehydration. |
block | Reject the entire outbound request with HTTP 403. Logged to audit trail. |
log_only | Pass the request unchanged but write the detection to the audit log. |
How redaction works
When the proxy finds a credit card number in an outbound request body:
Before: "Please charge 4111111111111111 for $50"
After: "Please charge [CREDIT_CARD_9f2a3b] for $50"
The token CREDIT_CARD_9f2a3b is stored in the per-sandbox session map. When the API responds and the response body contains that token, it is replaced back with the original value before your code sees it.
Redact all types
Omit types or pass an empty list to scan for all supported PII types.
pii=PIIConfig(
enabled=True,
types=[], # or omit entirely — defaults to all types
action="redact",
)
Block on sensitive PII
Use action="block" for the most sensitive types to prevent any transmission.
pii=PIIConfig(
enabled=True,
types=["ssn", "credit_card"],
action="block",
)
Any request containing an SSN or credit card number will be rejected with HTTP 403. The event is written to the audit log.
Log without redacting
Use action="log_only" for audit visibility without modifying traffic.
pii=PIIConfig(
enabled=True,
types=["email"],
action="log_only",
)
Domain scoping
Limit PII scanning to specific destination domains using the domains field on PIIConfig (available via the underlying SecurityPolicy JSON). By default, all domains are scanned.
With the Guardrails Service
When the Guardrails Service is deployed and GUARDRAILS_URL is set, PII scanning uses Microsoft Presidio instead of the built-in regex engine. Presidio provides higher accuracy and supports additional entity types including:
- Person names, organizations, locations
- Passport numbers, driver’s license numbers
- Medical record numbers
- US bank account numbers
The fallback to regex detection is automatic if the Guardrails Service is unreachable.
Example: OpenAI call with PII redaction
from declaw import Sandbox, SecurityPolicy, PIIConfig
policy = SecurityPolicy(
pii=PIIConfig(
enabled=True,
types=["ssn", "credit_card", "email"],
action="redact",
rehydrate_response=True,
),
network={"allow_out": ["*.openai.com"], "deny_out": ["0.0.0.0/0"]},
)
sbx = Sandbox.create(security=policy)
# This script sends user data to OpenAI — PII is redacted before it leaves the sandbox
sbx.files.write("/workspace/call_api.py", b"""
import openai
client = openai.OpenAI()
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{
"role": "user",
"content": "Summarize this customer record: John Smith, SSN 123-45-6789, email john@example.com"
}]
)
print(response.choices[0].message.content)
""")
result = sbx.commands.run("python3 /workspace/call_api.py")
# OpenAI received "[PERSON_NAME_x1] [SSN_y2] [EMAIL_z3]"
# Response was rehydrated before reaching the agent
print(result.stdout)
PII redaction applies to HTTP and HTTPS request bodies only. PII present in URL query parameters or HTTP headers is not scanned by the body inspector. Use TransformationRule patterns to handle header-level PII.