# What Can Reach a Sandbox, and What Can It Reach?

> Inbound, only ports you host on the HTTPS proxy, the SSH endpoint and the public IPv6 address reach a sandbox, and ufw closes IPv6 except SSH. Outbound, it reaches the internet. Other sandboxes, private ranges and port 25 are blocked. Sandboxer has no egress allowlist; restrict outbound yourself with ufw inside the VM.

Source: https://sandboxer.com/guides/what-can-reach-a-sandbox-and-what-it-can-reach. Updated 2026-10-27.

**Short answer:** Inbound, only ports you host on the HTTPS proxy, the SSH endpoint and the public IPv6 address reach a sandbox, and ufw closes IPv6 except SSH. Outbound, it reaches the internet. Other sandboxes, private ranges and port 25 are blocked. Sandboxer has no egress allowlist; restrict outbound yourself with ufw inside the VM.

## At a glance

We checked every row below on two `small` sandboxes on 2026-10-27.

| Traffic | What happens | What we saw |
| - | - | - |
| Sandbox to the internet | Allowed, IPv4 through NAT, IPv6 direct | `curl` to pypi.org returned `200` on both |
| Sandbox to port 25 (SMTP) | Blocked | `nc` to smtp.gmail.com:25 timed out; port 587 connected |
| Sandbox to another of your sandboxes | Blocked | Timed out on its private IPv4 and its public IPv6, even after `ufw allow` |
| Sandbox to private ranges and link-local | Blocked | 10.x, 172.16.x, 192.168.x, 100.100.100.100 and 169.254.169.254 all failed |
| Sandbox to DNS | The node's DNS relay answers | `/etc/resolv.conf` points at `10.202.0.1` |
| Internet to a hosted port | Through the HTTPS proxy only | `sbx host` URL returned `200`; an unhosted port returned `404 Port not hosted` |
| Internet to the SSH endpoint | A public IPv4 `host:port` forwarded to port 22 | Connected; key auth required |
| Internet to the IPv6 address | Reaches the VM; ufw allows only port 22 | Port 22 open, other ports timed out until `sudo ufw allow` |
| Internet to any other IPv4 port | Nothing to connect to | Timed out |

**There is no egress allowlist, domain filter or outbound firewall setting in Sandboxer.** Outbound traffic is open by default. If you need to limit what an agent can call, do it inside the VM, as shown below.

## Inbound: three ways in

### Hosted ports, through the proxy

`sbx host` puts a port behind `https://<subdomain>-<port>.box.sandboxer.com`. It is private with a token by default, or public with `--public`. The proxy only forwards ports you hosted.

```bash
id=sb_zh0w0e4133    # your sandbox id from `sbx new`

sbx exec $id --detach "mkdir -p ~/site && cd ~/site && echo hello-from-8000 > index.html && python3 -m http.server 8000"
sbx exec $id --detach "mkdir -p ~/s2 && cd ~/s2 && echo not-hosted-9000 > index.html && python3 -m http.server 9000"
sbx host $id 8000 --public

curl -s -w ' %{http_code}\n' https://candid-rocky-basil-8000.box.sandboxer.com/
# hello-from-8000
#  200
curl -s -o /dev/null -w '%{http_code}\n' https://candid-rocky-basil-9000.box.sandboxer.com/
# 404    (the page says "Port 9000 is not hosted for this sandbox")
```

Both servers were listening. Only the hosted one was reachable. Hosted ports don't need a ufw rule: the VM's firewall already lets in IPv4, because on IPv4 only its own node can reach it.

```bash
sbx exec $id "sudo ufw status verbose"
```

```text
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), allow (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW IN    Anywhere                   # ssh
Anywhere                   ALLOW IN    Anywhere                   # sandboxer: IPv4 reaches this VM only via its node
22/tcp (v6)                ALLOW IN    Anywhere (v6)              # ssh
```

### The SSH endpoint

`sbx info` shows `sshEndpoint`, a public IPv4 `host:port` that is forwarded to the sandbox's port 22 while it runs. Ours was `62.238.91.250:22017`. From outside, the port answered and asked for a key:

```bash
ssh -o BatchMode=yes -p 22017 user@62.238.91.250 true
# user@62.238.91.250: Permission denied (publickey).
```

Other ports on that IPv4 address timed out. `sbx ssh` uses a tunnel over HTTPS instead, so it works even where outbound SSH is blocked. See [SSH](/docs/ssh).

### The public IPv6 address

Every sandbox has its own public IPv6 address:

```bash
sbx exec $id "ip -6 addr show scope global"
```

```text
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
    inet6 2a01:4f9:3120:1d84::5b00:12/128 scope global nodad
       valid_lft forever preferred_lft forever
```

The machine we wrote this on has no IPv6, so we ran the outside checks from a server elsewhere on the internet that does. Port 22 was open. A server on port 8001 timed out until we opened it in ufw, then answered, then timed out again after we removed the rule:

```bash
# inside the sandbox: listen on IPv6 too (http.server binds IPv4 only by default)
sbx exec $id --detach "mkdir -p ~/s6 && cd ~/s6 && echo hello-over-ipv6 > index.html && python3 -m http.server 8001 --bind ::"
sbx exec $id "sudo ufw allow 8001/tcp"

# from a computer with IPv6
curl -s -m 6 http://[2a01:4f9:3120:1d84::5b00:12]:8001/
# hello-over-ipv6

sbx exec $id "sudo ufw delete allow 8001/tcp"
curl -s -m 6 http://[2a01:4f9:3120:1d84::5b00:12]:8001/; echo $?
# 28   (timed out)
```

## Outbound: open by default

```bash
sbx exec $id "curl -s -4 https://api.ipify.org; echo; curl -s -6 https://api6.ipify.org; echo; curl -sI https://pypi.org | head -1"
```

```text
62.238.91.250
2a01:4f9:3120:1d84::5b00:12
HTTP/2 200
```

IPv4 leaves through the node's address. IPv6 leaves from the sandbox's own address. Bandwidth is shaped per VM, so one sandbox can't starve its neighbours.

### What outbound is blocked

```bash
sbx exec $id "nc -zv -w5 smtp.gmail.com 25; nc -zv -w5 smtp.gmail.com 587"
```

```text
nc: connect to smtp.gmail.com (64.233.162.109) port 25 (tcp) timed out: Operation now in progress
Connection to smtp.gmail.com (2a00:1450:4010:c0a::6c) 587 port [tcp/submission] succeeded!
```

Send mail through your provider's submission port instead. Port 587 connected in our test.

The host, internal networks and link-local addresses are blocked too. This loop tries a TCP connection to each one:

```bash
sbx exec $id 'for t in 10.202.0.73:22 10.202.0.1:22 192.168.1.1:80 172.16.0.1:80 100.100.100.100:53 169.254.169.254:80; do
  timeout 4 bash -c "</dev/tcp/${t%:*}/${t#*:}" 2>/dev/null && echo "$t open" || echo "$t blocked"; done'
```

```text
10.202.0.73:22 blocked
10.202.0.1:22 blocked
192.168.1.1:80 blocked
172.16.0.1:80 blocked
100.100.100.100:53 blocked
169.254.169.254:80 blocked
```

`10.202.0.73` is the sandbox's own gateway, so even the host it runs on is out of reach.

### Other sandboxes are blocked, even your own

We started a second sandbox and tried to reach the first one from it, on its private IPv4 and its public IPv6:

```bash
other=sb_iajhvzwtws
sbx exec $other "nc -zv -w4 10.202.0.74 8000"
# nc: connect to 10.202.0.74 port 8000 (tcp) timed out
sbx exec $other "nc -zv -w4 2a01:4f9:3120:1d84::5b00:12 22"
# nc: connect to 2a01:4f9:3120:1d84::5b00:12 port 22 (tcp) timed out
sbx exec $id "sudo ufw allow 8001/tcp"
sbx exec $other "curl -s -m 6 http://[2a01:4f9:3120:1d84::5b00:12]:8001/; echo \$?"
# 28
sbx exec $other "curl -s https://candid-rocky-basil-8000.box.sandboxer.com/"
# hello-from-8000
```

Both of our sandboxes ran on the same server. Opening the port in ufw didn't help, because the node drops the traffic before it reaches the VM. The hosted URL worked. To connect two sandboxes, host a port and put your own authentication on it, or use the private URL's token.

### DNS goes through the node's relay

```bash
sbx exec $id "grep nameserver /etc/resolv.conf; dig +short @1.1.1.1 example.com +time=3 +tries=1; dig +short +tcp @1.1.1.1 example.com"
```

```text
nameserver 10.202.0.1
;; communications error to 1.1.1.1#53: timed out
104.20.23.154
172.66.147.243
```

The resolver at `10.202.0.1` is the node's DNS relay, the one internal address a sandbox may reach. In our test, plain UDP queries to a public resolver over IPv4 timed out, while TCP and IPv6 queries to it answered. Keep the default resolver unless you have a reason not to.

## Restrict outbound yourself with ufw

ufw is already installed and active, so an allowlist is three steps: allow the hosts you need, allow the DNS relay, then deny everything else. ufw matches IP addresses, not names, so resolve the host first. This example allows only pypi.org:

```bash
sbx exec $id 'for ip in $(getent ahosts pypi.org | awk "{print \$1}" | sort -u); do
  sudo ufw allow out to $ip port 443 proto tcp comment pypi; done
sudo ufw allow out to 10.202.0.1 port 53 comment dns-relay
sudo ufw default deny outgoing'
```

```text
Rule added
…
Default outgoing policy changed to 'deny'
```

Then check it:

```bash
sbx exec $id 'curl -s -m 8 -o /dev/null -w "pypi %{http_code}\n" https://pypi.org/simple/requests/
curl -s -m 8 -o /dev/null https://example.com; echo "example.com exit $?"
curl -s -m 8 -o /dev/null https://api.github.com; echo "api.github.com exit $?"'
```

```text
pypi 200
example.com exit 28
api.github.com exit 28
```

Exit code 28 is curl's timeout.

pypi.org still worked, the other hosts timed out, and the public URL on port 8000 kept answering `200`, because replies to inbound connections are still allowed. `sbx exec` kept working too: it doesn't use the sandbox's network. Undo it with `sudo ufw default allow outgoing`.

Three limits to know:

- **Docker containers skip these rules.** With outbound denied in ufw, `docker run --rm alpine wget https://example.com` still succeeded, even after `sudo ufw default deny routed`. Docker puts its own rules first. Use its `DOCKER-USER` chain instead, as below.
- **The addresses change.** A CDN can move a host to new IPs. Re-run the allow loop when a host stops working.
- **Root can undo it.** The default `user` has passwordless sudo, so code that runs as `user` can turn the firewall off again. Run untrusted code as a separate user without sudo if that matters to you.

### Limit Docker containers too

```bash
sbx exec $id 'sudo iptables -I DOCKER-USER -i docker0 -j REJECT
for ip in $(getent ahostsv4 pypi.org | awk "{print \$1}" | sort -u); do
  sudo iptables -I DOCKER-USER -i docker0 -d $ip -p tcp --dport 443 -j RETURN; done
sudo iptables -I DOCKER-USER -i docker0 -d 10.202.0.1 -p udp --dport 53 -j RETURN
docker run --rm alpine wget -q -T 8 -O /dev/null https://example.com; echo "example.com exit $?"
docker run --rm alpine wget -q -T 8 -O /dev/null https://pypi.org/simple/; echo "pypi exit $?"'
```

```text
wget: can't connect to remote host (172.66.147.243): Connection refused
example.com exit 1
pypi exit 0
```

Rules inserted with `-I` go to the top, which is why the `REJECT` comes first in the script: it ends up last. `sudo iptables -F DOCKER-USER` removes them.

## FAQ

### Does Sandboxer have an egress allowlist or domain firewall?

No. Outbound traffic is open by default, except SMTP port 25, other sandboxes, the host and internal networks. To allow only certain hosts, set ufw's outgoing policy to deny inside the VM and allow the addresses you need.

### Do I need a ufw rule for a hosted port?

No. `sbx host` works without one, because the VM's firewall already accepts IPv4 from its node, and the proxy only forwards ports you hosted. You need `sudo ufw allow <port>` only to serve a port directly on the IPv6 address.

### Can two of my sandboxes talk to each other?

Not directly. In our test, traffic between two sandboxes was blocked on both private IPv4 and public IPv6, even with the port open in ufw. Connect them through a hosted URL and add your own authentication.

### Can code in a sandbox reach the host or a cloud metadata service?

No. Connections to the gateway, RFC 1918 ranges, 100.100.100.100 and 169.254.169.254 all failed in our test. The only internal address a sandbox can reach is the node's DNS relay. The agent inside the VM talks to the host over vsock, not the network.

### Why can't I query 1.1.1.1 over UDP?

In our test, UDP DNS queries to a public resolver over IPv4 timed out, while TCP and IPv6 queries answered. Use the default resolver in `/etc/resolv.conf`, or query over TCP.

## Related

- [Security](/docs/security)
- [Hosting](/docs/hosting)
- [SSH and file transfer](/docs/ssh)
- [Give a sandbox port an HTTPS URL](/guides/give-a-sandbox-port-an-https-url)
