> ## Documentation Index
> Fetch the complete documentation index at: https://docs.declaw.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# PII Redaction

> Configure automatic PII detection and redaction for outbound traffic from Declaw sandboxes.

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

```python theme={null}
from declaw import Sandbox, SecurityPolicy, PIIConfig

sbx = Sandbox.create(
    security=SecurityPolicy(
        pii=PIIConfig(
            enabled=True,
            types=["ssn", "credit_card", "email", "phone"],
            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`            | `True`     | Replace redaction tokens in responses with originals |

## Detected PII types

| 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`       | Phone numbers (E.164 and local formats) | `+1-555-867-5309`     |
| `person_name` | Full person names (NER-based)           | `John Smith`          |
| `ip_address`  | IPv4 and IPv6 addresses                 | `192.168.1.1`         |

<Note>
  `person_name` requires the optional [Guardrails Service](/security/guardrails-service). Structured types (SSN, credit card, email, phone) work with the built-in regex scanner.
</Note>

## 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.

```mermaid theme={null}
sequenceDiagram
    participant Agent as Agent Code
    participant Proxy as Security Proxy
    participant API as External API

    Agent->>Proxy: POST with "charge 4111111111111111"
    Proxy->>Proxy: Detect CC number
    Proxy->>Proxy: Store original in session map
    Proxy->>API: POST with "charge [CREDIT_CARD_9f2a3b]"
    API-->>Proxy: Response with "[CREDIT_CARD_9f2a3b] charged"
    Proxy->>Proxy: Rehydrate token with original
    Proxy-->>Agent: Response with "4111111111111111 charged"
```

## Redact all types

Omit `types` or pass an empty list to scan for all supported PII types.

```python theme={null}
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.

```python theme={null}
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.

```python theme={null}
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](/security/guardrails-service) is deployed and `GUARDRAILS_URL` is set, PII scanning uses Microsoft Presidio (ML-based NER) instead of the built-in regex engine, for higher accuracy and a few additional entity types:

* Person names and locations
* Passport numbers and driver's license numbers

The fallback to regex detection is automatic if the Guardrails Service is unreachable.

## Example: OpenAI call with PII redaction

```python theme={null}
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)
```

<Warning>
  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.
</Warning>
