Skip to content

Limit Sandbox egress to an HTTPS allow-list - #82

Merged
jacobprall merged 1 commit into
mainfrom
sandbox-egress-allow-list
Nov 1, 2026
Merged

jacobprall merged 1 commit into
mainfrom
sandbox-egress-allow-list

Conversation

@jacobprall

Copy link
Copy Markdown
Collaborator

Summary

Every Sandbox ran with allow-all egress, so dependency install scripts and prompt-injected agents could send source code or the model key anywhere. Render Sandboxes now support an allow-list network policy. This PR creates every Sandbox with one.

Sandbox Allowed hosts (HTTPS only)
Task Sandbox github.com, every registered agent harness's model API, and the repository's egress
Snapshot builder github.com, deb.debian.org, and the repository's egress

Breaking change for existing deployments

This change is on by default. A deployed fork whose repositories don't list egress hosts will fail its next snapshot build at install. The error names the allowed hosts and says where to add more. To migrate, add each repository's registries to factory.config.ts:

"acme/web": {
  baseBranch: "main",
  install: "npm ci",
  verify: ["npm test"],
  egress: ["registry.npmjs.org"],
},

To keep the old behavior for one repository, set egress: "allow-all". docs/configuration.md lists common hosts for npm, Go, and PyPI.

Changes

  • Config: RepoConfig gets egress?: string[] | "allow-all". Hosts are validated when app/config loads, so a typo stops both services at startup. The example target gets egress: ["registry.npmjs.org"].
  • Harnesses declare egress, the same way they declare credential. pi() derives the host from model.baseUrl and takes an explicit egress for a model served elsewhere, such as through a proxy. A task Sandbox allows the union of every registered agent's hosts, because it opens before the task picks agents and Triage runs two agents in one Sandbox.
  • app/sandbox/egress.ts builds both policies and removes duplicate domains, which the API rejects. Install failures under an allow-list now name the allowed hosts, because a blocked host fails as a connection reset that looks like a network flake.
  • install-tools.sh switches the image's Debian sources to HTTPS. The base image has no ripgrep, and apt's plain-HTTP sources are blocked under an allow-list.
  • verify.ts: removes the stale ALLOW_ALL_EGRESS cast, since SDK 1.3.0 types the allow-list policy.
  • Docs: adds a Sandbox egress section to docs/configuration.md, updates the trust boundaries, adds invariant 11, and rewrites the residual risks in docs/architecture.md. Also updates the setup runbook, the extension runbook, AGENTS.md, and the README.

Design notes

  • The policy is fixed when a Sandbox is created. The API has no update endpoint, and a Sandbox restored from a snapshot uses the policy passed at creation. So task Sandboxes keep github.com for their whole lifetime, even though they only need it for the fetch.
  • One repository list covers both install and runtime. Task Sandboxes reinstall when lockfiles change, and verify commands can download.
  • This narrows exfiltration but doesn't close it. github.com and the model API accept data sent under an attacker's own credentials, and DNS resolution isn't restricted. The residual-risks section in docs/architecture.md says so.

Verification

  • npm run check passes: Biome, tsc, and 253 Vitest tests. New tests cover the builder and task policies, merging and deduplicating repository hosts, the allow-all escape hatch, the install-failure hint, config host validation, and harness egress.
  • shellcheck sandbox/*.sh sandbox/build/*.sh passes.
  • Live probes in a Render workspace, using throwaway Sandboxes that were each terminated:
    • Under allow-list, listed hosts are reachable, including git ls-remote over HTTPS. Every other host gets a connection reset.
    • A Sandbox restored from an existing factory snapshot uses the policy passed at creation.
    • The modified install-tools.sh installs ripgrep and exits 0 with only github.com and deb.debian.org allowed.
    • For render-examples/render-factory-example-target, npm ci, npm run build, and npm test pass with only github.com and registry.npmjs.org.
    • For a Go repository, go mod download plus a toolchain download pass with go.dev, dl.google.com, proxy.golang.org, and sum.golang.org, and fail with only github.com.
  • Not run: a full buildSnapshot and an agent run against a deployed instance.

After merge

Existing deployments need to:

  1. Add egress hosts to each repository in factory.config.ts.
  2. Deploy both services.
  3. Refresh every repository snapshot (this PR changes sandbox/).
  4. Run one Triage smoke test.

Task Sandboxes reach github.com, the agents' model APIs, and the
repository's configured egress hosts. The snapshot builder reaches
github.com, deb.debian.org, and the repository's hosts; install-tools.sh
switches the image's Debian sources to HTTPS so apt works under the list.
A repository can opt out with egress: "allow-all".

Co-authored-by: Cursor <cursoragent@cursor.com>
@jacobprall
jacobprall merged commit 93d0a03 into main Nov 1, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant