Linux capabilities: the pieces of root
The handful that actually decide an escape.
Classic Unix had a binary: root (UID 0) could do everything, everyone else almost nothing. Linux capabilities shattered that all-or-nothing power into ~40 discrete privileges — bind a low port, load a kernel module, change file ownership, trace another process — each grantable independently. A container does not run with full root power even when it runs as UID 0; it gets a default subset, and the whole game of runtime hardening is dropping what it does not need.
# what a default container actually holds (a subset of full root)$ docker run --rm alpine sh -c 'apk add -q libcap; capsh --print' | grep CurrentCurrent: cap_chown,cap_dac_override,cap_fowner,cap_net_bind_service,cap_setuid,cap_setgid,cap_kill,...# ~14 by default — not the full ~40 root would have on the host
The dangerous handful
A few capabilities are escape-grade and should almost never be added. SYS_ADMIN is so broad — it gates mount and dozens of kernel operations — that it is nicknamed “the new root,” and mount alone is often enough to break out. SYS_PTRACE lets a process inspect and hijack others. SYS_MODULE loads kernel code, game over. NET_ADMIN reconfigures networking. DAC_READ_SEARCH bypasses file permission checks. If a manifest adds any of these “to be safe,” that is the thing to challenge.
# least privilege: drop everything, add back only what is needed$ docker run --rm --cap-drop ALL --cap-add NET_BIND_SERVICE nginx:1.27 \sh -c 'apk add -q libcap; capsh --print' | grep CurrentCurrent: cap_net_bind_service # exactly one capability remains