Sandbox Escape on Docker
How Sandbox Escape Manifests in Docker
Docker containers rely on Linux namespaces and cgroups to isolate processes from the host. A sandbox escape occurs when an attacker breaks out of these isolation mechanisms and gains execution privileges on the host or in other containers. In Docker‑specific contexts, the most common vectors are:
- Privileged mode – running a container with
--privilegedgives it access to all host devices and effectively disables many namespace restrictions. - Exposed Docker socket – mounting
/var/run/docker.sockinside a container allows the containerized process to issue Docker daemon commands, such asdocker runwith privileged flags, leading to a host escape. - Dangerous Linux capabilities – granting capabilities like
SYS_ADMIN,SYS_PTRACE, orCAP_SYS_MODULElets a container perform operations that can modify host kernel state or break out of namespaces. - Insecure volume mounts – bind‑mounting host directories such as
/,/etc, or/devcan give a container read/write access to critical host files. - Known runtime exploits – vulnerabilities like CVE‑2019‑5736 (runc) allow overwriting the host runc binary via a malicious container image, leading to host code execution.
For example, a Dockerfile that builds an image intended to run as root and then executes a container with --privileged -v /var/run/docker.sock:/var/run/docker.sock creates a direct path to escape:
# Dockerfile (bad practice)
FROM alpine:latest
USER root
CMD ["/bin/sh"]
# docker run command (bad practice)
docker run --rm -it \
--privileged \
-v /var/run/docker.sock:/var/run/docker.sock \
myimage
When the container starts, any process inside can talk to the Docker daemon via the socket and launch another container with privileged flags, effectively executing arbitrary code on the host.
Docker-Specific Detection
Detecting a potential sandbox escape involves examining the container’s runtime configuration for the risky patterns described above. Since middleBrick performs unauthenticated black‑box scans, it can identify exposed Docker APIs and infer risky container settings from the responses.
What middleBrick looks for:
- Responses from endpoints that expose the Docker Engine API (typically on
tcp://0.0.0.0:2375orunix:///var/run/docker.sock) without authentication. - HTTP headers or body indicators that suggest a container is running in privileged mode (e.g.,
X-Docker-Privileged: truein custom middleware, or diagnostic endpoints that leakHostConfig.Privileged). - Volume mount information leaked through debug endpoints that show bindings like
/var/run/docker.sockor host root directories. - Presence of dangerous capabilities in container metadata (if the API returns
HostConfig.CapAddcontainingSYS_ADMIN,SYS_PTRACE, etc.).
Example of a scan via the middleBrick CLI:
# Install the CLI (npm)
npm i -g middlebrick
# Scan an API that may expose Docker socket
middlebrick scan https://api.example.com/docker
The output includes a risk score (A–F) and a finding such as:
| Finding ID | Category | Severity | Description |
|---|---|---|---|
| DOCK-001 | Privilege Escalation | High | Docker socket exposed without authentication; container likely runs with privileged flag. |
| DOCK-002 | Container Misconfiguration | Medium | Volume mount includes host root directory (/). |
These findings give developers actionable guidance: secure the Docker daemon, remove privileged flags, and restrict volume mounts.
Docker-Specific Remediation
Remediation focuses on eliminating the risky configurations that enable escape. Use Docker’s native features to enforce least privilege.
1. Avoid privileged mode
Run containers without --privileged. If specific capabilities are needed, drop all others and add only the required ones.
# Good: drop all capabilities, then add only NET_BIND_SERVICE if needed
docker run --rm \
--cap-drop ALL \
--cap-add NET_BIND_SERVICE \
myimage
2. Secure the Docker socket
Never mount /var/run/docker.sock into a container unless absolutely necessary, and if you do, protect it with authentication (e.g., using a TLS‑protected socket or a proxy that enforces auth).
# Example of using a TCP socket with TLS (requires daemon configuration)
docker run --rm \
-e DOCKER_HOST=tcp://docker.example.com:2376 \
-e DOCKER_TLS_VERIFY=1 \
-e DOCKER_CERT_PATH=/certs \
myimage
3. Use user namespaces and non‑root users
Enable userns-remap on the daemon to map container root to an unprivileged host UID, and run processes as a non‑root user inside the container.
# Docker daemon config (/etc/docker/daemon.json)
{
"userns-remap": "default"
}
# Dockerfile
FROM alpine:latest
RUN addgroup -S app && adduser -S -G app app
USER app
CMD ["/app/start.sh"]
4. Limit dangerous capabilities
Explicitly drop capabilities that are not needed, especially SYS_ADMIN, SYS_PTRACE, and CAP_SYS_MODULE.
docker run --rm \
--cap-drop SYS_ADMIN,SYS_PTRACE,CAP_SYS_MODULE \
myimage
5. Restrict volume mounts
Bind‑mount only the specific directories the container needs, and mount them read‑only when possible.
docker run --rm \
-v /app/data:/data:ro \
-v /etc/myapp:/etc/myapp:ro \
myimage
After applying these changes, re‑run a middleBrick scan to verify that the risk score improves and the Docker‑specific findings disappear.