# Network egress

Sandboxes have no outbound network by default. Allow the hosts a build needs by name; every other name never resolves, so nothing else can leave.

An agent with open network access can install anything, send your code anywhere, and pass a test by calling a live service. Kestrel turns outbound traffic off. You open it one host at a time.

![Kestrel answers the sandbox's name lookups itself. A host on the allow list resolves and the request goes out. Any other name gets no address, so the request never starts.](/illos/dns.svg)

## Allow a host

List hosts in `kestrel.yaml` at the root of the repo. Wildcards match one level of subdomain.

```yaml kestrel.yaml {3-6}
sandbox:
  network:
    allow:
      - registry.npmjs.org
      - pypi.org
      - "*.githubusercontent.com"
```

The allow list applies to every run on the repo, and to sandboxes you make with the SDK for that repo.

## Presets

Most builds only need a package registry. Use a preset instead of listing hosts.

| Preset | Allows |
|---|---|
| `npm` | registry.npmjs.org, registry.yarnpkg.com |
| `python` | pypi.org, files.pythonhosted.org |
| `go` | proxy.golang.org, sum.golang.org |
| `github` | github.com, *.githubusercontent.com |

```yaml kestrel.yaml
sandbox:
  network:
    presets: [npm, github]
```

## What a blocked request looks like

A name that isn't on the list doesn't resolve, so the request fails at once with a DNS error rather than hanging until a timeout. The trace marks it, so you can see which host a build was reaching for.

```bash Terminal
$ curl https://example.com
curl: (6) Could not resolve host: example.com
kestrel: example.com is not on the allow list for acme/web-app
```

> [!WARNING]
> Allowing a host lets the agent send data to it, not only fetch from it. Keep the list to registries and mirrors you trust.
