20.3.1.4 Privileged Mode Avoidance
A focused guide to Privileged Mode Avoidance, connecting core concepts with practical Docker and container operations.
Privileged mode (--privileged) grants a Docker container nearly unlimited access to the host system. A privileged container has all Linux capabilities enabled, can access all host devices, and has no seccomp or AppArmor restrictions. The container can mount filesystems, load kernel modules, manipulate network interfaces, and escape the container namespace to access the host. Privileged mode exists for specific infrastructure use cases and must never be used for application containers.
What --privileged Does
Running a container with --privileged applies the following:
- Grants all ~38 Linux capabilities, including
CAP_SYS_ADMIN,CAP_NET_ADMIN,CAP_SYS_MODULE,CAP_SYS_RAWIO, and all others. - Disables the default seccomp profile, allowing any system call.
- Removes AppArmor/SELinux confinement.
- Exposes all host devices under
/devto the container. - Allows mounting host filesystems.
The result is a container that is isolated at the process namespace level (it has its own PID, UTS, and network namespace) but is otherwise essentially root on the host. A process inside a privileged container can trivially escape to the host:
# Inside a privileged container — this breaks out to the host filesystem
mkdir /mnt/host
mount /dev/sda1 /mnt/host
chroot /mnt/host
This sequence mounts the host's root disk and chroots into it, giving full host access.
Why --privileged Is Sometimes Used
Several legitimate use cases require elevated container privileges:
Docker-in-Docker (DinD) — Running a Docker daemon inside a container, used in CI/CD pipelines to build images during tests. The inner Docker daemon needs access to system resources that only --privileged provides.
Device access — Containers that directly manage hardware devices (GPU compute containers, USB device managers, hardware security modules) need access to host device files.
Kernel module loading — Containers that load kernel modules need CAP_SYS_MODULE.
Network manipulation tools — Tools that configure host networking (VPN clients, network monitoring agents) may need CAP_NET_ADMIN and device access.
Even for these legitimate cases, --privileged is the broadest possible grant — and a better approach exists for most of them.
Alternatives to --privileged
Instead of --privileged for Docker-in-Docker: Use the Docker socket (/var/run/docker.sock) bind mount, which gives the container access to the host Docker daemon without granting kernel-level privileges. Or use a rootless Docker setup, or use Kaniko or Buildah for image building in CI without any daemon access.
docker run -v /var/run/docker.sock:/var/run/docker.sock \
docker:dind \
docker build -t my-image .
Note: mounting the Docker socket also carries security implications — a container with Docker socket access can create privileged containers, which is an effective host escape. Use this only when necessary and with careful access control.
Instead of --privileged for device access: Mount only the specific device needed with --device:
docker run --device /dev/video0 my-camera-app
This grants access to /dev/video0 only, not all host devices.
Instead of --privileged for capability requirements: Add only the specific capabilities needed with --cap-add:
docker run \
--cap-add NET_ADMIN \
--cap-add NET_RAW \
my-vpn-client
This grants two capabilities instead of all 38.
Detecting Privileged Containers
To check whether a running container is privileged:
docker inspect my-container --format '{{.HostConfig.Privileged}}'
Output: true indicates privileged mode. false indicates it is not privileged.
To list all running containers and their privilege status:
docker ps -q | xargs docker inspect --format '{{.Name}} Privileged={{.HostConfig.Privileged}}'
/api-1 Privileged=false
/db-1 Privileged=false
/dind-1 Privileged=true
Policy: Preventing Privileged Containers
In environments where privileged containers should never run, enforce this at the infrastructure level:
Docker Swarm: Use docker config and service constraints to prevent privileged services from being scheduled.
Kubernetes: Use Pod Security Standards (PSS) or PodSecurityPolicy (deprecated) to block privileged: true pods. The Restricted PSS profile blocks all privileged containers.
OPA/Gatekeeper: Define admission policies that reject any pod or container spec containing privileged: true.
Docker daemon configuration: The Docker daemon does not have a built-in flag to block privileged containers universally, but authorization plugins can intercept and reject docker run --privileged calls.
The Escape Demonstration (Educational)
Understanding how privileged containers escape is important for security practitioners. Inside a privileged container with access to the host's block devices, it is trivial to mount the host root filesystem and gain complete control of the host. This is not a subtle exploit — it is the documented, intended behavior of privileged mode.
This is why privileged mode must be treated as granting root on the host, not just root in the container. Every security boundary between the container and the host is removed.
Privileged Mode in CI/CD
The most common legitimate use of --privileged in practice is Docker-in-Docker in CI pipelines. Even here, the pattern has known alternatives:
Option 1: Docker socket mount — Mount the host Docker socket. The CI job builds images using the host Docker daemon. Security implication: any job that can create containers can create privileged ones.
Option 2: Kaniko — A tool designed for building container images inside a container without requiring Docker daemon access or privileged mode. Kaniko runs as a regular non-privileged container and builds the image from a Dockerfile using a userspace implementation.
docker run \
-v /path/to/context:/workspace \
-v /path/to/kaniko-config.json:/kaniko/.docker/config.json \
gcr.io/kaniko-project/executor:latest \
--context /workspace \
--destination registry.example.com/my-image:latest
Kaniko is the recommended approach for image builds in environments where --privileged is not permitted, such as Kubernetes-based CI platforms.
Option 3: Buildah — An alternative image builder that runs without a daemon and supports rootless operation.
Summary
--privileged is a host escape in a single flag. It exists because there are real infrastructure use cases that require it, but those use cases are narrow. Application containers — web servers, databases, APIs, workers, caches — never have a legitimate reason to run privileged. Infrastructure containers that do require elevated access should use targeted alternatives (--device, --cap-add, Docker socket mounts, or purpose-built tools like Kaniko) rather than the broadest possible privilege grant.