Safeguard
Containers

Docker Privileged Mode: What --privileged Really Grants and Safer Options

Docker Compose privileged mode hands a container nearly all host capabilities. Here is what --privileged actually turns on, and the scoped alternatives that do the same job safely.

Karan Patel
Platform Engineer
6 min read

Docker Compose privileged mode (privileged: true) gives a container almost the same access to the host as a process running as root on the host itself, and in nearly every case you can replace it with a narrow set of capabilities instead. A privileged container gets all Linux capabilities, unrestricted device access, and its default seccomp and AppArmor confinement dropped. It is the single biggest single-flag escalation of container risk, and it shows up constantly in Compose files copied from Stack Overflow to "just make it work."

This post explains exactly what the flag turns on, why a privileged container is close to a host-level foothold, and how to get the same functionality with scoped grants.

What --privileged Actually Turns On

Running docker run --privileged or setting docker compose --privileged equivalent in a Compose file does several distinct things at once. People assume it is one switch; it is really four:

  1. All capabilities granted. Every Linux capability the kernel offers is added, including CAP_SYS_ADMIN, CAP_SYS_MODULE (load kernel modules), CAP_SYS_PTRACE, and CAP_DAC_READ_SEARCH. CAP_SYS_ADMIN alone is often called "the new root" because of how much it enables.
  2. All host devices exposed. The container sees /dev from the host. That includes raw disk devices like /dev/sda, so a process in the container can read or write the host's filesystem directly, bypassing every namespace boundary.
  3. Default seccomp profile disabled. The syscall filter that normally blocks around 40 dangerous syscalls is switched off, re-enabling calls like mount, keyctl, and others.
  4. AppArmor / SELinux confinement dropped. The default mandatory access control profile no longer applies.

Combine device access with CAP_SYS_ADMIN and a container can mount the host disk, chroot into it, and edit anything, including adding an SSH key for root. That is not a theoretical escape; it is a few shell commands.

Why a Privileged Container Is Effectively Host Root

The container isolation model rests on namespaces (what you can see), cgroups (what you can use), and capabilities plus seccomp plus MAC (what you can do). Privileged mode leaves the namespaces intact but demolishes the third pillar. Since the container still shares the host kernel, a process with full capabilities and device access has enough tools to cross the namespace boundary deliberately.

A concrete illustration of the risk category, using the host disk:

# Inside a privileged container, the host's root disk is visible
fdisk -l                 # host block devices are listed
mkdir /host && mount /dev/sda1 /host
# /host is now the host filesystem, writable

The point is not that the container was configured maliciously. It is that privileged mode removes the guardrails that would stop a compromised process, or a buggy one, from doing this by accident or under attacker control.

The Legitimate Reasons People Reach for It

Privileged mode does solve real problems, which is why it persists:

  • Docker-in-Docker for CI runners that build images.
  • Hardware access for containers driving USB devices, GPUs, or FUSE mounts.
  • Low-level networking tools that manipulate iptables or raw sockets.
  • System monitoring agents that read kernel structures.

In almost all of these, the container needs one or two specific powers, not all of them. Reaching for privileged: true is choosing the sledgehammer because you did not want to look up which capability you actually needed.

Scoped Alternatives That Replace It

The replacement pattern is: drop everything, add back only what the workload requires, and mount only the specific device. In Compose:

services:
  app:
    image: myorg/app:1.4.2
    cap_drop:
      - ALL
    cap_add:
      - NET_ADMIN        # only if the app manages network interfaces
    devices:
      - "/dev/net/tun:/dev/net/tun"   # expose one device, not all of /dev
    security_opt:
      - no-new-privileges:true

A few specific swaps:

  • FUSE mounts need SYS_ADMIN plus /dev/fuse, not full privilege.
  • iptables/NAT needs NET_ADMIN and usually NET_RAW.
  • GPU access should go through the NVIDIA container runtime with devices reservations, never privileged.
  • Docker-in-Docker is better replaced by mounting the host's Docker socket into a trusted CI job, or by rootless/sysbox runtimes, both of which have their own tradeoffs but avoid full host device access.

Always pair the grant with no-new-privileges:true, which prevents setuid binaries inside the container from re-escalating.

Detecting Privileged Containers Before They Ship

You cannot fix what you cannot see. Enforce it in three places:

At review time, grep your Compose and Kubernetes manifests. privileged: true, securityContext.privileged: true, and empty cap_drop with broad cap_add are all signals.

At admission, in Kubernetes, use Pod Security Admission (the restricted profile bans privileged pods) or a policy engine like Kyverno or OPA Gatekeeper to reject privileged workloads outright.

In the pipeline, container and IaC scanning tools flag privileged mode as a misconfiguration finding. A container scanning step in CI catches the Compose file before it reaches a host, alongside the image vulnerability scan you are presumably already running.

The goal is that privileged: true becomes a deliberate, reviewed exception with a comment explaining why, not a default that spreads by copy-paste.

FAQ

What does privileged mode do in Docker Compose?

Setting privileged: true grants the container all Linux capabilities, exposes all host devices under /dev, disables the default seccomp syscall filter, and drops AppArmor or SELinux confinement. The container gains access roughly equivalent to root on the host.

Is a privileged container a security risk?

Yes, a significant one. Because the container shares the host kernel and has full capabilities plus device access, a compromised process can mount the host filesystem and gain host-level control. Privileged containers should be rare, reviewed exceptions.

How do I replace privileged mode safely?

Drop all capabilities with cap_drop: [ALL], add back only the specific capabilities the workload needs, expose only the individual devices required, and set no-new-privileges:true. Most use cases need one or two capabilities, not full privilege.

How can I detect privileged containers in my environment?

Scan Compose and Kubernetes manifests in CI, enforce Pod Security Admission or a policy engine like Kyverno at the cluster admission layer, and use container or IaC scanning that reports privileged mode as a misconfiguration.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.