← Home ← Codex ← DEBT ← Engine
Browse by Category
+ added · updated 7d
← Back to glossary

Linux Capabilities

Linux Advanced
debt(d5/e3/b5/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5), because trivy, kube-bench, and docker-bench-security flag --privileged, missing capabilities.drop, and over-broad cap grants, but only if you run them as part of the pipeline.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3), because the quick_fix is essentially swapping in --cap-drop=ALL --cap-add=NET_BIND_SERVICE or running setcap on a binary — a small, pattern-based change per service rather than one line, but not architectural.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5), because capability decisions apply across cli, web, and queue workers, and every new binary/container image invites a recurring 'what caps does this need?' review that slows delivery.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7), because per the misconception, dropping setuid and running non-root feels sufficient, yet CAP_SYS_ADMIN is nearly full root and the Ambient/Permitted/Inheritable set distinction contradicts the intuitive model of privilege inheritance across execve.

About DEBT scoring →

Also Known As

posix capabilities kernel capabilities cap_*

TL;DR

Kernel mechanism that splits root's monolithic privilege into ~40 discrete capabilities so processes get only the specific powers they need.

Explanation

Traditional Unix has a binary privilege model: UID 0 (root) can do everything, everyone else is checked against DAC permissions. Linux capabilities, introduced in kernel 2.2 and refined ever since, break root's superpowers into fine-grained units so a program can be granted exactly the privileges it requires and nothing more. Common capabilities include CAP_NET_BIND_SERVICE (bind to ports below 1024), CAP_NET_ADMIN (configure interfaces, iptables, routing), CAP_SYS_ADMIN (a catch-all for mount, sethostname, and many container ops - often called 'the new root'), CAP_SYS_PTRACE (attach to arbitrary processes), CAP_CHOWN (change file ownership), CAP_DAC_OVERRIDE (bypass file permission checks), CAP_SETUID / CAP_SETGID (change identity), and CAP_KILL (signal any process). Each process has five capability sets: Permitted (maximum it may hold), Effective (currently active for permission checks), Inheritable (passed across execve for capability-aware binaries), Bounding (upper limit for the process tree), and Ambient (inherited by non-privileged execs, added in 4.3). File capabilities, stored in extended attributes, let a binary gain specific capabilities on exec without being setuid root - for example, /usr/bin/ping typically has cap_net_raw+ep instead of the historical setuid bit. You inspect capabilities with getcap, setcap, and capsh, and view a process's sets in /proc/<pid>/status. Container runtimes rely heavily on capabilities: Docker drops most by default and keeps a small allowlist, while --cap-add and --cap-drop tune the sandbox. Kubernetes exposes the same knobs via securityContext.capabilities. Combined with namespaces, cgroups, seccomp, and MAC systems like AppArmor or SELinux, capabilities form a core layer of least-privilege defense - but only if you actually drop the ones you don't need. Granting CAP_SYS_ADMIN or leaving the full default set defeats most of the benefit.

Common Misconception

Dropping the setuid bit and running as an unprivileged UID is enough security. In practice, many binaries still need one specific privilege (raw sockets, low ports, ptrace) and either get run as root or given file capabilities - if you grant CAP_SYS_ADMIN or the whole default set you have effectively kept root, since several individual capabilities are nearly as powerful as full root.

Why It Matters

Capabilities are the difference between a compromised web server that can only bind port 80 and one that can load kernel modules, mount filesystems, or read every file on disk; getting them right shrinks the blast radius of any RCE dramatically.

Common Mistakes

  • Granting CAP_SYS_ADMIN because a tool complains - it is nearly equivalent to full root and should be a last resort.
  • Keeping Docker's default capability list instead of dropping all and adding only what the workload needs.
  • Confusing file capabilities (xattrs on a binary) with process capabilities and expecting shell scripts to inherit them across execve.
  • Forgetting the Ambient set, so a capability in Permitted is silently lost when the process execs a non-capability-aware binary.
  • Using setuid root for a daemon that only needs CAP_NET_BIND_SERVICE, giving it every other root privilege for free.

Code Examples

✗ Vulnerable
# 1. Running a web server as root just to bind port 80:
sudo ./mywebserver --port 80
# Any RCE now runs with full root: mount, modprobe, read /etc/shadow, everything.

# 2. Docker with the default (still generous) capability set,
#    then adding SYS_ADMIN because 'something didn't work':
docker run --cap-add=SYS_ADMIN myapp
# CAP_SYS_ADMIN alone allows mount, pivot_root, setns, and dozens of
# operations that let a container escape - this is essentially root.

# 3. Setuid-root binary for a tool that just needs raw sockets:
sudo chown root:root ./myping
sudo chmod u+s ./myping
# Now myping runs as full root instead of holding only CAP_NET_RAW.
✓ Fixed
# 1. Grant only the one capability the binary needs, via file caps:
sudo setcap 'cap_net_bind_service=+ep' ./mywebserver
./mywebserver --port 80        # runs as unprivileged user, still binds :80
getcap ./mywebserver           # ./mywebserver = cap_net_bind_service+ep

# 2. Docker: drop everything, add back only what you need:
docker run --cap-drop=ALL \
           --cap-add=NET_BIND_SERVICE \
           --security-opt=no-new-privileges \
           myapp

# 3. Kubernetes securityContext with least privilege:
# securityContext:
#   runAsNonRoot: true
#   capabilities:
#     drop: ["ALL"]
#     add:  ["NET_BIND_SERVICE"]
#   allowPrivilegeEscalation: false

# Inspect a running process's capability sets:
grep Cap /proc/$(pgrep mywebserver)/status
capsh --decode=0000000000000400   # decode a hex cap mask

Added 13 Sep 2026
Views 22
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 4 pings M 1 ping T 2 pings W 0 pings T 2 pings F 0 pings S 0 pings S 2 pings M 0 pings T 0 pings W 0 pings T
No pings yet today
No pings yesterday
Google 4 Meta AI 2 PetalBot 1 Perplexity 1 Ahrefs 1 Unknown AI 1 SEMrush 1
crawler 11
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Medium
⚡ Quick Fix
Stop running as root: drop ALL capabilities and add back only the specific ones you need (e.g. NET_BIND_SERVICE), using setcap for binaries or --cap-drop=ALL --cap-add=... for containers.
📦 Applies To
bash cli web queue-worker docker podman kubernetes systemd
🔗 Prerequisites
🔍 Detection Hints
Dockerfiles or compose files using --privileged or --cap-add=SYS_ADMIN; Kubernetes pods without capabilities.drop: [ALL]; setuid root binaries where file capabilities would suffice; services running as root just to bind low ports
Auto-detectable: ✓ Yes getcap setcap capsh trivy kube-bench docker-bench-security
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Low ✗ Manual fix Fix: Medium Context: File Tests: Update
CWE-250 CWE-269 CWE-732


✓ schema.org compliant