Skip to content

Egress Firewall

What it is

The egress firewall is a two-layer network policy that controls outbound traffic from sandboxed AI sessions and project build processes. On Linux servers, it combines an nftables rule that blocks raw egress from sandbox UIDs at the kernel level, with a Squid HTTPS proxy (127.0.0.1:3128) that mediates all allowed outbound HTTP(S) traffic against a hostname allowlist. Together they ensure that AI-driven npm install, pip install, and preview builds can only reach destinations you have explicitly permitted.

Why it exists

Sandboxed project processes need outbound network access (package registries, CDNs, AI provider APIs), but an unrestricted internet connection creates real risk: a compromised or misbehaving AI agent could exfiltrate source code, call back to an attacker, or probe cloud metadata endpoints. The egress firewall applies the principle of least privilege at the network layer: deny everything by default, allow only known-good destinations.

The two layers

Layer 1: nftables UID firewall

server-setup.sh provisions a pool of sandbox UIDs (range 10001-65000, named doable-dev-1 through doable-dev-1000). Each AI session worker and Vite preview process runs as one of these unprivileged UIDs. An nftables drop-in rule at /etc/nftables.d/doable-dev.nft blocks all egress from this UID range except loopback:

table inet doable_dev {
  chain output {
    type filter hook output priority 0; policy accept;
    oif "lo" accept
    meta skuid 10001-65000 drop
  }
}

This means a sandbox process cannot open a raw TCP or UDP connection to any public IP. The only route out is through the loopback interface, where Squid is listening.

Layer 2: Squid HTTP(S) proxy

Squid listens on 127.0.0.1:3128. Build tooling (npm, pip, yarn, pnpm) is configured via BUILD_HTTP_PROXY to route requests through it. Squid enforces a hostname allowlist at /etc/squid/conf.d/doable-allowlist.conf. Traffic to destinations not on the list is rejected with a 403 Forbidden.

Default allowlists by profile

Doable ships four sandbox profiles, each with its own network allowlist seeded in migration 080. The defaults are:

Profile Allowed destinations
install registry.npmjs.org, registry.yarnpkg.com, pypi.org, files.pythonhosted.org
build registry.npmjs.org, *.sentry.io
vite-preview registry.npmjs.org, registry.yarnpkg.com, esm.sh, unpkg.com, cdn.jsdelivr.net, fonts.googleapis.com, fonts.gstatic.com
ai-bash registry.npmjs.org, api.anthropic.com, api.openai.com, ghcr.io, github.com

Additionally, three global hard-floor denies apply to every profile and cannot be overridden by workspace rules:

  • ipinfo.io / *.ipinfo.io: IP geolocation recon blocked
  • 169.254.169.254: cloud instance metadata endpoint blocked (AWS/GCP)

Workspace rules

Workspace owners and admins can extend or tighten the allowlist on a per-workspace basis without touching server config. Rules are managed through:

  • Workspace Settings, AI, Sandbox rules in the UI
  • The REST API: GET/POST/PATCH/DELETE /workspaces/:id/sandbox/rules

Each rule has a rule_type (tool or network), a pattern, an action (allow or deny), and a numeric priority (lower number = higher precedence, first match wins).

The workspace also has a network_default_action setting (allow or deny). The default is allow so existing workspaces keep current behavior. To run deny-by-default, flip it to deny and add explicit allow rules for the patterns your projects need.

Hard-floor rules

Global is_floor=true rules (managed in sandbox_system_rules) always take precedence. A workspace rule cannot un-block ipinfo.io or the cloud metadata endpoint.

Wildcard support

Pattern matching supports * as a subdomain wildcard. For example, *.example.com allows all subdomains of example.com. This applies to both workspace rules and the profile-level seed data (e.g. *.sentry.io in the build profile).

Limitations

  • IP-based exfiltration: nftables blocks direct TCP/UDP but a host on the allowlist could act as a relay. For high-sensitivity workspaces, consider disabling outbound network entirely by setting network_default_action=deny with no allow rules.
  • TLS inspection: Squid mediates CONNECT tunnels but does not perform TLS inspection by default. Hostname matching is done via the CONNECT destination, not payload inspection.
  • network rule enforcement is database-ready but partially wired: the workspace_sandbox_rules schema (migration 073) stores network rules, but enforcement at the dovault egress jail layer is still in progress. The nftables + Squid system enforces profile-level allowlists today; per-workspace network rule enforcement in the proxy is the next step.

Cross-platform note

The nftables + Squid egress firewall is Linux-only. The sandbox backends on other platforms rely on the proxy layer alone or OS-native controls:

Platform Sandbox backend Egress enforcement
Linux bubblewrap (bwrap) + systemd nftables UID firewall + Squid proxy
macOS sandbox-exec (Seatbelt) Squid proxy (if configured)
Windows psroot (Job Object) Squid proxy (if configured)

For production deployments, a Linux host is strongly recommended to get both layers of network enforcement.

See also