# How to restrict a sandbox to an allow-list of hosts Create the sandbox with `network: { internet: true, allow: ["pypi.org", "*.pythonhosted.org"] }`; every other destination is refused. **On Runtime the allow-list is held by a proxy on the host, outside the microVM, so code running as root inside the sandbox cannot widen it.** Programs that honour `HTTP_PROXY` and programs that open raw sockets meet the same rule. A change applies at once, to connections already open too. The narrowed sandbox is still a full Firecracker microVM, from $0.03125 an hour at 2 vCPU and 4 GiB while it waits ([pricing](/docs/pricing)). ## Allow a list at create ```ts check import { Sandbox } from "withruntime"; await using sbx = await Sandbox.create({ network: { internet: true, allow: ["pypi.org", "*.pythonhosted.org", "github.com"] }, }); await sbx.exec("pip install requests", { check: true, timeoutMs: 120_000 }); const other = await sbx.exec("curl -sS --max-time 5 https://example.com", { timeoutMs: 30_000 }); console.log(other.exitCode !== 0); // true: example.com is not on the list ``` ```python check from withruntime import Sandbox with Sandbox.create(network={"internet": True, "allow": ["pypi.org", "*.pythonhosted.org", "github.com"]}) as sbx: sbx.exec("pip install requests", check=True, timeout_ms=120_000) other = sbx.exec("curl -sS --max-time 5 https://example.com", timeout_ms=30_000) print(other.exit_code != 0) # True: example.com is not on the list ``` ```bash no-run runtime sandbox create --allow pypi.org --allow '*.pythonhosted.org' --allow github.com ``` ## Change the list later `sbx.network.set(...)` replaces the rules as a whole, so send the complete list each time: ```ts check import { Sandbox } from "withruntime"; await using sbx = await Sandbox.create(); await sbx.network.set({ internet: true, allow: ["registry.npmjs.org"] }); await sbx.exec("npm install left-pad", { check: true, timeoutMs: 120_000 }); await sbx.network.set({ internet: true, allow: ["api.openai.com"] }); // npm is now refused console.log(await sbx.network.get()); ``` ```python check from withruntime import Sandbox with Sandbox.create() as sbx: sbx.network.set(internet=True, allow=["registry.npmjs.org"]) sbx.exec("npm install left-pad", check=True, timeout_ms=120_000) sbx.network.set(internet=True, allow=["api.openai.com"]) # npm is now refused print(sbx.network.get()) ``` ```bash no-run runtime sandbox network --allow registry.npmjs.org runtime sandbox network # show the current rules ``` MCP agents change rules with `runtime_sandbox_network_set`. ## What an entry can be | Entry | Matches | | ---------------------------------- | ---------------------------------------------------------- | | `pypi.org` | That name exactly | | `*.pythonhosted.org` | Every name under the domain | | `203.0.113.7` | One address | | `198.51.100.0/24` | A CIDR range | | `connect: ["db.example.com:5432"]` | A `host:port` pair beyond the web ports, on a paid sandbox | An allowed host is reachable on every port the sandbox may use: 80 and 443 on the trial, any port on a paid sandbox once the account has made a purchase. `deny` entries still win over `allow` ([block a domain](/how-to/block-a-domain)). ## Allow-lists for common jobs | Job | Entries | | --------------------------- | ----------------------------------------- | | Python packages | `pypi.org`, `*.pythonhosted.org` | | npm packages | `registry.npmjs.org` | | GitHub, clone and raw files | `github.com`, `*.githubusercontent.com` | | One model API | That API's host, such as `api.openai.com` | ## Mistakes and how Runtime handles them - **Adding one host with `set`.** A `set` replaces the rules, so a call that names only the new host drops the old ones. Read the current list with `sbx.network.get()` and send every entry you still need. - **Forgetting a CDN.** Registries often serve files from a second domain, which is why PyPI needs `*.pythonhosted.org` as well as `pypi.org`. - **Clone over SSH on a narrowed paid sandbox.** `github.com:22` is not a web port; add it with `connect`, or clone over HTTPS. - **Expecting the list to open private addresses.** Private and internal addresses are refused whatever the rules say, and mail ports 25, 465 and 587 stay closed unless support enables mail for the account. - **A key in the sandbox for the one allowed API.** Store it as a [secret](/how-to/use-secrets-in-a-sandbox) for that host instead, and the sandbox never holds it. ## Related - [The network](/docs/sandbox-environment#the-network): every rule. - [Egress control](/glossary/egress-control), the general idea. - [Turn off sandbox internet](/how-to/turn-off-sandbox-internet) for no destinations at all. - [Coding agent sandbox](/use-cases/coding-agent-sandbox). Facts on this page were checked on 25 September 2026.