Safeguard
Containers

Docker Privileged Containers: `docker run` and Compose Risks

docker run privileged and docker compose privileged both hand a container root-equivalent access to the host — here's exactly what that means and when, if ever, it's justified.

Safeguard Team
Product
Updated 5 min read

Running docker run --privileged gives a container nearly every Linux capability, direct access to host devices, and the ability to bypass most of the isolation Docker's namespace and cgroup model is built to provide — which means a compromised privileged container is functionally a compromised host. The same applies to docker compose privileged: true in a compose file; it's the identical flag, just declared differently. This isn't a theoretical concern: privileged mode is one of the most common container misconfigurations flagged in cloud security audits, and it's frequently enabled for reasons that don't actually require it.

What does docker run privileged actually grant?

Privileged mode disables the default capability drop, gives the container access to all host devices under /dev, disables seccomp and AppArmor/SELinux confinement, and allows the container to mount additional filesystems including the host's. In practice, a process inside a privileged container can load kernel modules, access raw block devices, and in many configurations mount the host filesystem and chroot into it — at which point "container" is a formality, not a boundary. Docker's own documentation is explicit that --privileged is intended for cases like running Docker-in-Docker or certain hardware-access workloads, not as a convenience flag for "the app needs one extra permission and I don't want to figure out which one."

Why do teams reach for docker compose privileged so often?

Usually because a container needs one specific capability — binding to a low port, accessing a USB device, running iptables, mounting a loopback device — and privileged mode is the fastest way to make an error go away without diagnosing which permission is actually missing. The compose syntax makes this worse because it's a single boolean flag sitting next to dozens of other unremarkable service options:

services:
  app:
    image: myapp:latest
    privileged: true

That line looks no more alarming than restart: always in a diff, which is exactly the problem — it doesn't visually signal how much access it's granting, so it survives code review more often than it should.

What should you use instead of full privileged mode?

Grant the specific Linux capability the process needs with --cap-add, rather than all of them. Docker drops a defined set of capabilities by default and privileged mode restores all of them; most workloads that "need privileged" actually need one or two, such as NET_ADMIN for network manipulation or SYS_PTRACE for debugging tools. The pattern looks like:

docker run --cap-drop=ALL --cap-add=NET_ADMIN myapp:latest

For device access specifically, --device=/dev/xyz grants access to a single device node instead of all of /dev. For Docker-in-Docker workloads, rootless Docker or sysbox-runtime can often replace the need for privileged mode entirely by running the nested daemon without host-level capability escalation.

How do you find privileged containers already running in your environment?

Query the Docker API or Kubernetes admission data directly rather than relying on someone remembering which services were configured that way. On a single host, docker inspect on each running container reports HostConfig.Privileged; at scale, security teams typically run this as a continuous policy check against the container orchestrator's admission API so new privileged workloads get flagged before they reach production rather than discovered during an audit. Safeguard's SCA and container scanning surfaces privileged configuration alongside dependency vulnerabilities in a project's manifest and compose files, so a privileged: true line shows up as a finding during the same review as a vulnerable package, instead of requiring a separate infrastructure audit.

Is privileged mode ever the right call?

Occasionally — legitimate use cases include running nested Docker daemons for CI runners, certain systems-level monitoring agents that need broad /proc and /dev visibility, and some hardware-testing pipelines. Even then, the recommended pattern is to isolate the privileged workload on dedicated infrastructure separated from anything handling sensitive data or credentials, and to treat the host it runs on as being at the same trust level as the container itself. Privileged mode as a default in a shared multi-tenant cluster, or as a workaround for an unrelated permission error, is the pattern worth eliminating.

FAQ

Does --privileged disable Docker's user namespace remapping too?

Yes — privileged containers effectively run as root with full capabilities regardless of user namespace configuration, which undermines one of the main defense-in-depth controls Docker offers.

Is docker compose privileged: true any less risky than the CLI flag?

No, it's the exact same underlying mechanism; Compose just serializes the same runtime configuration Docker CLI flags produce.

Can Kubernetes prevent privileged containers even if a compose file requests it?

Yes, if compose files are translated to Kubernetes manifests or if teams migrate directly to Kubernetes, a Pod Security Standard or admission controller can reject privileged: true at the API server level, which is a much stronger control than code review alone.

What's the quickest fix if I inherited a codebase full of privileged: true?

Audit each instance for the specific capability or device it actually needs, replace the blanket flag with --cap-add and --device, and treat any that genuinely require full privileged access as infrastructure requiring isolated hosts, not shared clusters.

Never miss an update

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