Summary
There is a number of proxy related problems with sbx, looks like the common theme is the internal proxy is mucking around with connections more then it should. Bug report from claude Fable...
When a sandboxed process connects to an allowed host:port that happens to be an HTTP proxy (e.g., apt-cacher-ng), the sbx transparent gateway does not deliver the connection to that destination. It parses the intercepted HTTP request, extracts the hostname from the Host header / absolute URI, and dials that hostname combined with the original destination's port — an address neither endpoint ever referenced. The connection then fails with and the client hangs with no error reaching it.
Policy in sbx is expressed as host/port rules. As a user, the expectation is: if the destination host:port is allowed by policy, the traffic is forwarded to that destination unmodified. The gateway is a policy firewall, not a traffic-rewriting middlebox — silently re-routing connections based on payload contents violates that contract and breaks any protocol where the application-layer host legitimately differs from the connection target (HTTP proxies being the canonical case).
Environment
- Docker Sandboxes (sbx) on macOS (Apple Silicon), sandboxes on the default nation explicitly allowed
- Sandbox: Ubuntu 24.04 container (custom template)
- In-sandbox proxy target: apt-cacher-ng on a LAN host (apt-cacher-ng:1234, name
Steps to reproduce
From inside any sandbox where apt-cacher-ng:1234 resolves and is policy-allowed:
# Control: plain request TO the destination — works (Host == destination)
curl -s --noproxy '*' --max-time 10 -o /dev/null -w "%{http_code} %{time_total}s\n" \
http://apt-cacher-ng:1234/
# → 406 0.01s (apt-cacher-ng answers; connection delivered correctly)
# Bug: proxy-form request THROUGH the same allowed destination (Host != destination)
curl -s -x http://apt-cacher-ng:1234 --max-time 10 -o /dev/null -w "%{http_code}
http://ports.ubuntu.com/ubuntu-ports/dists/noble/Release
# → 000 10.0s (timeout; no response, no error)
Real-world trigger: a standard apt proxy configuration (Acquire::http::Proxyetc/apt/apt.conf.d/01proxy) makes apt update hang indefinitely with Ign:retries on every http source.
Observed behavior
sbx policy log shows the gateway dialing the Host-header hostname on the original destination's port:
opencode-serve-zoracrew-ui network ports.ubuntu.com:1234 transparent 10
opencode-serve-zoracrew-ui network archive.ubuntu.com:1234 transparent
opencode-serve-zoracrew-ui network apt-cacher-ng:1234 transparent domain-allowed 105
The client connected to apt-cacher-ng:1234 (allowed) and sent GET http://ports.ubuntu.com/... HTTP/1.1. The gateway dialed ports.ubuntu.com:5003 — the hostname from the request combined
with the port from the connection. Nothing listens there. The original, allotacted.
Expected behavior
- The connection is policy-checked against its actual destination (apt-cacher-ng:1234 are forwarded to that destination unmodified. What the payload says in aHost header is the destination service's business — in this case a caching proxy whose entire function is to serve requests for other hosts.
- If the gateway insists on also vetting the application-layer domain (antiainst policy — but still deliver the connection to the original destination.
- At absolute minimum: if proxy-form requests (absolute-URI request line, Host ≠ destination) are unsupported, reject them explicitly (e.g., HTTP 400/403 with a policy-style explanation body, plus a distinct policy-log entry). The current behavior — stream and timing out — is indistinguishable from a network outage and isextremely costly to diagnose.
Impact
- Any in-sandbox use of an internal HTTP proxy/cache (apt-cacher-ng, devpi, corporate caches) silently breaks, even when the proxy's host:port is explicitly allowed by policy.
- The failure mode is a hang with entries attributed to hosts h misdirects diagnosis toward DNS, policy, and upstream connectivity.
Workaround
Address the cache mirror-style so Host = destination (apt-cacher-ng remap UR/ports.ubuntu.com/ubuntu-ports noble main — confirmed working through thegateway with caching intact.
sbx diagnose report
OS: darwin
Arch: arm64
DS Version: v0.32.0
| Check |
Status |
Message |
| CLI binary |
✓ |
found |
| Daemon |
✓ |
healthy |
| Daemon diagnostics |
✓ |
collected (175467 bytes) |
| Version match |
✓ |
v0.32.0 |
| Storage directories |
✓ |
all 1 paths present |
| Directory permissions |
✓ |
all writable |
| Socket |
✓ |
responsive |
| Authentication |
✓ |
authenticated |
Full JSON output
{
"version": "1.0",
"checks": [
{
"name": "CLI binary",
"status": "pass",
"message": "found",
"detail": "/opt/homebrew/Caskroom/sbx/0.32.0/bin/sbx",
"hint": ""
},
{
"name": "Daemon",
"status": "pass",
"message": "healthy",
"detail": "version v0.32.0",
"hint": ""
},
{
"name": "Daemon diagnostics",
"status": "pass",
"message": "collected (175467 bytes)",
"detail": "",
"hint": ""
},
{
"name": "Version match",
"status": "pass",
"message": "v0.32.0",
"detail": "",
"hint": ""
},
{
"name": "Storage directories",
"status": "pass",
"message": "all 1 paths present",
"detail": "",
"hint": ""
},
{
"name": "Directory permissions",
"status": "pass",
"message": "all writable",
"detail": "",
"hint": ""
},
{
"name": "Socket",
"status": "pass",
"message": "responsive",
"detail": "",
"hint": ""
},
{
"name": "Authentication",
"status": "pass",
"message": "authenticated",
"detail": "",
"hint": ""
}
],
"summary": {
"pass": 8,
"warn": 0,
"fail": 0,
"skip": 0
}
}
Summary
There is a number of proxy related problems with sbx, looks like the common theme is the internal proxy is mucking around with connections more then it should. Bug report from claude Fable...
When a sandboxed process connects to an allowed host:port that happens to be an HTTP proxy (e.g., apt-cacher-ng), the sbx transparent gateway does not deliver the connection to that destination. It parses the intercepted HTTP request, extracts the hostname from the Host header / absolute URI, and dials that hostname combined with the original destination's port — an address neither endpoint ever referenced. The connection then fails with and the client hangs with no error reaching it.
Policy in sbx is expressed as host/port rules. As a user, the expectation is: if the destination host:port is allowed by policy, the traffic is forwarded to that destination unmodified. The gateway is a policy firewall, not a traffic-rewriting middlebox — silently re-routing connections based on payload contents violates that contract and breaks any protocol where the application-layer host legitimately differs from the connection target (HTTP proxies being the canonical case).
Environment
Steps to reproduce
From inside any sandbox where apt-cacher-ng:1234 resolves and is policy-allowed:
Real-world trigger: a standard apt proxy configuration (Acquire::http::Proxyetc/apt/apt.conf.d/01proxy) makes apt update hang indefinitely with Ign:retries on every http source.
Observed behavior
sbx policy log shows the gateway dialing the Host-header hostname on the original destination's port:
opencode-serve-zoracrew-ui network ports.ubuntu.com:1234 transparent 10
opencode-serve-zoracrew-ui network archive.ubuntu.com:1234 transparent
opencode-serve-zoracrew-ui network apt-cacher-ng:1234 transparent domain-allowed 105
The client connected to apt-cacher-ng:1234 (allowed) and sent GET http://ports.ubuntu.com/... HTTP/1.1. The gateway dialed ports.ubuntu.com:5003 — the hostname from the request combined
with the port from the connection. Nothing listens there. The original, allotacted.
Expected behavior
Impact
Workaround
Address the cache mirror-style so Host = destination (apt-cacher-ng remap UR/ports.ubuntu.com/ubuntu-ports noble main — confirmed working through thegateway with caching intact.
sbx diagnose report
OS: darwin
Arch: arm64
DS Version: v0.32.0
Full JSON output
{ "version": "1.0", "checks": [ { "name": "CLI binary", "status": "pass", "message": "found", "detail": "/opt/homebrew/Caskroom/sbx/0.32.0/bin/sbx", "hint": "" }, { "name": "Daemon", "status": "pass", "message": "healthy", "detail": "version v0.32.0", "hint": "" }, { "name": "Daemon diagnostics", "status": "pass", "message": "collected (175467 bytes)", "detail": "", "hint": "" }, { "name": "Version match", "status": "pass", "message": "v0.32.0", "detail": "", "hint": "" }, { "name": "Storage directories", "status": "pass", "message": "all 1 paths present", "detail": "", "hint": "" }, { "name": "Directory permissions", "status": "pass", "message": "all writable", "detail": "", "hint": "" }, { "name": "Socket", "status": "pass", "message": "responsive", "detail": "", "hint": "" }, { "name": "Authentication", "status": "pass", "message": "authenticated", "detail": "", "hint": "" } ], "summary": { "pass": 8, "warn": 0, "fail": 0, "skip": 0 } }