Network Access Control
By default, agents with the web_fetch capability can access any public URL. Network access lists let you restrict which hosts and URLs an agent can reach, giving you fine-grained control over outbound network access.
Access lists are configured at three levels, harness, agent, and session, and each layer can only make access more restrictive, never less.
Configuration
Section titled “Configuration”A network access list has two fields:
| Field | Purpose | Default |
|---|---|---|
allowed | If non-empty, only matching URLs are permitted | [] (no restriction) |
blocked | Always denied, even if matched by allowed | [] |
Pattern Format
Section titled “Pattern Format”Patterns support three formats:
| Format | Example | Matches |
|---|---|---|
| Exact domain | api.example.com | Any URL on that exact domain |
| Wildcard domain | *.example.com | The domain and all subdomains |
| URL prefix | https://api.example.com/v1/ | URLs starting with that prefix |
Domain matching is case-insensitive. Blocked patterns always take precedence over allowed patterns.
API Examples
Section titled “API Examples”Set a network access list when creating or updating an agent:
POST /v1/agents{ "name": "Research Agent", "system_prompt": "You are a research assistant.", "network_access": { "allowed": ["*.github.com", "api.openai.com"], "blocked": ["evil.example.com"] }}Restrict a specific session further:
POST /v1/sessions{ "agent_id": "agent_...", "network_access": { "blocked": ["internal.corp"] }}To clear a network access list on update, send an empty object:
PATCH /v1/agents/{id}{ "network_access": {}}Layer Merging
Section titled “Layer Merging”Network access lists merge across three layers using restrictive semantics, each layer can only narrow what the parent allows:
Harness (baseline) ∩ Agent (can only restrict further) ∩ Session (can only restrict further)The merge rules:
| Field | Rule | Rationale |
|---|---|---|
allowed | Intersection: child entries kept only if covered by a parent pattern | Child cannot grant access the parent didn’t allow |
blocked | Union: all blocked patterns combined | Child cannot un-block a parent’s block |
If a child layer doesn’t set allowed, it inherits the parent’s list unchanged.
Example
Section titled “Example”Given this configuration:
Harness: allowed: ["*.github.com", "*.openai.com"]Agent: allowed: ["api.github.com"], blocked: ["evil.com"]Session: blocked: ["malware.github.com"]The effective policy for the session is:
- Allowed:
["api.github.com"], kept because it’s a subset of*.github.com;*.openai.comdropped because the agent didn’t include it - Blocked:
["evil.com", "malware.github.com"], union of all layers
Only api.github.com is reachable, and both evil.com and malware.github.com are explicitly denied.
Harness Inheritance
Section titled “Harness Inheritance”If a harness inherits from a parent harness (via parent_harness_id), the network access list is merged through the inheritance chain before any agent or session layer is applied. The same intersection/union rules apply.
Enforcement
Section titled “Enforcement”The merged network access list is checked in web_fetch before every HTTP request. If a URL doesn’t match the effective policy, the tool returns an error:
URL blocked by network access policy: https://blocked-domain.com/pathStandard SSRF protections (blocking private IPs, loopback, cloud metadata endpoints) are always enforced regardless of the network access list.
Capabilities Affected
Section titled “Capabilities Affected”| Capability | Enforced | Notes |
|---|---|---|
web_fetch | Yes | Checked before every HTTP request |
bashkit_shell | N/A | No network builtins (curl/wget not available) |