Are you an LLM? You can read better optimized documentation at /docs/agent-guard/network/how-network-access-works.md for this page in Markdown format
How network access works
The microVM reaches only the hosts on the run's allow list. A name the list does not carry does not resolve, and a connection to an address or port the list does not open is refused. That includes your local network, other machines on your VPN, and the services running on your desktop.
The allow list is what keeps a compromised or misled agent from sending your workspace to a host of its choosing. Policies decide which commands the agent may run. The allow list decides where any of them can connect, whatever command made the connection.
The path of a connection
Every outbound connection answers two questions. Is the destination on the list: a name the list does not carry does not resolve, and a listed name is checked again at the Jozu gateway or, for a tcp:// port, by address. Does the host need a credential: for a header entry or a registry entry the gateway ends TLS and sets the credential, and for every other host it passes the connection through without decrypting it. The sections below take each step in turn.
What is on the list without any flags
A run with no --allow-host flags and no agent definition reaches:
| Host | Why | On the list as |
|---|---|---|
| The model API | Requests to the model provider go through the Jozu gateway, which applies GuardrailPolicy to them | Never an entry. An entry that names a model API host has no effect |
The agent's sign-in hosts, such as platform.claude.com for Claude Code | Sign-in and token refresh | The agent's baseline, listed per agent in the network access reference |
deb.debian.org | Installing Debian packages. apt-get is the one command the agent's account may run with sudo, with a restricted argument list | The baseline every run carries |
Some hosts are reached for the agent rather than by it. A remote MCP server named in an agent definition is reached by the Jozu gateway, under policy. api.github.com is reached by Agent Guard itself when a GitHub token is staged, to configure your git identity. OpenClaw's npm registry is reached on the environment's first boot, to install OpenClaw. None of these hosts are open to the agent.
Everything else the agent tries is refused, and the refusal is recorded in the session's egress log. Most agents try a few hosts the baseline leaves out on purpose: update checks, plugin marketplaces, telemetry. The agent works without them, so expect a handful of refused names in every session's log.
How the list is built
The list for a run merges three sources:
| Source | Scope | Use it for |
|---|---|---|
spec.egress in an agent definition | Every run of that definition | Hosts the agent needs to do its job: your git host, package indexes, internal APIs |
--allow-host on agentguard run | One run | A host you need once, or an address that only exists on your network |
| Built-in baselines | Every run | The agent's sign-in hosts and the Debian mirror |
Put a host the agent needs every time in its agent definition. The definition is versioned, can be signed, and goes wherever the agent goes, so the list is reviewed in the same place as the agent's policies and MCP servers. A definition that inherits from a base carries the base's entries, and can add to them but not remove them, so a vetted base can fix a floor for every agent derived from it.
Agent Guard resolves every exact name on the list on your desktop before the microVM boots. A name from --allow-host that does not resolve stops the run, since you are on the network you meant it for. A name from a definition or a baseline that does not resolve is reported as a warning and the run continues: a definition runs on networks its author cannot see, and an internal host that resolves only on the corporate network is expected to fail elsewhere.
How a connection is checked
Each entry form opens one kind of path, and each path is checked in a different place:
| Entry | Opens | Checked by | Where |
|---|---|---|---|
example.com | Port 443 on the name | The name the client asks for | The Jozu gateway |
*.example.com | Port 443 on every name under example.com, not example.com itself | The name | The Jozu gateway |
tcp://host:port | One other port, on the addresses the name resolves to or on the IPv4 address given | The address and port | The microVM's packet filter, and your desktop |
A header entry, or oci://registry | Port 443 on the name, with TLS ending at the gateway | The name, then each request | The Jozu gateway |
Names are checked at the gateway. Every HTTPS connection the agent makes goes to the Jozu gateway first. The gateway reads the name the client asked for in its TLS handshake (the SNI) and compares it with the list. A listed name is connected to the address it resolves to and passed through without decryption. Any other name is closed. The address the client dialled plays no part, so a client that resolves an allowed name and then asks for a different one on the same address gets nothing: a shared CDN address is not an opening for every site behind it. This is the check an HTTP forward proxy with a domain allowlist makes, with no proxy settings and no decryption.
Ports are checked by address. A tcp://host:port entry opens one port on the addresses the name resolves to, or on the address you give. Nothing checks what travels over it, so tcp://github.com:22 opens SSH to GitHub's addresses for any account on them. Prefer HTTPS where the service offers it.
Unlisted names do not resolve. The microVM's resolver answers only names on the list, so the agent sees a lookup failure rather than a refused connection.
Like a firewall egress rule or a Kubernetes NetworkPolicy, the list is a set of destinations. Unlike them, it names hosts rather than address ranges, and a destination's addresses come from DNS while the run is live.
Hosts that need credentials
Some hosts need a credential, and putting the credential in the agent's environment hands it to every process the agent runs. Two kinds of entry give it to the Jozu gateway instead:
A header entry in an agent definition names headers the gateway sets on every request to that host. The agent's environment holds the placeholder
agentguard-withheld-GITHUB_TOKENin place of the token.yaml- host: api.github.com headers: Authorization: "Bearer ${needs.GITHUB_TOKEN}"A registry entry,
oci://ghcr.io, has the gateway sign the agent in to a container registry with the login your desktop'sdockerorpodmanholds.
For these hosts, and only these, the gateway terminates TLS. Inside the microVM the host resolves to the gateway, which presents a certificate signed by the run's certificate authority. The agent's tools trust that authority. The gateway refuses requests whose Host or target names another host, and TRACE, so the credential cannot be steered to another tenant of a shared address or echoed back. It sets the headers and forwards the request over its own TLS connection, verifying the host's certificate against the system trust roots.
The trade is visibility. On a passed-through host, the gateway sees a name. On a host it signs in to, it sees every request and response, in the microVM, and evaluates no policy on them. Every other host on the list stays as described above.
A registry also names hosts at run time: a token service in its sign-in challenge and a content host in its download redirects. The gateway admits those for the rest of the run, the token service with the login and the content host as a plain name, and records each admission in the egress log.
See Credentials for allowed hosts for the walkthrough and the limits.
Two layers
The list is enforced in two places.
Inside the microVM, packet filter rules decide who may send: the agent's connections are checked against the list, and connections made by root are not. The agent's account has no permission to change those rules.
On your desktop, the network stack that carries all of the microVM's traffic enforces the list again, by address. It allows TCP to an address only once that address was opened for the run, from a listed name's DNS answer or a listed IPv4 address. It refuses UDP and ICMP, so ping and HTTP/3 do not work and clients fall back to TCP. This layer does not depend on anything inside the microVM. If root inside the microVM removed the packet filter rules, it would still reach nothing beyond the list.
How this relates to ToolPolicy
A ToolPolicy reads the command the agent runs. The allow list governs the connection the command makes. They catch different things, and they compose:
- A ToolPolicy rule against
curlmissespython -c 'import urllib...'. The allow list refuses the connection whichever program makes it. - The allow list cannot tell an upload to
github.comfrom a clone. A ToolPolicy rule ongit pushorgh gist createcan.
Use the list as the floor and policies for the decisions that depend on arguments. See How policies work.
Turning the list off
--dangerously-allow-all-hosts runs the microVM with no allow list. Every destination is reachable, including your local network, and the egress log records names but no refusals. Model API traffic still goes through the Jozu gateway, so GuardrailPolicy still applies to it.
Header entries and registry entries still apply in open mode: their hosts still resolve to the gateway, which signs the agent in.
Use it to find out which hosts an unfamiliar tool needs, then list them and go back to the default.
What the allow list does not cover
- What travels to an allowed host. An allowed host is allowed for any content. If the agent can reach
github.com, it can push to any repository its credentials reach. Restrict that with ToolPolicy. - What the agent does with a credential the gateway holds. A header entry keeps the token out of the agent's hands, not out of its use: the agent can make any request the token permits on that host. Root inside the microVM can read the value from the gateway's memory.
- Processes running as root inside the microVM. They skip the gateway's name check and reach the addresses the list opened directly, on the ports it opened. When the agent installs a Debian package, the package's install scripts run as root, so the agent can choose code that runs without the name check. It still reaches nothing outside the list.
- DNS under a wildcard. Lookups for names under an allowed wildcard are answered by that domain's name servers, so data can leave encoded in the names the agent looks up. Prefer exact names when you do not control the domain.
- IPv6. The microVM has IPv4 connectivity only. Listed names resolve to their IPv4 addresses, and an IPv6 address cannot be listed.
- Shell mode.
agentguard run --shellruns as your account, which has full sudo inside the microVM and can remove the packet filter rules. The layer on your desktop still applies.
Next steps
- Add the hosts your agent needs: Allow a host
- Entry syntax and baselines: Network access reference
- Every egress record kind and field: Logs and audit
- Where the network sits in the system: Threat model
