# Limits

> What Egress CI covers in a CI job and what it does not: root, steps before the action, Docker, HTTPS content, IPv6 and runner types.

Egress CI makes a job's outbound traffic visible and limits it to a list. It raises the cost of exfiltration by a compromised dependency, build script or action, and shows the attempt in the summary. It is not a sandbox: read what it does not cover before relying on it.

## Coverage

| Traffic | Covered | How |
|---|---|---|
| Tools that honour `HTTPS_PROXY`/`HTTP_PROXY` | Yes | The proxy: name and SNI checked |
| Tools that ignore the proxy variables, the runner itself | With the lock | The transparent proxy: named by SNI or Host, name checked against the address |
| DNS | With the lock | The forwarder: logged, `NXDOMAIN` for names outside the policy in enforce |
| UDP, ICMP, IPv6 | With the lock | Only to addresses of allowed names (IPv4); the rest refused in enforce |
| The job's containers and `docker build` steps | With Docker tracking | Same as the job, per container |
| Image pulls through the job's socket | With Docker tracking | Registry checked |
| Steps before the action | No | |

## Known limits

- **Root can undo it.** The job has the root the action uses: on GitHub-hosted runners every job has `sudo`, and on self-hosted runners the docker group is equivalent to root. A step that sets out to remove the lock can.
- **Only the steps after the action.** Put it right after `actions/checkout`.
- **HTTPS content is not seen** unless the host is under [`inspect`](https://developers.openwaf.dev/egress/ci/inspect-and-dlp/#inspect), and inspection needs the tool to trust the run's CA. A secret sent over HTTPS to an allowed host is not detected.
- **Allowed hosts can carry data.** A package registry or an object store you allow can receive an upload. Allow exact names, and keep write credentials out of jobs that do not need them.
- **Docker without `DOCKER_HOST`.** A tool that opens `/var/run/docker.sock` itself is not attributed; with `lock-all` its containers' traffic outside the policy is still refused. Containers with `--network host` are outside the lock unless they run as the job's user.
- **The Docker daemon's own connections** (pushes, layer downloads of a pull once the registry is allowed) are not proxied.
- **Docker's address pool** (`172.16.0.0/12`) is left to the runner's own rules, and is in `NO_PROXY`.
- **IPv4 only** for naming TCP connections; the job's IPv6 is refused in enforce.
- **Without root** (a self-hosted runner with neither passwordless `sudo` nor Docker), only `HTTPS_PROXY` is covered. `lock: "on"` makes that an error.
- **Linux only**, x64 and arm64. No macOS or Windows runners.
- **One job per runner user at a time** on a host.

## What it costs

The action starts the sidecar before the job's own steps and stops it in the post step; the log line `OpenWAF Egress CI: proxy …, started in … ms` and the summary give the times of each run. Connections through the proxies add one local hop. With Docker tracking, `docker build` runs in the job builder instead of the daemon's builder; on runners that start clean for each job its cache starts empty.

## Security model

- The sidecar runs as root and the job's steps as the runner user; the lock matches that user's sockets and the job's Docker networks only.
- The binaries are in the action's `dist/`, built reproducibly from its source (CI checks it); their SHA-256 are in `dist/SHA256SUMS` and checked before every run.
- Tokens are never put on a command line or in a log: the GitHub token reaches `curl` on standard input, the OIDC tokens stay in the post step's memory.
- The run's CA key never leaves the sidecar's memory.
- The summary and `report.json` hold names, ports, counts and detection ids, never bodies or the secrets found.

Report vulnerabilities to security@openwaf.dev, as described in the repository's [SECURITY.md](https://github.com/openwaf-dev/egress-action/blob/main/SECURITY.md).
