Docker audit fixes

Volume Permissions: fixing all 7 checks

The volume audit reads every container's mount table and the /var/lib/docker/volumes tree, so it finds which host paths a container can reach and which volume data a local account can write.

Three of the seven stat /var/lib/docker/volumes and need real root: docker group membership gets you the daemon but not that directory, so they skip with a "Need root" message while the four container-side checks still run. Those same three skip on a host with a custom data-root, because the path they look under is hard-coded.

7
checks in this audit
2
rated high severity
7
need root or sudo
~13s
automated run time

Transcribed from the docker-security-volume-permissions audit script.

Every check

Find your finding

Listed in the order the audit runs them. Take the check name from the third field of the result line and open its page.

  • Sensitive Host Path Mounts

    Soon

    Checks for containers bind-mounting sensitive host paths (/, /etc, /root, /proc, /sys, docker.sock, /var/lib/docker, /home)

    HighNeeds root3 results
  • Writable Volume Mounts

    Soon

    Counts read-write vs read-only volume mounts and flags a writable docker.sock

    HighNeeds root3 results
  • World-Writable Volumes

    Soon

    Scans Docker volume data directories for world-writable permissions

    MediumNeeds root3 results
  • Volume Ownership

    Soon

    Flags volume data owned by UIDs with no matching host user (orphaned ownership)

    MediumNeeds root3 results
  • Volume Directory Permissions

    Soon

    Checks for overly permissive (777) modes on volume directories and the volumes root

    MediumNeeds root3 results
  • Anonymous/Dangling Volumes

    Soon

    Detects dangling (unused/orphaned) Docker volumes

    LowNeeds root3 results
  • Read-Only Volume Enforcement

    Soon

    Checks whether containers enforce a read-only root filesystem

    MediumNeeds root3 results
Shared script behaviour

How the Volume Permissions audit reads your server

Every check in this audit runs after the same preamble, and several of its results only make sense once you know what that preamble could and could not see.

The first two and the last two evaluate all containers (docker ps -a, including stopped); the three /var/lib/docker/volumes checks need root.

Docker detection: DOCK=direct if docker ps works as the audit user (docker group), DOCK=root if it works through sudo; the dk helper wraps docker accordingly. IDS is the list of running container IDs and NRUN their count; dk inspect --format is used with Go templates. Podman is recognised but not audited.

Why checks skip

A SKIP is never a pass

A skipped check verified nothing at all. The most common cause is privilege: 7 of the 7 checks in this audit need root for a complete result. Before every run, each script works out which of four privilege modes it is in.

The four privilege modes an audit script can run in, and what each one means for checks that need root
ModeHow it is reachedWhat it means for your results
rootThe audit runs as UID 0.Every privileged branch runs directly. No check skips for lack of permission.
nopasssudo -n true succeeds, so the account has passwordless sudo.Privileged commands run through sudo -n.
passA sudo password was supplied in the CtrlOps audit settings and accepted.Privileged commands run through sudo -S.
noneNone of the above worked.CAN_ROOT=0. Every privileged branch returns SKIP with a "Need root" message rather than guessing.

If many checks skip with a “need root” message, run the audit as root, grant the audit account sudo (with or without NOPASSWD), or supply the sudo password in the CtrlOps audit settings. For Docker checks, membership of the docker group is an alternative to sudo: run usermod -aG docker <user> and log in again.

FAQ

Volume Permissions questions

Those three read volume data directly under /var/lib/docker/volumes, which is mode 701 or 711 and owned by root, so they go through sudo rather than through the Docker API. Membership of the docker group is enough for the four container-side checks and not enough for these. Run the audit as root, or give the audit account sudo. The same three also skip when that directory does not exist, which is how a custom data-root in daemon.json looks to them.
Usually yes, which is why the message says to confirm before deleting. The check calls a volume orphaned when its owning UID matches no host user and no container's configured user. Images such as postgres, redis and nginx drop privileges inside their entrypoint instead of declaring USER, so .Config.User is empty and their UIDs never enter the comparison. Hosts running userns-remap shift UIDs into the 100000 range and produce the same false warning in bulk.
Change the owner, not the mode. Work out the UID the container actually writes as, chown the volume data to it, and only then remove other-write with chmod o-w: a container that could write purely because the directory was 777 starts failing the moment you take that bit away without giving it ownership. Note too that the check reads only the volume root directory, not the files beneath it, so fixing the root does not clear anything deeper.
Audit your fleet

Run all 7 Volume Permissions checks, in one click

CtrlOps runs this audit over your existing SSH connection - no agents, no scripts to manage. $7/user/month after a 1 month free trial - no credit card required.

Start instantly· No credit card· No sneaky autorenewals