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

# Security Policy

> SecurityPolicy, PIIConfig, InjectionDefenseConfig, NetworkPolicy, TransformationRule, AuditConfig, and EnvSecurityConfig reference for the Python SDK.

```python theme={null}
from declaw import (
    SecurityPolicy,
    PIIConfig, PIIType, RedactionAction,
    InjectionDefenseConfig, InjectionAction, InjectionSensitivity,
    ToxicityConfig,
    CodeSecurityConfig,
    InvisibleTextConfig,
    NetworkPolicy,
    TransformationRule, TransformDirection,
    AuditConfig, AuditEntry,
    EnvSecurityConfig, SecureEnvVar,
    CustomPolicyConfig, ContentGateConfig,
    SandboxNetworkOpts, ALL_TRAFFIC,
)
```

A `SecurityPolicy` is passed to `Sandbox.create()` via the `security` parameter. It composes PII detection, injection defense, toxicity / code-security / invisible-text scanners, network policy, transformation rules, audit logging, and environment variable security into a single object.

## SecurityPolicy

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

policy = SecurityPolicy(
    pii=PIIConfig(enabled=True, action="redact"),
    injection_defense=InjectionDefenseConfig(enabled=True, action="block"),
    audit=True,
)

sbx = Sandbox.create(security=policy, api_key="key", domain="host:8080")
```

<ParamField body="pii" type="PIIConfig" default="PIIConfig()">
  PII detection and redaction configuration. See [PIIConfig](#piiconfig).
</ParamField>

<ParamField body="injection_defense" type="bool | InjectionDefenseConfig" default="False">
  Prompt injection defense. Pass `True` to enable with defaults, or an
  `InjectionDefenseConfig` for custom settings. See
  [InjectionDefenseConfig](#injectiondefenseconfig).
</ParamField>

<ParamField body="transformations" type="list[TransformationRule]" default="[]">
  List of regex-based request/response body transformations. See
  [TransformationRule](#transformationrule).
</ParamField>

<ParamField body="network" type="NetworkPolicy | None" default="None">
  Network allowlist/denylist policy. See [NetworkPolicy](#networkpolicy).
</ParamField>

<ParamField body="audit" type="bool | AuditConfig" default="False">
  Audit logging. Pass `True` to enable with defaults, or an `AuditConfig`
  for custom retention and body logging settings.
</ParamField>

<ParamField body="toxicity" type="ToxicityConfig | None" default="None">
  Toxicity scanner for outbound HTTP request bodies. See
  [ToxicityConfig](#toxicityconfig).
</ParamField>

<ParamField body="code_security" type="CodeSecurityConfig | None" default="None">
  Code-security scanner for outbound HTTP request bodies. See
  [CodeSecurityConfig](#codesecurityconfig).
</ParamField>

<ParamField body="invisible_text" type="InvisibleTextConfig | None" default="None">
  Invisible-Unicode scanner for outbound HTTP request bodies. See
  [InvisibleTextConfig](#invisibletextconfig).
</ParamField>

<ParamField body="env_security" type="EnvSecurityConfig" default="EnvSecurityConfig()">
  Environment variable masking in audit logs. See
  [EnvSecurityConfig](#envsecurityconfig).
</ParamField>

<ParamField body="custom_policy" type="CustomPolicyConfig | None" default="None">
  Attach OPA/Rego policy — a built-in governance pack via `policy_ref`, or your
  own rules via `inline_rego`/`inline_modules`. See
  [CustomPolicyConfig](#custompolicyconfig).
</ParamField>

<ParamField body="content_gate" type="ContentGateConfig | None" default="None">
  Run the `content.scan` OPA gate (e.g. an LLM model allowlist / cross-signal
  rules) on the listed domains. See [ContentGateConfig](#contentgateconfig).
</ParamField>

### Properties

| Property                           | Type                     | Description                                                           |
| ---------------------------------- | ------------------------ | --------------------------------------------------------------------- |
| `policy.injection_config`          | `InjectionDefenseConfig` | Resolved config regardless of whether a `bool` or object was passed.  |
| `policy.audit_config`              | `AuditConfig`            | Resolved audit config.                                                |
| `policy.requires_tls_interception` | `bool`                   | `True` if PII, injection defense, or any transformations are enabled. |

### Methods

| Method                           | Returns          | Description                          |
| -------------------------------- | ---------------- | ------------------------------------ |
| `policy.to_dict()`               | `dict`           | Serialize to a JSON-compatible dict. |
| `policy.to_json()`               | `str`            | Serialize to a JSON string.          |
| `SecurityPolicy.from_dict(data)` | `SecurityPolicy` | Deserialize from a dict.             |

***

## PIIConfig

Configure detection and handling of personally identifiable information in
outbound HTTP traffic.

```python theme={null}
from declaw import PIIConfig, PIIType, RedactionAction

pii = PIIConfig(
    enabled=True,
    types=[PIIType.EMAIL, PIIType.CREDIT_CARD, PIIType.SSN],
    action=RedactionAction.REDACT.value,
    rehydrate_response=True,
)
```

<ParamField body="enabled" type="bool" default="False">
  Whether PII scanning is active.
</ParamField>

<ParamField body="types" type="list[str]" default="all types">
  PII types to scan for. Defaults to all `PIIType` values. Valid values are
  the string values of `PIIType`.
</ParamField>

<ParamField body="action" type="str" default="'redact'">
  Action to take when PII is detected. One of `'redact'`, `'block'`,
  `'log_only'`.
</ParamField>

<ParamField body="rehydrate_response" type="bool" default="True">
  When `True`, the security proxy replaces redaction tokens in API responses
  with the original values so the agent sees real data in replies.
</ParamField>

<ParamField body="domains" type="list[str] | None" default="None">
  Limit PII scanning to requests targeting these domains. `None` means scan
  all domains.
</ParamField>

### `PIIType` enum

```python theme={null}
class PIIType(str, Enum):
    SSN         = "ssn"
    CREDIT_CARD = "credit_card"
    EMAIL       = "email"
    PHONE       = "phone"
    PERSON_NAME = "person_name"
    API_KEY     = "api_key"
    ADDRESS     = "address"
    IP_ADDRESS  = "ip_address"
```

### `RedactionAction` enum

```python theme={null}
class RedactionAction(str, Enum):
    REDACT   = "redact"    # Replace with a placeholder token
    BLOCK    = "block"     # Reject the request entirely (HTTP 403)
    LOG_ONLY = "log_only"  # Log the detection but forward unchanged
```

***

## InjectionDefenseConfig

Detect and block prompt injection attempts in outbound HTTP request bodies.

```python theme={null}
from declaw import InjectionDefenseConfig, InjectionAction, InjectionSensitivity

injection = InjectionDefenseConfig(
    enabled=True,
    action=InjectionAction.LOG_ONLY.value,
    sensitivity=InjectionSensitivity.MEDIUM.value,
    threshold=0.8,
)
```

<ParamField body="enabled" type="bool" default="False">
  Whether injection defense is active.
</ParamField>

<ParamField body="action" type="str" default="'log_only'">
  Action when injection is detected. One of `'block'` (HTTP 403) or
  `'log_only'` (forward unchanged, record detection in the audit log).
</ParamField>

<ParamField body="sensitivity" type="str" default="'medium'">
  Preset sensitivity tier. One of `'low'`, `'medium'`, `'high'`. Adjusts the
  scanner's detection aggressiveness independently of `threshold`.
</ParamField>

<ParamField body="threshold" type="float" default="0.8">
  Confidence threshold between `0.0` and `1.0`. Requests with a score above
  this value trigger the configured action. Lower values increase sensitivity.
</ParamField>

<ParamField body="domains" type="list[str] | None" default="None">
  Limit injection scanning to these domains. `None` means scan all.
</ParamField>

### `InjectionAction` enum

```python theme={null}
class InjectionAction(str, Enum):
    BLOCK    = "block"     # Reject the request (HTTP 403)
    LOG_ONLY = "log_only"  # Log and forward unchanged
```

### `InjectionSensitivity` enum

```python theme={null}
class InjectionSensitivity(str, Enum):
    LOW    = "low"
    MEDIUM = "medium"
    HIGH   = "high"
```

***

## ToxicityConfig

Scan outbound HTTP request bodies for toxic content (harassment, hate speech, etc.).

```python theme={null}
from declaw import ToxicityConfig

toxicity = ToxicityConfig(
    enabled=True,
    threshold=0.9,
    action="block",
)
```

<ParamField body="enabled" type="bool" default="False">
  Whether toxicity scanning is active.
</ParamField>

<ParamField body="threshold" type="float" default="0.9">
  Confidence threshold between `0.0` and `1.0`. Requests scoring above this
  value trigger the configured action.
</ParamField>

<ParamField body="action" type="str" default="'block'">
  Action when toxic content is detected. One of `'block'` (HTTP 403) or
  `'log_only'`.
</ParamField>

***

## CodeSecurityConfig

Detect suspicious or unsafe code in outbound HTTP request bodies.

```python theme={null}
from declaw import CodeSecurityConfig

code = CodeSecurityConfig(
    enabled=True,
    threshold=0.6,
    action="log_only",
    excluded_languages=["markdown", "plaintext"],
)
```

<ParamField body="enabled" type="bool" default="False">
  Whether code-security scanning is active.
</ParamField>

<ParamField body="threshold" type="float" default="0.6">
  Confidence threshold between `0.0` and `1.0`.
</ParamField>

<ParamField body="action" type="str" default="'log_only'">
  Action when suspicious code is detected. One of `'block'` (HTTP 403) or
  `'log_only'`.
</ParamField>

<ParamField body="excluded_languages" type="list[str] | None" default="None">
  Languages to exclude from scanning. Useful when content is intentionally
  code but already in a trusted context.
</ParamField>

***

## InvisibleTextConfig

Detect invisible or control Unicode characters (often used to smuggle prompt
instructions past the model) in outbound HTTP request bodies.

```python theme={null}
from declaw import InvisibleTextConfig

invisible = InvisibleTextConfig(
    enabled=True,
    action="strip",
)
```

<ParamField body="enabled" type="bool" default="False">
  Whether invisible-text scanning is active.
</ParamField>

<ParamField body="action" type="str" default="'strip'">
  Action when invisible characters are detected. One of `'block'` (HTTP 403),
  `'strip'` (remove the characters and forward), or `'log_only'`.
</ParamField>

***

## CustomPolicyConfig

Attach OPA/Rego policy — a built-in governance pack via `policy_ref`, or your
own rules via `inline_rego` / `inline_modules`. Custom rules are evaluated at
the enforcement layer alongside the platform defaults and can only tighten
policy, never relax it.

```python theme={null}
from declaw import CustomPolicyConfig

# Reference a built-in governance pack
custom = CustomPolicyConfig(
    enabled=True,
    policy_ref="owasp-llm-top10@v1",
    default_deny=False,
)

# Or supply your own Rego
custom = CustomPolicyConfig(
    enabled=True,
    inline_rego='''
        deny_command contains msg if {
            input.action.command in {"rm", "dd"}
            msg := "dangerous command blocked"
        }
    ''',
)
```

<ParamField body="enabled" type="bool" default="False">
  Whether custom policy evaluation is active for the sandbox.
</ParamField>

<ParamField body="inline_rego" type="str | None" default="None">
  A single Rego module string appended to the platform defaults. Use this for
  a single-package policy.
</ParamField>

<ParamField body="inline_modules" type="list[str] | None" default="None">
  A list of independent Rego module strings, each its own `package`. Use this
  when your policy spans multiple packages; for a single package use
  `inline_rego` instead.
</ParamField>

<ParamField body="policy_ref" type="str | None" default="None">
  Reference a published or built-in policy bundle by `name@version` (e.g.
  `owasp-llm-top10@v1`), `sha256:<hex>`, or `blob:<key>`. See
  [Governance Packs](/security/governance-packs) for the catalog.
</ParamField>

<ParamField body="default_deny" type="bool" default="False">
  Fail-closed behavior: when `True`, an evaluator error or unreachable engine
  denies the action. Fail-closed is safer for hard security gates; fail-open
  (`False`) is acceptable for advisory-only scanners.
</ParamField>

See [Custom Policy](/security/custom-policy) and
[Governance Packs](/security/governance-packs) for the full guides.

***

## ContentGateConfig

Run the `content.scan` OPA gate (e.g. an LLM model allowlist / cross-signal
rules) on the listed domains. Opts a sandbox into content-gate enforcement
without requiring an ML scanner to be enabled.

```python theme={null}
from declaw import ContentGateConfig

content = ContentGateConfig(
    enabled=True,
    domains=["api.openai.com", "api.anthropic.com"],
)
```

<ParamField body="enabled" type="bool" default="False">
  Whether the content gate is active.
</ParamField>

<ParamField body="domains" type="list[str] | None" default="None">
  Opt-in list of destination hosts to intercept. Empty or `None` means no
  hosts are intercepted.
</ParamField>

See [Custom Policy](/security/custom-policy) for details.

***

## NetworkPolicy

Network allowlist and denylist for outbound traffic from the sandbox. Set this on `SecurityPolicy.network` to apply it alongside other security controls.

```python theme={null}
from declaw import NetworkPolicy, ALL_TRAFFIC

# Allow only pypi.org and github.com, deny everything else
network = NetworkPolicy(
    allow_out=["pypi.org", "*.github.com", "8.8.8.8"],
    deny_out=[ALL_TRAFFIC],
    allow_public_traffic=False,
)
```

<ParamField body="allow_out" type="list[str]" default="[]">
  Destinations to allow. Accepts IP addresses, CIDR blocks (e.g.
  `"10.0.0.0/8"`), and domain names with optional wildcard prefix (e.g.
  `"*.github.com"`).
</ParamField>

<ParamField body="deny_out" type="list[str]" default="[]">
  Destinations to deny. Accepts IP addresses and CIDR blocks only (domains
  not accepted in deny rules).
</ParamField>

<ParamField body="allow_public_traffic" type="bool" default="True">
  Whether to allow all public traffic by default. Set to `False` when using
  `allow_out` to build an allowlist.
</ParamField>

<ParamField body="mask_request_host" type="str | None" default="None">
  Replace the `Host` header in all outbound requests with this value. Used
  for routing through a reverse proxy.
</ParamField>

### `ALL_TRAFFIC` constant

```python theme={null}
ALL_TRAFFIC: str = "0.0.0.0/0"
```

Use `deny_out=[ALL_TRAFFIC]` to block all outbound traffic.

### `SandboxNetworkOpts`

`SandboxNetworkOpts` is the lower-level equivalent used directly in `Sandbox.create(network=...)`. It has the same fields as `NetworkPolicy` using `snake_case` attribute names.

```python theme={null}
from declaw import SandboxNetworkOpts

network = SandboxNetworkOpts(
    allow_out=["pypi.org"],
    deny_out=[ALL_TRAFFIC],
    allow_public_traffic=False,
)
```

***

## TransformationRule

Regex-based text transformation applied to outbound request bodies, inbound response bodies, or both.

```python theme={null}
from declaw import TransformationRule, TransformDirection

# Strip Bearer tokens from outbound requests
rule = TransformationRule(
    match=r"Bearer [A-Za-z0-9\-_\.]+",
    replace="Bearer [REDACTED]",
    direction=TransformDirection.OUTBOUND.value,
)
```

<ParamField body="match" type="str" required>
  Python-compatible regular expression. Must be a valid regex pattern.
</ParamField>

<ParamField body="replace" type="str" required>
  Replacement string. Supports Python `re.sub` back-references (e.g. `\1`).
</ParamField>

<ParamField body="direction" type="str" default="'outbound'">
  Direction to apply the rule. One of `'outbound'`, `'inbound'`, `'both'`.
</ParamField>

### `TransformDirection` enum

```python theme={null}
class TransformDirection(str, Enum):
    OUTBOUND = "outbound"   # Apply to requests leaving the sandbox
    INBOUND  = "inbound"    # Apply to responses entering the sandbox
    BOTH     = "both"       # Apply in both directions
```

### Methods

| Method                       | Returns | Description                                             |
| ---------------------------- | ------- | ------------------------------------------------------- |
| `rule.applies_to(direction)` | `bool`  | Whether the rule applies in the given direction string. |
| `rule.apply(text)`           | `str`   | Apply the regex substitution to `text`.                 |

***

## AuditConfig

Toggle whether lifecycle and security events for the sandbox are shipped
to Declaw's audit log.

```python theme={null}
from declaw import AuditConfig

# Opt out of audit logging for this sandbox
audit = AuditConfig(enabled=False)
```

<ParamField body="enabled" type="bool" default="True">
  When `True` (the default), the orchestrator records the sandbox's
  lifecycle events (create, kill, pause, resume, snapshot) and security
  decisions (egress allow/block) to the audit log. Set to `False` to
  suppress all audit events for the sandbox.
</ParamField>

Audit log retention is a platform-wide setting (currently a 7-day
rolling window) and is not configurable per sandbox. Request and
response body logging is not exposed to callers.

### `AuditEntry`

```python theme={null}
@dataclass
class AuditEntry:
    timestamp: datetime.datetime
    method: str
    url: str
    status_code: int = 0
    pii_redactions: int = 0
    injection_blocks: int = 0
    transformations_applied: int = 0
    direction: str = "outbound"
```

***

## EnvSecurityConfig

Control how environment variable values are masked in audit logs.

```python theme={null}
from declaw import EnvSecurityConfig

env_sec = EnvSecurityConfig(
    mask_patterns=["*_KEY", "*_SECRET", "*_TOKEN", "*_PASSWORD", "API_KEY"],
    auto_mask_in_audit=True,
)
```

<ParamField body="mask_patterns" type="list[str]" default="['*_KEY', '*_SECRET', '*_TOKEN', '*_PASSWORD', '*_CREDENTIALS', 'API_KEY', 'SECRET_KEY']">
  Glob patterns matched against uppercase environment variable names. Variables
  matching any pattern are masked as `***` in audit logs.
</ParamField>

<ParamField body="auto_mask_in_audit" type="bool" default="True">
  Automatically redact matching variable values in all audit log entries.
</ParamField>

### `SecureEnvVar`

Pass sensitive environment variables without leaking values in logs:

```python theme={null}
from declaw import SecureEnvVar

var = SecureEnvVar(key="OPENAI_API_KEY", value="sk-...", secret=True)
var.to_safe_dict()  # {"key": "OPENAI_API_KEY", "value": "***", "secret": True}
```

***

## Full policy example

```python theme={null}
from declaw import (
    Sandbox, SecurityPolicy,
    PIIConfig, PIIType,
    InjectionDefenseConfig, InjectionAction,
    NetworkPolicy, ALL_TRAFFIC,
    TransformationRule, TransformDirection,
    AuditConfig,
    CustomPolicyConfig, ContentGateConfig,
)

policy = SecurityPolicy(
    pii=PIIConfig(
        enabled=True,
        types=[PIIType.EMAIL, PIIType.SSN, PIIType.CREDIT_CARD],
        action="redact",
        rehydrate_response=True,
    ),
    injection_defense=InjectionDefenseConfig(
        enabled=True,
        action=InjectionAction.BLOCK.value,
        threshold=0.75,
    ),
    network=NetworkPolicy(
        allow_out=["api.openai.com", "pypi.org"],
        deny_out=[ALL_TRAFFIC],
        allow_public_traffic=False,
    ),
    transformations=[
        TransformationRule(
            match=r"sk-[A-Za-z0-9]+",
            replace="sk-[REDACTED]",
            direction=TransformDirection.OUTBOUND.value,
        ),
    ],
    custom_policy=CustomPolicyConfig(
        enabled=True,
        policy_ref="owasp-llm-top10@v1",
    ),
    content_gate=ContentGateConfig(
        enabled=True,
        domains=["api.openai.com"],
    ),
    audit=AuditConfig(enabled=True),
)

sbx = Sandbox.create(
    security=policy,
    api_key="your-api-key",
    domain="104.198.24.180:8080",
)
```
