Egress
Sandboxes are open by default. A sandbox with no egress rules can reach external hosts. For sandboxes that run untrusted or AI-generated code, set an allowlist before the sandbox runs any user-supplied input. CreateOS enforces the policy outside the sandbox.
Egress rules control which external hosts a sandbox can reach. There is one default and it is worth stating plainly: an empty rule list means open egress: all outbound traffic is allowed. A non-empty rule list means deny-by-default: only the listed destinations pass; everything else is dropped in-kernel on the host, outside the VM, so code inside the sandbox cannot rewrite or route around the policy. Inbound is closed regardless (see ingress_enabled). Pass egress at create time so the allowlist is in force before the first command runs; the same rules can be changed live afterwards.
A deny-by-default Python job, for example, needs exactly two rules: ["pypi.org:443", "*.pythonhosted.org:443"]. Rules cover any port and any protocol to the listed host, IP or CIDR; host:port narrows to one port. Both IPv4 addresses and hostnames (with *. wildcards) are accepted, so there is no separate "domain allowlist" mode with its own restrictions.
Rules apply live with no sandbox restart required.
Get your API key from https://createos.sh/app/profile. Pass it as X-Api-Key: <token> on every request.
Base URL: https://api.sb.createos.sh
At a glance
- Base URL:
https://api.sb.createos.sh - Auth:
X-Api-Key: <token>header. Get a token - Response envelope: JSend,
{"status": "...", "data": ...}
Rule formats
Each rule is a string in one of these forms:
| Format | Example | Effect |
|---|---|---|
host | pypi.org | Allow HTTP and HTTPS to that hostname on TCP ports 80 and 443. |
host:port | github.com:443 | Restrict a hostname rule to TCP 80 or 443. Use an IP/CIDR rule for other ports. |
*.host | *.pythonhosted.org | Wildcard subdomain match. |
ip | 1.1.1.1 | Allow all ports to that IP. |
ip:port | 1.1.1.1:53 | Allow only that port. |
cidr | 10.0.0.0/8 | Allow all ports to that CIDR block. |
cidr:port | 10.0.0.0/8:8080 | Allow only that port in the block. |
* | * | Allow all destinations (same as empty list). |
Empty list / null / ["*"] allows outbound traffic without a destination allowlist.
There is no denylist token. To block one destination you must list all destinations you do want.
GET /v1/sandboxes/{id}/egress
Read the current egress allowlist for a sandbox.
Auth required: Yes
Path parameters
| Parameter | Description |
|---|---|
id | Sandbox id. |
Example
curl https://api.sb.createos.sh/v1/sandboxes/sb-01K.../egress \
-H "X-Api-Key: $CREATEOS_API_KEY"Success response 200
{
"status": "success",
"data": {
"id": "sb-01K…",
"egress": ["pypi.org", "*.pythonhosted.org", "github.com:443"]
}
}Notable errors: 404 sandbox not found or not owned by caller.
PUT /v1/sandboxes/{id}/egress
Replace the egress allowlist without restarting the sandbox. Allow time for hostname policy updates to propagate before running a workload that depends on the new rules.
Auth required: Yes
Path parameters
| Parameter | Description |
|---|---|
id | Sandbox id. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
egress | array of strings | No | Full replacement allowlist. null, missing, [], or ["*"] all mean allow-all. |
Example: restrict to PyPI and GitHub
curl -X PUT https://api.sb.createos.sh/v1/sandboxes/sb-01K.../egress \
-H "X-Api-Key: $CREATEOS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"egress": [
"pypi.org",
"*.pythonhosted.org",
"github.com:443",
"1.1.1.1:53"
]
}'Success response 200
{
"status": "success",
"data": {
"id": "sb-01K…",
"egress": ["pypi.org", "*.pythonhosted.org", "github.com:443", "1.1.1.1:53"]
}
}Example: restore allow-all
curl -X PUT https://api.sb.createos.sh/v1/sandboxes/sb-01K.../egress \
-H "X-Api-Key: $CREATEOS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"egress": []}'Notable errors: 404 sandbox not found.
Setting egress at sandbox creation
You can also supply the initial egress list when creating a sandbox. Pass egress in the POST /v1/sandboxes body:
{
"shape": "s-1vcpu-256mb",
"egress": ["pypi.org", "github.com:443"]
}See /Sandbox/REST-API/Sandboxes for the full create request shape.
Related
- Limits & defaults: ingress and egress defaults alongside every other limit.
- Networks for private sandbox-to-sandbox traffic, which egress rules do not govern.
- Product explanation with the threat model: Egress you can prove. Worked example: egress-locked managed agent worker.