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

# Networking

> Network access control — proxy modes, domain filtering, credential injection, and localhost IPC

By default the sandboxed process has unrestricted network access. When you restrict networking, nono routes traffic through an HTTP proxy running in the unsandboxed supervisor process. The sandboxed child can only reach `localhost:<proxy-port>` — all other outbound TCP is blocked at the kernel level.

The same proxy can also be run on its own with [`nono proxy`](#standalone-proxy-nono-proxy) — a foreground server with no sandboxed child — so you can point external workloads (containers, microVMs) at nono's domain filtering and credential injection.

## Common cases

```bash theme={null}
# Allow only specific domains — everything else is blocked
nono run --allow-cwd --allow-domain api.openai.com -- my-agent

# Block all outbound network
nono run --allow-cwd --block-net -- my-agent

# Inject an API key the sandbox never sees
nono run --allow-cwd --credential openai -- my-agent
```

## Proxy Modes

The proxy supports three modes that can be combined in a single session:

| Mode               | What it does                                                                                                                                                              | Activated by                          |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- |
| **CONNECT tunnel** | Domain-filtered HTTPS tunneling. Validates the target host against an allowlist, then relays raw TCP bytes. TLS is end-to-end — the proxy never sees plaintext.           | `--allow-domain`, `--network-profile` |
| **Reverse proxy**  | Credential injection for API calls. Requests arrive at `http://localhost:<port>/<service>/...`, the proxy injects the real API key and forwards to the upstream over TLS. | `--credential`                        |
| **External proxy** | Enterprise proxy passthrough. CONNECT requests are chained through a corporate proxy. Cloud metadata endpoints are still denied.                                          | `--upstream-proxy`                    |

When domain filtering or credential injection is active, the proxy starts automatically. `HTTP_PROXY` and `HTTPS_PROXY` are set in the child environment. For Node.js 26+, nono also sets `NODE_USE_ENV_PROXY=1` so built-in `fetch()` reads `HTTPS_PROXY`.

A 256-bit session token is generated for each proxy session. The child must include it in every request (`Proxy-Authorization` header for CONNECT, `X-Nono-Token` for reverse proxy), preventing other localhost processes from using the proxy.

## Blocking All Network

```bash theme={null}
nono run --allow-cwd --block-net -- cargo build
```

No outbound connections are permitted. See [Localhost IPC](#localhost-ipc) for allowing specific ports as exceptions.

In a profile, set `network.block` to `true`:

```json theme={null}
{
  "network": { "block": true }
}
```

## CONNECT Tunnel (Domain Filtering)

The CONNECT tunnel is the most common proxy mode. It validates outbound hostnames against an allowlist, then relays raw TCP bytes. TLS is end-to-end between the sandboxed process and the upstream server — the proxy never sees plaintext.

`--allow-domain` is an HTTP(S) proxy allowlist, not a generic raw TCP `host:port` allow. When domain filtering is active, direct outbound connections are blocked and traffic must go through the proxy.

```bash theme={null}
# Allow specific domains (unrestricted access)
nono run --allow-cwd --allow-domain api.openai.com --allow-domain api.anthropic.com -- my-agent

# Restrict a domain to specific path patterns
nono run --allow-cwd \
  --allow-domain 'https://github.com/my-org/**' \
  --allow-domain 'https://github.com/my-other-org/**' \
  -- my-agent

# Use a predefined network profile
nono run --allow-cwd --network-profile claude-code -- claude
```

When `--allow-domain` is given a URL with a path (e.g., `https://github.com/org/**`), only requests matching that path pattern are allowed for that domain. Requests to other paths on the same domain receive `403 Forbidden`. A plain hostname (e.g., `api.openai.com`) allows all paths on the domain.

Use `nono why --self --host https://github.com/some/path` inside the sandbox to check whether a specific URL is permitted and see the configured endpoint rules.

<img src="https://mintcdn.com/alwaysfurther/pmWQoFvNV8bx8U2E/assets/proxy-flow.png?fit=max&auto=format&n=pmWQoFvNV8bx8U2E&q=85&s=b0e3fa32f982d0d6a63a2a1933c262dc" alt="Proxy architecture flow" width="2145" height="1536" data-path="assets/proxy-flow.png" />

### DNS Rebinding Protection

The proxy resolves DNS itself and checks all resolved IPs against the deny list before connecting. This prevents DNS rebinding attacks where a malicious DNS server maps an allowed hostname to an internal IP.

### Proxy Port

By default the proxy binds to an OS-assigned ephemeral port. Use `--proxy-port` to fix it when the application requires a known port:

```bash theme={null}
nono run --profile openclaw --proxy-port 19999 --listen-port 18789 -- openclaw gateway
```

Applications that read `OPENAI_BASE_URL`, `ANTHROPIC_BASE_URL`, etc. from the environment don't need `--proxy-port` — nono sets these automatically.

### Network Profiles

Network profiles are named sets of allowed domains composed from groups. They are defined in `network-policy.json` (embedded in the binary) and activated with `--network-profile` or via a profile's `network.network_profile` field.

#### Preset Network Profiles

| Profile       | Groups                                                                  | Use Case               |
| ------------- | ----------------------------------------------------------------------- | ---------------------- |
| `minimal`     | `llm_apis`                                                              | LLM API access only    |
| `developer`   | `llm_apis`, `package_registries`, `github`, `sigstore`, `documentation` | General development    |
| `claude-code` | `llm_apis`, `package_registries`, `github`, `sigstore`, `documentation` | Claude Code agent      |
| `codex`       | Same as `developer` + bundled `openai` credential                       | Codex agent            |
| `opencode`    | Same as `developer` + bundled `google-ai` credential                    | OpenCode agent         |
| `enterprise`  | All groups + `google_cloud`, `azure`, `aws_bedrock`                     | Corporate environments |

#### Groups

Each group maps to a set of allowed hostnames and wildcard suffixes:

| Group                | Hosts                                                                     |
| -------------------- | ------------------------------------------------------------------------- |
| `llm_apis`           | api.openai.com, api.anthropic.com, generativelanguage.googleapis.com, ... |
| `package_registries` | registry.npmjs.org, pypi.org, crates.io, ...                              |
| `github`             | github.com, api.github.com, raw\.githubusercontent.com, ...               |
| `sigstore`           | fulcio.sigstore.dev, rekor.sigstore.dev, tuf-repo-cdn.sigstore.dev        |
| `documentation`      | docs.python.org, developer.mozilla.org, doc.rust-lang.org, ...            |
| `google_cloud`       | \*.googleapis.com                                                         |
| `azure`              | \*.openai.azure.com, \*.cognitiveservices.azure.com                       |
| `aws_bedrock`        | \*.bedrock.amazonaws.com, \*.bedrock-runtime.amazonaws.com                |

### Adding Domains

Use `--allow-domain` on the command line or `allow_domain` in a profile to add domains on top of the network profile:

```json theme={null}
{
  "meta": { "name": "my-agent" },
  "filesystem": { "allow": ["$WORKDIR"] },
  "network": {
    "network_profile": "developer",
    "allow_domain": ["my-internal-api.example.com"]
  }
}
```

```bash theme={null}
nono run --allow-cwd --network-profile developer --allow-domain my-internal-api.example.com -- my-agent
```

### Client-Side Proxy Bypass

Profiles can add host patterns to the generated `NO_PROXY` and `no_proxy` environment variables with `network.no_proxy`. nono still emits loopback defaults and any safe direct-connect bypasses first; parent-shell `NO_PROXY` values are not inherited. These entries do not grant network access; on macOS ProxyOnly and other restricted modes, direct connections still require matching sandbox permissions.

```json theme={null}
{
  "network": {
    "network_profile": "developer",
    "no_proxy": ["redis", ".internal.example"]
  }
}
```

Entries must be host patterns, not URLs or `host:port` values. Bare multi-label domains and protected metadata suffix tokens are rejected because common clients treat them as suffix matches; use a safe single-label local alias like `redis`, a canonical IP literal, or an explicit suffix pattern such as `.internal.example`. Patterns conflicting with proxy-allowed hosts or credential/L7-filtered route upstreams fail configuration so that traffic stays on the local nono proxy.

Generated `NO_PROXY` / `no_proxy` values use common environment-client syntax, so profile `*.internal.example` is emitted as `.internal.example`. nono also emits `NONO_NO_PROXY` with canonical nono patterns, preserving forms such as `*.internal.example`, so wrappers can translate them to runtime-specific formats like Java `http.nonProxyHosts`.

## Reverse Proxy (Credential Injection)

When `--credential` is active, the proxy runs a reverse proxy alongside the CONNECT tunnel. The sandboxed process sends plain HTTP requests to `http://localhost:<port>/<service>/...`, and the proxy injects the real API key and forwards to the upstream over TLS.

```bash theme={null}
nono run --allow-cwd --credential openai -- my-agent
```

The agent never sees the real credential. A phantom session token is placed in the sandbox environment; the proxy swaps it for the real key at the HTTP header level. See [Credential Injection](/docs/cli/features/credential-injection) for full details on credential sources, custom credentials, and endpoint filtering.

## External Proxy (Enterprise Passthrough)

For corporate environments with a mandatory outbound proxy, chain domain-filtered traffic through it with `--upstream-proxy`. This is typically paired with the `enterprise` network profile:

```bash theme={null}
nono run --allow-cwd --network-profile enterprise \
  --upstream-proxy squid.corp:3128 -- my-agent
```

CONNECT requests are chained through the corporate proxy. Cloud metadata endpoints are still denied regardless.

### Bypassing the External Proxy

Some domains may need to bypass the upstream proxy and connect directly:

```bash theme={null}
nono run --allow-cwd --network-profile enterprise \
  --upstream-proxy squid.corp:3128 \
  --upstream-bypass git.internal.corp \
  --upstream-bypass "*.dev.local" \
  -- my-agent
```

Bypass patterns support exact hostnames and `*.` wildcard suffixes (case-insensitive). Matching hosts route directly; everything else goes through the upstream proxy.

This can also be configured in a profile:

```json theme={null}
{
  "network": {
    "network_profile": "enterprise",
    "upstream_proxy": "squid.corp:3128",
    "upstream_bypass": ["git.internal.corp", "*.dev.local"]
  }
}
```

Or via environment variables:

```bash theme={null}
export NONO_UPSTREAM_PROXY=squid.corp:3128
export NONO_UPSTREAM_BYPASS=git.internal.corp,*.dev.local
nono run --allow-cwd --network-profile enterprise -- my-agent
```

## Standalone Proxy (`nono proxy`)

`nono run` / `shell` / `wrap` start the proxy as a side effect of launching a sandboxed child, wiring `HTTP_PROXY`/`HTTPS_PROXY` and the session token into that child. `nono proxy` instead runs the same network-filtering / credential-injection proxy as a **foreground server with no sandboxed child**, prints the connection details, and blocks until you press Ctrl-C.

This lets you point your own tools at nono's domain filtering and credential injection, useful for workloads that provide their own OS-level isolation, such as Docker containers, Kata Containers, Kubernetes pods, Firecracker, and gVisor. The workload routes its egress through the proxy via `HTTP(S)_PROXY` while isolation comes from the container/microVM runtime.

```bash theme={null}
# Ephemeral port, token auth, prints connection info
nono proxy

# Fixed port
nono proxy --port 8080

# Allowlist a host
nono proxy --allow-domain github.com

# Load network/credential settings from a profile
nono proxy --profile my-profile
```

On startup it prints the proxy URL (with the embedded credential), the raw token, ready-to-paste `HTTP(S)_PROXY` exports, a summary of configured routes, and — when TLS interception is active — the trust-bundle path:

```
  nono proxy listening on 127.0.0.1:8080
  proxy URL: http://nono:<token>@127.0.0.1:8080
  token:     <token>

  export HTTPS_PROXY=http://nono:<token>@127.0.0.1:8080
  export HTTP_PROXY=http://nono:<token>@127.0.0.1:8080

  Press Ctrl-C to stop.
```

Settings are loaded from `--profile` and extended/overridden by explicit flags, reusing the same configuration machinery as the sandboxed path. Allow-domains and credentials are merged on top of the profile; the network profile and upstream proxy are overridden by flags. Credential injection for known services and `cmd://` credential-capture routes carry through the profile exactly as they do under `nono run`.

### Flags

| Flag                                     | Purpose                                                                                                                                                              |
| ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--listen <ADDR>`                        | Bind address (default `127.0.0.1`).                                                                                                                                  |
| `--port <PORT>`                          | Port to listen on (`0` = OS-assigned ephemeral, the default).                                                                                                        |
| `--no-auth`                              | Disable session-token auth — accept every request on the bind address. Loopback only.                                                                                |
| `--pass <PASSWORD>`                      | Pin the proxy credential to a fixed value instead of a random token. Reads `NONO_PROXY_PASS`.                                                                        |
| `--profile <NAME_OR_PATH>`               | Load network/credential settings from a profile.                                                                                                                     |
| `--max-connections <N>`                  | Maximum concurrent client connections (`0` = unlimited, default `256`). Raise for highly parallel clients such as `docker pull`. Reads `NONO_PROXY_MAX_CONNECTIONS`. |
| `--network-profile <PROFILE>`            | Enable a named network profile (e.g. `developer`).                                                                                                                   |
| `--allow-domain <DOMAIN_OR_URL>`         | Add a domain (or path-scoped URL) to the allowlist (repeatable).                                                                                                     |
| `--credential <SERVICE>`                 | Inject credentials for a service via the reverse proxy (repeatable).                                                                                                 |
| `--allow-endpoint <SERVICE:METHOD:PATH>` | Restrict a credential service to specific HTTP method+path patterns (repeatable). See [Endpoint Filtering](#endpoint-filtering).                                     |
| `--upstream-proxy <HOST:PORT>`           | Chain outbound traffic through an upstream proxy.                                                                                                                    |
| `--upstream-bypass <DOMAIN>`             | Route these domains direct instead of through the upstream proxy (requires `--upstream-proxy`).                                                                      |
| `--allow-http2`                          | Negotiate HTTP/2 with upstreams that support it (ALPN). Off by default. See [HTTP/2 Support](#http2-support---allow-http2).                                          |
| `--proxy-ca-validity <DAYS>`             | Proxy CA certificate validity in days (1–365). Conflicts with `--proxy-ca-cert`.                                                                                     |
| `--trust-proxy-ca`                       | Add the proxy CA to the macOS user trust store (macOS only).                                                                                                         |
| `--proxy-ca-cert <PEM_FILE>`             | Sign intercepted TLS with this existing CA certificate (PEM) instead of a fresh per-session CA. Requires `--proxy-ca-key`. Reads `NONO_PROXY_CA_CERT`.               |
| `--proxy-ca-key <PEM_FILE>`              | PKCS#8 private key (PEM) for `--proxy-ca-cert`. Reads `NONO_PROXY_CA_KEY`.                                                                                           |

### Reusing a CA across runs

By default each `nono proxy` run mints a fresh ephemeral CA, so any client that trusts the intercepted TLS has to re-trust a new certificate every time. To keep one CA across runs — trust it once in your clients, containers, or microVM images — supply your own with `--proxy-ca-cert` and `--proxy-ca-key`:

```bash theme={null}
nono proxy \
  --allow-domain 'https://api.github.com/**' \
  --proxy-ca-cert ./ca.crt \
  --proxy-ca-key ./ca.key
```

The key must be an **ECDSA P-256** private key in **PKCS#8** PEM (`-----BEGIN PRIVATE KEY-----`); the certificate must be a CA certificate in PEM. Generate a pair with OpenSSL:

```bash theme={null}
# PKCS#8 EC P-256 private key
openssl ecparam -name prime256v1 -genkey -noout -out ca.ec.key
openssl pkcs8 -topk8 -nocrypt -in ca.ec.key -out ca.key && rm ca.ec.key

# Self-signed CA certificate (30-day validity here)
openssl req -x509 -new -nodes -key ca.key -sha256 -days 30 \
  -subj "/CN=my-proxy-ca" \
  -addext "basicConstraints=critical,CA:TRUE" \
  -addext "keyUsage=critical,keyCertSign,cRLSign,digitalSignature" \
  -out ca.crt
```

The key and cert are validated at startup: a mismatched pair (or an unreadable file) fails the command immediately rather than silently disabling interception. Validity comes from the supplied certificate, so `--proxy-ca-cert` cannot be combined with `--proxy-ca-validity`; on macOS it also cannot be combined with `--trust-proxy-ca`, which manages its own CA in the Keychain. Protect the key file — anyone who can read it can mint certificates your clients will trust.

<Note>
  TLS interception (and therefore the CA) only activates when a route requires layer-7 visibility — for example an endpoint-scoped `--allow-domain` (a URL with a path glob) or `--allow-endpoint` rules. Plain host allowlisting tunnels CONNECT traffic without interception, so no CA is used.
</Note>

### Authentication

By default the proxy generates a random per-session token; clients authenticate with `Proxy-Authorization` (Basic via the `nono:<token>` userinfo in the printed URL, or Bearer). To use a fixed credential, pass `--pass` (or set `NONO_PROXY_PASS` to keep it out of shell history and process listings).

`--no-auth` starts an open proxy that accepts every request on the bind address. To fail secure, it is **refused for non-loopback bind addresses** so you can't accidentally expose an open proxy to other hosts, and it is mutually exclusive with `--pass`.

## Endpoint Filtering

When credential injection routes traffic through the reverse proxy, you can further restrict which HTTP method+path combinations are allowed on a per-service basis. This enforces least-privilege at the API level — the agent can reach an allowed domain but only use specific endpoints.

### CLI Usage

Use `--allow-endpoint` to restrict a credential service to specific patterns:

```bash theme={null}
# Allow only chat completions through OpenAI
nono run --allow-cwd --credential openai \
  --allow-endpoint 'openai:POST:/v1/chat/completions' \
  -- my-agent

# Allow GitHub issue reads and comment writes, block everything else
nono run --allow-cwd --credential github \
  --allow-endpoint 'github:GET:/repos/*/issues/**' \
  --allow-endpoint 'github:POST:/repos/*/issues/*/comments' \
  -- my-agent
```

When any endpoint rules are configured for a service, requests that don't match receive `403 Forbidden` and are logged in the audit trail.

### Profile Configuration

Endpoint rules can also be defined on custom credentials within profiles:

```json theme={null}
{
  "network": {
    "custom_credentials": {
      "gitlab": {
        "upstream": "https://gitlab.example.com",
        "credential_key": "gitlab_token",
        "endpoint_rules": [
          { "method": "GET", "path": "/api/v4/projects/*/merge_requests/**" },
          { "method": "POST", "path": "/api/v4/projects/*/merge_requests/*/notes" }
        ]
      }
    }
  }
}
```

See [Credential Injection — Custom Credential Definitions](/docs/cli/features/credential-injection#custom-credential-definitions) for the full `custom_credentials` schema.

### Pattern Syntax

Path patterns use standard glob syntax (same as `.gitignore` and nono profile `include` patterns):

| Pattern                | Matches                                             |
| ---------------------- | --------------------------------------------------- |
| `/v1/chat/completions` | Exact path only                                     |
| `/repos/*/issues`      | One segment wildcard (e.g., `/repos/myrepo/issues`) |
| `/api/**`              | Zero or more segments (e.g., `/api/v1/data/export`) |
| `*`                    | Any method (when used as the method field)          |

## Localhost IPC

Use `--open-port` to allow bidirectional localhost TCP on a specific port (connect + listen). This enables IPC between sandboxed processes — for example, an MCP server in one sandbox and an AI agent in another.

```bash theme={null}
# Terminal 1: MCP server listening on port 3000
nono run --block-net --open-port 3000 --allow ./mcp-server -- node server.js

# Terminal 2: Agent connecting to the MCP server
nono run --block-net --open-port 3000 --allow ./client -- claude
```

`--open-port` works alongside domain filtering. Outbound to allowed hosts goes through the proxy; IPC stays on localhost:

```bash theme={null}
nono run --network-profile claude-code --open-port 3000 --allow-cwd -- claude
```

This generates Seatbelt rules (macOS) or Landlock rules (Linux) that allow both `connect()` and `bind()` on the specified port, in addition to the proxy port.

See [CLI Reference](/docs/cli/usage/flags#--open-port) for full details and platform limitations.

### Listen-Only Ports

Use `--listen-port` when a sandboxed process needs to accept inbound connections but does not need to initiate outbound connections on that port (e.g., a server or gateway):

```bash theme={null}
nono run --allow-cwd --network-profile developer --listen-port 3000 -- npm run dev
```

See [CLI Reference](/docs/cli/usage/flags#--listen-port) for platform limitations.

## Always-Denied Destinations

The following destinations are always blocked by the proxy, regardless of configuration. These cannot be overridden.

| Destination                    | Why                                        |
| ------------------------------ | ------------------------------------------ |
| `169.254.169.254`              | AWS/GCP/Azure instance metadata            |
| `fd00:ec2::254`                | AWS IMDS IPv6 endpoint                     |
| `metadata.google.internal`     | GCP metadata alias                         |
| `metadata.azure.internal`      | Azure metadata alias                       |
| `169.254.0.0/16` (resolved IP) | IPv4 link-local — DNS rebinding protection |
| `fe80::/10` (resolved IP)      | IPv6 link-local — DNS rebinding protection |

Private network addresses (RFC1918: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) are allowed to support enterprise environments.

## Platform Behavior

### Linux

Network filtering uses Landlock V4+ per-port TCP rules. The sandbox restricts `connect()` to only the proxy port. All other outbound TCP is blocked at the kernel level.

**Requirements:** Landlock ABI v4+ (Linux 6.7+)

### macOS

Network filtering uses Seatbelt rules. The sandbox allows only `(remote tcp "localhost:PORT")` and denies all other network operations.

```scheme theme={null}
(deny network*)
(allow network-outbound (remote tcp "localhost:PORT"))
(allow system-socket (socket-domain AF_INET) (socket-type SOCK_STREAM))
(allow system-socket (socket-domain AF_INET6) (socket-type SOCK_STREAM))
```

### WSL2

The WSL2 kernel (6.6) ships with Landlock V3, which does not include TCP network filtering (V4 requires kernel 6.7+). Additionally, the seccomp-based proxy fallback is unavailable due to [WSL2's own seccomp notify listener](https://github.com/microsoft/WSL/issues/9548).

**What works:** `--block-net` (blocks all networking via `SECCOMP_RET_ERRNO`).

**What doesn't work:** Per-port filtering (`--open-port`, `--listen-port`) and proxy-based domain filtering (`--allow-domain`, `--network-profile`, `--credential`). Domain filtering is blocked by default on WSL2 — set `wsl2_proxy_policy: "insecure_proxy"` in your profile's security config to opt in to degraded execution. See [Credential Proxy on WSL2](/docs/cli/internals/wsl2#credential-proxy-on-wsl2) for details.

When Microsoft upgrades the WSL2 kernel to 6.7+, per-port filtering will activate automatically. See [WSL2 Support](/docs/cli/internals/wsl2) for full details.

## Audit Logging

All proxy decisions are logged via `tracing`:

```
ALLOW CONNECT api.openai.com:443
DENY  CONNECT 169.254.169.254:80 reason=denied_cidr
```

Enable verbose logging to see proxy decisions:

```bash theme={null}
nono run -vv --network-profile claude-code --allow-cwd -- my-agent
```

## HTTP/2 Support (`--allow-http2`)

By default, the proxy uses HTTP/1.1 with keep-alive connection pooling for all upstream connections. The `--allow-http2` flag enables HTTP/2 multiplexing via ALPN negotiation:

```bash theme={null}
nono run --profile claude-code --allow-http2 -- claude
```

It can also be set in a profile with `network.allow_http2`, which both `nono run` and `nono proxy` honor.

When enabled:

* **Reverse proxy**: Negotiates h2 with upstreams that support it, allowing multiple requests to be multiplexed over a single TCP connection. This eliminates per-request TLS handshake overhead (\~50-100ms) for workloads with many concurrent requests to the same host (e.g., Maven/Gradle artifact downloads).
* **CONNECT intercept**: Advertises both `h2` and `http/1.1` in ALPN, enabling gRPC and other HTTP/2 clients to negotiate h2 transparently through the proxy. Per-stream endpoint rules and credential injection are enforced at the HTTP/2 frame level.

### Why Disabled by Default

HTTP/2 is opt-in because:

* Some upstream servers or corporate proxies may not handle h2 correctly
* HTTP/1.1 keep-alive is sufficient for most workloads
* h2 multiplexing changes request ordering semantics, which may affect rate-limited APIs

### Connection Pooling

Regardless of `--allow-http2`, the reverse proxy reuses TCP+TLS connections via keep-alive. With HTTP/1.1, connections are reused but requests are serialized per connection. With HTTP/2, multiple concurrent requests share a single connection via stream multiplexing.

The pool provides DNS rebinding protection: resolved IPs are pinned after the initial filter check, preventing TOCTOU attacks on reused connections.

## Limitations

* **No per-port filtering on macOS** — Seatbelt cannot filter outbound by destination port
* **Domain filtering requires supervised execution** — The proxy runs in the unsandboxed parent process, so `nono wrap` (Direct mode) is incompatible. Use `nono run` instead.
* **WSL2: no per-port filtering or domain filtering by default** — See [WSL2 section](#wsl2) above

## Next Steps

* [Credential Injection](/docs/cli/features/credential-injection) — Keep API keys out of the sandbox
* [CLI Reference](/docs/cli/usage/flags) — Complete flag documentation
