Summary
Two related defaults make the server itself the soft spot, even though the sandbox boundary is solid.
Unauthenticated by default, bound to all interfaces. api_auth_enabled defaults to false (tako_vm/config.py:268) and server_host defaults to 0.0.0.0 (tako_vm/config.py:255). Auth middleware only engages when enabled (tako_vm/server/limits.py:148). Out of the box this is a network-reachable, unauthenticated code-execution service.
Server holds host-root-equivalent Docker access. docker/Dockerfile.server mounts /var/run/docker.sock. In compose, the socket-proxy is configured with CONTAINERS=1, IMAGES=1, VOLUMES=1, POST=1 (docker-compose.yaml), which permits POST /containers/create with HostConfig.Privileged=true + a host bind-mount, then /start — a host-root escape. gVisor protects the host from untrusted code, but not from the server, which transitively holds host root.
These are RCE/SSRF-gated rather than a one-step sandbox escape: the request schema is locked down (ExecuteRequest uses extra: "forbid" and exposes no image/mount/privileged fields, app.py), and argv is validated (security.py), so a normal caller can't inject container parameters. The realistic path is a separate server bug reaching the socket. Still, the default posture maximizes the blast radius of any such bug.
Proposed changes
- Default
api_auth_enabled to true (or refuse to start unauthenticated on a non-loopback host without an explicit override).
- Tighten the socket-proxy permissions (drop
POST/VOLUMES where possible), or move to a policy-enforcing executor service that only exposes the create-sandbox operation instead of the raw Docker API.
- Document the server as a trust boundary distinct from the sandbox, with a hardened reference deployment.
Pointers
tako_vm/config.py:255, 268 — server_host, api_auth_enabled
tako_vm/server/limits.py:148 — auth middleware gating
docker/Dockerfile.server, docker-compose.yaml — socket / proxy
docs/deployment/security.md — existing notes on the proxy boundary
Summary
Two related defaults make the server itself the soft spot, even though the sandbox boundary is solid.
Unauthenticated by default, bound to all interfaces.
api_auth_enableddefaults tofalse(tako_vm/config.py:268) andserver_hostdefaults to0.0.0.0(tako_vm/config.py:255). Auth middleware only engages when enabled (tako_vm/server/limits.py:148). Out of the box this is a network-reachable, unauthenticated code-execution service.Server holds host-root-equivalent Docker access.
docker/Dockerfile.servermounts/var/run/docker.sock. In compose, the socket-proxy is configured withCONTAINERS=1,IMAGES=1,VOLUMES=1,POST=1(docker-compose.yaml), which permitsPOST /containers/createwithHostConfig.Privileged=true+ a host bind-mount, then/start— a host-root escape. gVisor protects the host from untrusted code, but not from the server, which transitively holds host root.These are RCE/SSRF-gated rather than a one-step sandbox escape: the request schema is locked down (
ExecuteRequestusesextra: "forbid"and exposes no image/mount/privileged fields,app.py), and argv is validated (security.py), so a normal caller can't inject container parameters. The realistic path is a separate server bug reaching the socket. Still, the default posture maximizes the blast radius of any such bug.Proposed changes
api_auth_enabledto true (or refuse to start unauthenticated on a non-loopback host without an explicit override).POST/VOLUMESwhere possible), or move to a policy-enforcing executor service that only exposes the create-sandbox operation instead of the raw Docker API.Pointers
tako_vm/config.py:255, 268—server_host,api_auth_enabledtako_vm/server/limits.py:148— auth middleware gatingdocker/Dockerfile.server,docker-compose.yaml— socket / proxydocs/deployment/security.md— existing notes on the proxy boundary