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

# Networking

> Control outbound network access from sandboxes using domain allowlists, IP CIDR rules, and the ALL_TRAFFIC constant.

Each sandbox runs in its own Linux network namespace with a dedicated TAP device and veth pair. Outbound traffic passes through a Layer-7 TCP proxy that enforces your network policy before packets reach the internet.

## Default behavior

By default, sandboxes have unrestricted outbound internet access. Any domain or IP is reachable.

## Block all outbound traffic

`ALL_TRAFFIC` is a constant equal to `"0.0.0.0/0"`. Adding it to `deny_out` blocks everything.

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from declaw import Sandbox, ALL_TRAFFIC

    sbx = Sandbox.create(
        network={"deny_out": [ALL_TRAFFIC]}
    )

    # This will fail — no outbound traffic allowed
    result = sbx.commands.run("curl -s https://example.com")
    print(result.exit_code)  # non-zero
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    import { Sandbox, ALL_TRAFFIC } from '@declaw/sdk';

    const sbx = await Sandbox.create({
      network: { denyOut: [ALL_TRAFFIC] },
    });
    ```
  </Tab>
</Tabs>

## Domain allowlist

Allow only specific domains and block everything else.

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from declaw import Sandbox, ALL_TRAFFIC

    sbx = Sandbox.create(
        network={
            "allow_out": ["api.openai.com", "pypi.org"],
            "deny_out": [ALL_TRAFFIC],
        }
    )

    # This works — pypi.org is allowed
    result = sbx.commands.run("pip install requests")

    # This is blocked
    result = sbx.commands.run("curl -s https://google.com")
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const sbx = await Sandbox.create({
      network: {
        allowOut: ['api.openai.com', 'pypi.org'],
        denyOut: [ALL_TRAFFIC],
      },
    });
    ```
  </Tab>
</Tabs>

### Wildcard domain matching

Use `*.` prefix to match all subdomains.

```python theme={null}
sbx = Sandbox.create(
    network={
        "allow_out": [
            "*.openai.com",        # api.openai.com, platform.openai.com, etc.
            "*.anthropic.com",     # api.anthropic.com, etc.
            "*.github.com",        # api.github.com, raw.githubusercontent.com, etc.
            "pypi.org",            # exact match only
        ],
        "deny_out": [ALL_TRAFFIC],
    }
)
```

<Note>
  When domain filtering is enabled, DNS queries to `8.8.8.8` are automatically allowed so that domain resolution works. You do not need to add it manually.
</Note>

## IP and CIDR rules

Use IP addresses or CIDR ranges directly when you know the destination IPs.

```python theme={null}
sbx = Sandbox.create(
    network={
        "deny_out": [ALL_TRAFFIC],
        "allow_out": [
            "1.1.1.1",        # exact IP
            "8.8.8.0/24",     # CIDR range
        ],
    }
)
```

## Combined domains and IPs

Domain and IP rules can be mixed in the same `allow_out` list.

```python theme={null}
sbx = Sandbox.create(
    network={
        "allow_out": [
            "*.openai.com",
            "8.8.8.8",           # Google DNS (by IP)
        ],
        "deny_out": [ALL_TRAFFIC],
    }
)
```

## Priority rules

<Info>
  Allow rules always take precedence over deny rules, regardless of order.
</Info>

The evaluation order is:

1. If the destination matches any `allow_out` entry, the connection is permitted.
2. If the destination matches any `deny_out` entry, the connection is rejected.
3. If no rule matches, the connection is permitted by default (unless `deny_out=[ALL_TRAFFIC]`).

## SandboxNetworkOpts model

| Field               | Type          | Description                                                          |
| ------------------- | ------------- | -------------------------------------------------------------------- |
| `allow_out`         | `list[str]`   | Domains, IPs, or CIDRs to allow                                      |
| `deny_out`          | `list[str]`   | Domains, IPs, or CIDRs to deny; use `ALL_TRAFFIC` to deny everything |
| `mask_request_host` | `str \| None` | Override the `Host` header on outbound requests                      |

## Host header masking

Use `mask_request_host` to override the `Host` header on all outbound requests. Useful when routing traffic through an internal proxy.

```python theme={null}
sbx = Sandbox.create(
    network={"mask_request_host": "internal-proxy.company.com"}
)
```

## How enforcement works

Domain and IP rules are enforced at two layers:

```mermaid theme={null}
flowchart TD
    OUT["Sandbox outbound\nconnection"] --> L1
    L1["Layer 3/4\nCIDR rules\n(kernel-level DROP)"] -->|"IP matches deny"| DROP1["Dropped"]
    L1 -->|"pass"| L2
    L2["Layer 7\nTCP proxy\nSNI + Host inspection"] -->|"domain blocked"| DROP2["REJECT + audit"]
    L2 -->|"pass"| L3
    L3["Internet"] --> L2
    L2 -->|"response"| OUT
```

* **Layer 3/4**: IP and CIDR rules are applied as kernel-level DROP rules with no userspace proxy overhead.
* **Layer 7 (TCP proxy)**: For domain-based rules, all TCP traffic is redirected to the per-namespace proxy. HTTP Host headers and TLS SNI fields are inspected before forwarding.

<Warning>
  UDP and QUIC (HTTP/3) are not supported for domain-level filtering. Domain rules apply only to TCP traffic on ports 80 and 443. Use IP/CIDR rules if you need UDP filtering.
</Warning>

## Block cloud metadata service

Cloud instances expose a metadata endpoint at `169.254.169.254`. This is automatically blocked in all sandboxes to prevent SSRF attacks.

```python theme={null}
# This is always blocked, even with no network policy configured
result = sbx.commands.run("curl -s http://169.254.169.254/latest/meta-data/")
print(result.exit_code)  # non-zero (connection refused)
```

## Inbound traffic (port proxy)

The network policy controls outbound traffic. For **inbound** HTTP access to ports inside a sandbox, see [Port Proxy](/features/port-proxy). Inbound access is gated by the `allow_public_traffic` field in `NetworkPolicy` (defaults to `true`).

## Using SecurityPolicy network configuration

For richer network control integrated with PII scanning and audit logging, use `NetworkPolicy` inside a `SecurityPolicy`:

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

policy = SecurityPolicy(
    network=NetworkPolicy(
        allow_out=["*.openai.com", "*.anthropic.com", "pypi.org"],
        deny_out=[ALL_TRAFFIC],
        allow_public_traffic=False,
    ),
    audit=True,
)

sbx = Sandbox.create(security=policy)
```
