Docker audit fixes

Image Vulnerabilities: fixing all 8 checks

The image audit inspects the images already pulled onto this host - their CVEs, embedded secrets, default user, base image age and signing - because a container is never safer than what was baked in.

Six of the eight checks ask the daemon for the local image list, so they report "Cannot query Docker daemon - run as root, with sudo, or as a docker group member" rather than a pass, and they skip a second way when the host has no local images at all. Image Signature Verification and SBOM Generation only look for binaries on PATH, so they still answer when the daemon is unreachable.

8
checks in this audit
3
rated high severity
6
need root or sudo
~16s
automated run time

Transcribed from the docker-security-image-vulnerabilities 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.

  • Image Vulnerability Scan

    Soon

    Scans local Docker images for known CVEs using trivy (or reports if no scanner is available)

    HighNeeds root4 results
  • Floating Image Tags

    Soon

    Flags images using the floating :latest tag instead of a pinned version/digest

    MediumNeeds root3 results
  • Image Secrets Scan

    Soon

    Scans image layers/build history for embedded credentials and secrets

    HighNeeds root4 results
  • Image Default User

    Soon

    Checks whether images define a non-root USER

    MediumNeeds root3 results
  • Image Signature Verification

    Soon

    Checks whether Docker Content Trust or cosign-based signature verification is in place

    MediumNo root3 results
  • End-of-Life Base Image

    Soon

    Flags known end-of-life or soon-to-be-EOL base image tags

    HighNeeds root3 results
  • Image Build Best Practices

    Soon

    Runs dockle if available, otherwise heuristically checks for HEALTHCHECK presence

    LowNeeds root3 results
  • SBOM Generation

    Soon

    Checks whether an SBOM generator (syft, docker sbom, trivy) is available

    LowNo root2 results
Shared script behaviour

How the Image Vulnerabilities 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.

Most examine the first 5 or 10 local images (docker images | head -N), so large hosts are sampled, not fully scanned.

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: 6 of the 8 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

Image Vulnerabilities questions

That SKIP means trivy returned nothing inside the script's 120 second per-image timeout, and the usual cause is a first run: trivy downloads a vulnerability database of tens of megabytes before it can scan anything. Run trivy image --download-db-only once to warm the cache, then re-run the audit. On an air-gapped host, point TRIVY_DB_REPOSITORY at a mirror instead.
No, most of these checks read a sample. The CVE scan, the floating tag check and the secrets scan take the first 5 images from docker images; the default USER check and the HEALTHCHECK heuristic take the first 10, and dockle takes the first 3. Only the end-of-life base image check reads the whole list. On a host with thirty images, a PASS says the sample was clean, not that the host is.
Because this check has drifted, and its own page says so. It reads exactly two things: the DOCKER_CONTENT_TRUST variable in the audit's own shell, and whether a cosign binary is on PATH. It never inspects an image or a signature. Docker retired Content Trust and withdrew notary.docker.io, so DOCKER_CONTENT_TRUST=1 now breaks pulls of Docker Official Images: treat that PASS as a finding of its own, unset the variable, and verify with cosign instead.
Audit your fleet

Run all 8 Image Vulnerabilities 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