# CL-0002: Privileged Mode Enabled

**Severity:** CRITICAL

**References:**
- [OWASP Docker Security Rule #3](https://cheatsheetseries.owasp.org/cheatsheets/Docker_Security_Cheat_Sheet.html#rule-3-limit-capabilities-grant-only-specific-capabilities-needed-by-a-container)
- CIS Docker Benchmark 5.5 — Ensure that privileged containers are not used

## What it detects

Any service with `privileged: true`.

## Why it matters

Privileged mode disables nearly all container isolation. The container receives every Linux capability, every host device under `/dev`, and runs without the default seccomp and AppArmor profiles. PID, mount, and network namespaces are still in place by default, but escape to host root is trivial — `mount`, `unshare`, `mknod`, and BPF are all unblocked, and well-documented one-line escapes exist (e.g. mounting the host root via `/dev/sda1`, releasing the cgroup, abusing `release_agent`).

Treat `privileged: true` as **trivially escapable to host root**, not literally equivalent to running on the host — but the practical attack distance is one well-known technique away.

## Fix

`privileged: true` is almost never the right tool. The legitimate use cases (Docker-in-Docker, GPU passthrough, kernel module loading) each have surgical alternatives:

| Use case | Surgical alternative |
|---------|---------------------|
| Mount filesystems | `cap_add: SYS_ADMIN` (still dangerous; consider whether the mount can happen on the host) |
| Specific device access | `devices: [/dev/foo]` + `device_cgroup_rules` |
| Network configuration | `cap_add: NET_ADMIN` + `cap_add: NET_RAW` |
| Bind privileged ports | `cap_add: NET_BIND_SERVICE` |
| Run a debugger sidecar | `cap_add: SYS_PTRACE` (note: also allows reading any process's memory — see CL-0011) |
| Docker-in-Docker | Prefer `sysbox-runc` or rootless DinD over `--privileged` |

Replace it with a least-privilege configuration:

```yaml
# Instead of:
privileged: true

# Use:
cap_drop:
  - ALL
cap_add:
  - NET_ADMIN      # only what you actually need
security_opt:
  - no-new-privileges:true
```

If you don't know which capabilities are needed, remove `privileged: true`, run the service, and add back only the specific capabilities the workload demands.

## See also

- [CL-0006](CL-0006.md) — `cap_drop: [ALL]` (privileged grants all caps)
- [CL-0009](CL-0009.md) — seccomp / AppArmor (privileged drops both default profiles)
- [CL-0010](CL-0010.md) — host namespaces (privileged does not by itself share them, but is often combined with them)
- [CL-0011](CL-0011.md) — `cap_add: ALL` is the cap-only subset of privileged

When CL-0002 fires, expect CL-0006, CL-0009, and often CL-0010/CL-0011 to fire on the same service.
