Docker audit fix

How to Configure Docker Daemon Logging Levels on VPS

The Docker daemon logs at info unless log-level says otherwise, and debug writes API request bodies, environment variables and registry auth flows into the journal. Keep dockerd at info outside a troubleshooting window.

Hiren KalariyaLast reviewed: Oct 6, 2026Check daemon-log-level
Low
severity
No
needs root or sudo
3
results it can return
5 of 8
checks in this audit

Every threshold on this page is transcribed from the docker-security-daemon-socket audit script that CtrlOps runs, and a build check fails if the two ever disagree. See all 8 Daemon & Socket checks, or how the audit runs.

Low severityNo sudo needed

What this check reads

It reads the running dockerd command line out of ps -eo args and takes the value of --log-level from it. If no flag is set there it falls back to the "log-level" key in /etc/docker/daemon.json, so the command line always wins, exactly as it does for the daemon itself. The comparison is a literal string match on debug: only that value WARNs, and every other value PASSes, including an unset one, which is reported as info (default).

When it applies

Runs whenever the docker binary exists; it needs neither daemon access nor root, reading --log-level from the running dockerd command line first and falling back to "log-level" in /etc/docker/daemon.json (which is world-readable on a default install, so the check needs no root). Only the exact value debug produces a finding; trace, an invalid value, or no value at all all report as PASS, with an unset value shown as "info (default)". It judges the daemon's log verbosity only - per-container logging and the log driver are separate concerns, covered by the Container Log Limits check.

What each result means

Result thresholds this check applies
ResultWhenWhat it means
SKIPDocker not installedNothing was checked. With no docker binary present, the daemon's log level was never read.
WARN`debug`The daemon is writing debug records, which include full API request bodies and can carry registry credentials and build arguments into the journal.
PASS`info` (default) or anything elseNo debug level was found on the command line or in daemon.json. Note that trace, which is more verbose still, also lands here.

Why it matters

Debug logging records API request bodies, environment variables passed at docker run, registry auth flows and more into the journal, where a wider set of users may read them. It also degrades performance. CIS Docker 2.3 "Ensure the logging level is set to 'info'".

Why it fails, and when it is wrong

  • Left over from troubleshooting a daemon issue.
  • If daemon.json is not readable by the audit user, the JSON path is silently empty and the command-line path is used; a debug set only in an unreadable daemon.json would be missed.
  • -D/--debug on the command line and "debug": true in daemon.json both put the daemon at debug level, and neither is matched: the check only reads --log-level and "log-level".

How to fix it

Find where debug is set

The command line wins over the file, for the daemon and for the audit, so check both.

systemctl cat docker | grep -n ExecStart
sudo grep -nE '"(log-level|debug)"' /etc/docker/daemon.json

Set it to info

Set the level in daemon.json, merged with whatever keys the file already has, and delete any "debug": true. Remove --log-level debug or -D from the drop-in with sudo systemctl edit docker.

{ "log-level": "info" }

Restart the daemon

sudo systemctl daemon-reload
sudo systemctl restart docker

The restart stops every running container, and only those with an always or unless-stopped restart policy come back on their own, unless "live-restore": true is set in daemon.json.

Verify the fix

ps -eo args | grep '[d]ockerd'                     # expected: no --log-level debug
sudo grep -n log-level /etc/docker/daemon.json     # expected: "info", or absent
docker info --format '{{.LoggingDriver}}'

# Confirm the daemon is not emitting debug records:
sudo journalctl -u docker --since '-1h' | grep -c 'level=debug'
# expected: 0

Debugging

Usually left over from troubleshooting. Remove --log-level debug from the systemd drop-in (systemctl cat docker) or set "log-level": "info" in daemon.json, then systemctl restart docker. Debug output includes full API request bodies, which can contain registry credentials and build arguments.

The command line wins: the check reads it first, and so does the daemon. systemctl cat docker | grep ExecStart shows whether a flag is overriding your file.

This check only looks at the daemon's own verbosity. Runaway container logs are the far more common cause of a full disk; see the Container Log Limits check.

A genuine gap: only the literal string debug is matched, so the even more verbose trace slips through. Check by hand with the ps/grep commands above.

Log level is read at daemon start, so the change needs systemctl restart docker. That stops every running container, and only those with an always or unless-stopped restart policy come back on their own, unless "live-restore": true is set in daemon.json, which keeps containers running while the daemon restarts. Plan the restart.

Sources

How the script reads this

Next

Re-run the Daemon & Socket audit after applying the fix and confirm this check moves to PASS. CtrlOps runs all 8 checks over your existing SSH connection and scores the result, so the change is visible without reading another config file.

All 8 Daemon & Socket fixes
Audit your fleet

Find every one of these on every server, 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.

Windows

✓ Start instantly·✓ No credit card·✓ No sneaky autorenewals