Skip to main content
RunBook Academy

← All break/fix scenarios in Docker & Containers

advancedSecurity~20 min

Break/Fix 9: Container escape via Docker socket mount

Reported symptoms

  • A monitoring sidecar (e.g. `telegraf`, `cAdvisor`, `node-exporter` companion) is mounted with `/var/run/docker.sock`
  • The sidecar has more privileges than its purpose requires
  • No alternative pattern is in use (e.g. socket-proxy)

Evidence

  • · `docker inspect my-sidecar --format "{{json .Mounts}}"` shows the docker.sock mount
  • · The image runs as root
  • · No read-only / no-new-privileges hardening
Diagnosis and resolutionclick to reveal

Root cause

Mounting the Docker socket inside a container gives the container full access to the Docker API, which can be used to launch a privileged container with the host root filesystem bind-mounted in.

Remediation

Replace the socket mount with a restricted alternative: (1) a Docker socket-proxy that exposes only the needed endpoints (e.g. tecnativa/docker-socket-proxy with explicit ROUTE allowlist); (2) cAdvisor running as a host process or with restricted scopes; (3) node-exporter + textfile collector without Docker socket.

Verification

Re-deploy with the alternative. Verify the sidecar still has the data it needs (container metrics, image lists, etc.) and that `docker run --privileged` is no longer reachable from inside the sidecar.

Prevention

Default-deny policy on socket mounts. Any sidecar that needs the socket must justify the need and use a proxy. Add a pre-commit check that fails the build on `docker.sock` mounts without a documented exception.

Why this matters

The Docker socket is the daemon’s control plane. Anyone who can write to it can launch any container with any configuration.

The attack, run from inside a socket-mounted sidecar:

docker run --rm --privileged -v /:/host alpine \
  chroot /host cat /etc/shadow

One command. No kernel exploit. The Docker API permitted it by design.

Fix

Replace with a socket-proxy:

services:
  socket-proxy:
    image: tecnativa/docker-socket-proxy
    environment:
      - CONTAINERS=1
      - IMAGES=1
      - NETWORKS=0
      - VOLUMES=0
      - POST=0
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks: [obs]

  monitoring:
    image: telegraf:1.30
    networks: [obs]
    depends_on:
      - socket-proxy
    environment:
      - DOCKER_HOST=tcp://socket-proxy:2375

The proxy exposes only GET /containers and GET /images — read access, no write. The attack above cannot succeed because POST is disabled.