Skip to main content
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

FieldTypeDefaultDescription
enabledboolFalseActivate PII scanning
typeslist[PIIType]all typesWhich PII categories to detect
actionRedactionAction"redact"What to do when PII is found
rehydrate_responseboolFalseReplace redaction tokens in responses with originals

PIIType enum

ValueDescriptionExample
ssnUS Social Security Numbers123-45-6789
credit_cardCredit card numbers (Luhn-validated)4111 1111 1111 1111
emailEmail addressesuser@example.com
phone_numberPhone numbers (E.164 and local formats)+1-555-867-5309
person_nameFull person names (NER-based)John Smith
api_keyAPI key patternssk-abc123...
ip_addressIPv4 and IPv6 addresses192.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

ValueBehavior
redactReplace PII with a [PII_TYPE_token] placeholder. Supports response rehydration.
blockReject the entire outbound request with HTTP 403. Logged to audit trail.
log_onlyPass 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.