Skip to content

no-privileged-service

privileged: true in Docker Compose disables nearly every container isolation mechanism. What it actually grants and the narrower alternatives.

On this page

privileged: true is the biggest hammer in the Compose vocabulary: it gives the container every Linux capability, access to every host device, and turns off the seccomp, AppArmor, and cgroup device protections that make a container a container. It usually enters a file as a workaround, because some device wouldn't open or some syscall was blocked, and then never leaves. This rule flags every service that sets it.

What the rule catches

compose.yaml — full host access via privileged
services:
  runner:
    image: my-runner:2.1.0
    privileged: true

Scanning this file reports:

✖ ERROR [docker-doctor/no-privileged-service]
  Service 'runner' runs in privileged mode. A privileged container has full access to the host's devices and kernel, so compromising this service compromises the host.

Why it matters

A privileged container is not meaningfully contained: it can load kernel modules, talk to raw disks, and remount host filesystems. Root inside is root on the host, so compromise of the service becomes compromise of the machine and every other workload on it. The setting also hides the service's real requirements, so nobody can later reconstruct which capability it actually needed; an explicit cap_add/devices list is both safer and better documentation.

How to fix it

Remove privileged: true and grant only what the service needs: specific capabilities via cap_add, or individual device access via devices.

compose.yaml — specific capabilities and devices only
services:
  runner:
    image: my-runner:2.1.0
    # grant only what the service actually needs
    cap_add:
      - NET_ADMIN
    devices:
      - /dev/net/tun

Almost every legitimate use has a narrower replacement:

  • Network syscalls (VPN, routing): cap_add: [NET_ADMIN].
  • One device: devices: [/dev/net/tun] (or /dev/dri, /dev/kvm, …).
  • GPU access for model inference: deploy.resources.reservations.devices with the gpu capability, not privileged.
  • Docker-in-Docker for CI: prefer the host's socket via a scoped mechanism (see no-docker-socket-mount) or a rootless DinD setup.

Start from nothing and add single capabilities until the service works; the final list is rarely more than two entries.

Rule details

  • Rule keydocker-doctor/no-privileged-service
  • Category — Compose
  • Default severityerror
  • Applies to — Docker Compose files

Explain this rule from the CLI:

npx @docker-doctor/cli@latest rules explain docker-doctor/no-privileged-service

Change its severity — or turn it off — in your config file:

// docker-doctor.config.ts
export default {
  rules: {
    "docker-doctor/no-privileged-service": "off",
  },
};

Severity affects the health score: error findings cost more points than warning, and info costs the least.