cloudflare / cloudflare/sandbox-sdk

allowedHosts fails closed for approved hosts and setAllowedHosts does not enforce

Open
#844 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
1.1k
Forks
114
Avg merge
22h 42m
Merged PRs (30d)
14

Description

**Describe the bug**

On a production Workers Paid deployment using `@cloudflare/sandbox@0.12.4`, outbound host allowlisting does not behave as documented:

1. A class-level `allowedHosts` allowlist combined with `enableInternet = false` blocks both allowed and disallowed HTTPS destinations by timeout.
2. A runtime `setAllowedHosts()` call reports success when internet is enabled, but does not deny a destination outside the allowlist.

This prevents a fail-closed sandbox from reaching only explicitly approved hosts.

**To Reproduce**

Deploy a fresh RPC-transport Sandbox Worker with a `standard-2` container and export `ContainerProxy`:

```ts
import {
ContainerProxy,
Sandbox as CloudflareSandbox,
} from "@cloudflare/sandbox";

export { ContainerProxy };

export class Sandbox extends CloudflareSandbox {
enableInternet = false;
allowedHosts = ["github.com"];
}
```

From a newly created sandbox instance, run:

```sh
curl --max-time 15 -I https://github.com
curl --max-time 15 -I https://example.com
```

Observed: both commands time out. The allowed destination never reaches an outbound handler or the public destination.

A second test on a fresh instance with internet enabled:

```ts
const sandbox = getSandbox(env.Sandbox, freshId);
await sandbox.setAllowedHosts(["github.com"]);
```

Then run the same two curl commands. Observed: both destinations remain reachable, including `example.com`.

I also tested a class-level `outbound` handler and `outboundByHost`, always exporting `ContainerProxy`. With `enableInternet = false`, connection/DNS setup times out before the allowed request reaches the handler. With internet enabled, unlisted destinations remain reachable.

All tests used fresh sandbox IDs to avoid live-instance policy carryover.

**Expected behavior**

As documented:

- `enableInternet = false` should deny public internet by default.
- A host in `allowedHosts` should override that default and be reachable.
- A host outside the allowlist should be denied.
- `setAllowedHosts(["github.com"])` should produce the same deny-by-default behavior for the live instance.

Expected test result: `github.com` succeeds and `example.com` is denied.

**Environment**

- `@cloudflare/sandbox`: 0.12.4
- Container image: `cloudflare/sandbox:0.12.4` (matching release image)
- Wrangler: 4.114.0
- Transport: RPC
- Container instance type: `standard-2`
- Deployment: production `workers.dev` Worker on Workers Paid
- Tests performed July 24, 2026

**Additional context**

The outbound-traffic documentation states that `allowedHosts` overrides `enableInternet = false` and that exporting `ContainerProxy` enables interception. We need this boundary for an engineering-agent sandbox and cannot safely fall back to unrestricted internet access.

This differs from #791: that issue concerns customizing the response for a host that is successfully blocked. Here, an explicitly allowed host cannot egress in the fail-closed configuration, while runtime allowlisting does not block unlisted hosts in the internet-enabled configuration.

Contributor guide

Open the contributing guide

Research direction

Trace class-level allowedHosts and enableInternet handling through ContainerProxy, outbound, and outboundByHost, then compare it with setAllowedHosts on a fresh instance. Reproduce the two curl checks: github.com should succeed while example.com is denied, both for the class-level fail-closed setup and the runtime allowlist.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
backend, networking, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.