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 blocked169.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=denywith 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.
networkrule enforcement is database-ready but partially wired: theworkspace_sandbox_rulesschema (migration073) 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¶
- Sandboxing: the full five-layer sandbox model and threat coverage.
- Architecture: Sandboxing: implementation details.
- Hardening Checklist: steps to tighten security for multi-tenant deployments.