# Egress and isolation

> How internet access is selected, carried into a run, and enforced by the proxy and sandbox network.

An agent often needs the internet to install dependencies. Ryph’s egress proxy permits selected hosts while keeping the allowlist outside repository control. It is a separate service from the model proxy and MCP gateway.

**A run’s route to the internet**

- **Agent run** (sandboxed): setup + harness
- **Egress proxy**: verify token · check host
- **Allowed host**: registry.npmjs.org
- **Platform gateways**: models · tools · forge
- **Other host**: request refused

How they connect:

- Agent run → Egress proxy: signed token
- Egress proxy → Allowed host: allow
- Egress proxy → Other host: deny (refused)
- Agent run → Platform gateways: run keys

The proxy verifies the run’s signed host allowlist. Network confinement must also prevent a direct route around the proxy.

For what this means day to day, including how environment builds are confined, see [Egress confinement](https://ryph.ai/docs/egress-confinement.md).

## Resolve the allowlist

The deployment chooses proxy or open mode. In proxy mode, its allowlist defines a ceiling made of registry bundles and additional hostnames. Environment variables seed that ceiling; a saved administrator allowlist takes precedence afterward.

An agent’s network policy can narrow the ceiling. It cannot introduce a bundle or host that the deployment does not permit. With no agent override, the run inherits the ceiling. Repository files cannot request additional egress.

The bundle catalogue expands familiar names into the hostnames they need. The catalogue holds `npm`, `deno`, `pypi`, `cargo`, `debian`, `golang`, `github-releases`, `rustup`, `node-dist`, `mise` and `playwright`, and every bundle is in the default ceiling. Extra hosts and wildcard subdomains can be allowed explicitly.

## Freeze a signed claim

At launch, the orchestrator freezes the expanded host list into the run’s network scope and signs a token containing the run ID, expiry and hosts. The runner supplies proxy settings to setup steps and the harness.

The proxy verifies the token itself. It does not fetch the agent’s current blueprint or consult the orchestrator on each request. Editing a policy therefore affects future runs, not tokens already issued.

> [!WARNING]
> **Expiry is not revocation**
>
> The egress token has no revocation list. Its default lifetime is 24 hours, configurable at deployment. Ending the run revokes its model, MCP and forge keys, but does not invalidate an already issued egress token.

## Check destinations

The proxy accepts HTTP forwarding and HTTPS CONNECT on ports 80 and 443. It compares hostnames against the signed allowlist and checks the TLS ClientHello’s server name for HTTPS tunnels. It does not decrypt application traffic or inspect individual URL paths.

DNS resolution is also checked before dialing. By default, private, loopback, link-local and other blocked addresses are refused, including metadata destinations. An allowlisted name does not automatically authorize access back into the platform’s network.

Allowing a hostname is a broad grant: the run can communicate with that host, not just download one approved package. Package registries and GitHub release hosts should be selected with that scope in mind.

## Prevent bypasses

The proxy can only enforce the requests that reach it. The sandbox network must prevent a run from dialing the internet directly.

| Backend             | Network enforcement                                                                                                                                                                                                                        |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Kubernetes          | Supplied NetworkPolicy permits platform endpoints, DNS and the egress proxy, without general direct internet access. The cluster must enforce these policies.                                                                              |
| Docker, confined    | Each run joins an internal Docker network with no route out. It reaches Ryph and the egress proxy only through the run gate, a small relay container. Needs Docker Desktop, or Docker Engine 28 or later on Linux. Podman isn't supported. |
| Docker, allowlisted | Ryph supplies proxy settings, but the container keeps a direct route. Setup steps follow the allowlist; a run's own code can go around it.                                                                                                 |

`ryph setup` offers confined wherever the engine supports it, and the Docker Compose deployments use it too.

`RYPH_EGRESS=open` explicitly disables the proxy-mode boundary. A hostname allowlist in configuration should never be read as proof of confinement without checking the backend’s route out.

> [!WARNING]
> **Web tools are a separate path**
>
> The platform’s web search and fetch tools reach the internet from the web service, not from the run, so the egress allowlist does not limit them. Fetch reads public HTTPS pages only and returns them as untrusted text. Agents get these tools by default; an agent’s tool policy can remove them, and `RYPH_WEB_TOOLS=off` disables them for the deployment.

## Follow the implementation

The policy and registry catalogue live in [egress.ts](https://github.com/ryph-hq/ryph/blob/main/packages/orchestrator/src/core/egress.ts). The [proxy implementation](https://github.com/ryph-hq/ryph/blob/main/images/egress-proxy/main.ts) handles token verification, host checks, DNS restrictions and forwarding. The [network manifests](https://github.com/ryph-hq/ryph/blob/main/deploy/helm/ryph/templates/networkpolicies.yaml) provide the Kubernetes backstop.
