On Runtime, a proxy on the host holds the allow-list. The proxy runs outside
the microVM, so code running as root inside the sandbox cannot widen the list.
Programs that honor HTTP_PROXY and programs that open raw sockets meet the
same rule. A change takes effect immediately, including for connections that
are already open. The narrowed sandbox is still a full Firecracker microVM. It
costs $0.03125 an hour at 2 vCPU and 4 GiB while it waits
(pricing).
Allow a list at create
TypeScriptimport { 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 listPythonfrom withruntime import Sandboxwith 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 listTerminalruntime sandboxes create --allow pypi.org --allow '*.pythonhosted.org' --allow github.comChange the list later
sbx.network.set(...) replaces the rules as a whole. Send the complete list
each time:
TypeScriptimport { 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 refusedconsole.log(await sbx.network.get());Pythonfrom withruntime import Sandboxwith 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())Terminalruntime sandboxes network <id> --allow registry.npmjs.orgruntime sandboxes network <id> # show the current rulesMCP agents change rules with runtime_sandboxes_network, action 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. On the trial,
that is ports 80 and 443. On a paid sandbox, it is any port once the account
has made a purchase. deny entries still win over allow
(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. Asetreplaces the rules. A call that names only the new host drops the old ones. Read the current list withsbx.network.get(), and send every entry you still need. - Forgetting a CDN. Registries often serve files from a second domain. That
is why PyPI needs
*.pythonhosted.orgas well aspypi.org. - Cloning over SSH on a narrowed paid sandbox.
github.com:22is not a web port. Add it withconnect, or clone over HTTPS. - Expecting the list to open private addresses. Private and internal addresses are refused whatever the rules say. 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 the key as a secret for that host instead. The sandbox then never holds it.
Related
- The network: every rule.
- Egress control, the general idea.
- Turn off sandbox internet for no destinations at all.
- Coding agent sandbox.
Facts on this page were checked on 26 October 2026.