Audit Docker Plugins Safely with docker plugin ls
Installed plugins have a habit of going quietly wrong, and docker plugin ls is the read-only way to see exactly what state each one is in. It lists what the daemon holds, narrows the result by enabled state or capability, and hands back a format a script can use. None of this installs, enables, disables or removes anything: allow about five minutes for a quick check, longer if you are chasing a daemon or permission problem.
The route
Jump straight to the step you need, or tick off Done means at the end.
You need the Docker CLI and a running daemon to talk to. Docker access is security-sensitive in its own right: membership of the Docker socket's group can hand someone effective control of the host. Use sudo only if your installation genuinely requires it, and do not join a privileged group just to make this one command work.
1. Confirm the installed command
Check which executable actually runs and which package supplied it before you trust any output, particularly if more than one Docker installation or wrapper script is floating around. On this machine, the installed Docker Community Edition CLI is version 29.8.1.
$ command -v docker
/usr/bin/docker
$ dpkg-query -W -f='${Package} ${Version}\n' docker-ce-cli
docker-ce-cli 5:29.8.1-1~ubuntu.24.04~noble
$ docker plugin ls --help
The subcommand's synopsis is docker plugin ls [OPTIONS]. This guide matches that installed version, so keep the version number beside any output you capture; it matters when you are comparing hosts or writing an incident record later.
Checkpoint
docker resolves to the CLI you expect, and the docker-ce-cli package is the one installed.
2. List every installed plugin
Run the command with no filter to see everything the daemon's plugin store currently holds:
$ docker plugin ls
ID NAME DESCRIPTION ENABLED
The columns are ID, name, description and enabled state. The empty table above is genuinely what a daemon with no plugins looks like: it is not proof the CLI is broken. On a host with plugins, each one gets its own row.
If the command cannot reach the daemon, that is a service or socket problem to chase through your normal admin process, not a reason to start changing socket permissions. A permission-denied error means check your account's existing Docker access first.
3. Filter by enabled state
Two filter values do the narrowing you usually want:
enabled=truefinds plugins that are currently active.enabled=falsefinds plugins installed but sitting idle.
$ docker plugin ls --filter enabled=true
ID NAME DESCRIPTION ENABLED
$ docker plugin ls --filter enabled=false
ID NAME DESCRIPTION ENABLED
A filter returning no rows just means nothing matches that condition; it does not enable or disable anything. Stick to the documented values exactly, since a plugin name, image tag or arbitrary field is not an accepted filter.
Checkpoint
Decide whether you need the full inventory or only one enabled state, and keep the unfiltered result too if you are building an audit trail.
4. Find a capability
Plugins can also be filtered by what they claim to do. The installed CLI documents four capability values: volumedriver, networkdriver, ipamdriver and authz.
$ docker plugin ls --filter capability=volumedriver
ID NAME DESCRIPTION ENABLED
Swap in whichever of those four values matches what you are checking. A capability filter is narrower than an enabled-state one, so an empty result can simply mean no installed plugin offers that capability. It says nothing about what a registry could install, and it does not touch a registry at all.
5. Choose output for people or scripts
The default table reads fine at a terminal. For a compact human report, pick specific fields with a Go template:
$ docker plugin ls --format '{{.ID}}: {{.Name}}'
The documented placeholders are .ID, .Name, .Description and .Enabled. Quote the template as one shell argument, and keep the single quotes unless you deliberately want shell interpolation.
For machine-readable output, ask for JSON instead:
$ docker plugin ls --format json
With no matching plugins this prints nothing; with plugins present, each record is a JSON object. Treat it as data, not a fixed table layout: validate it with your JSON tooling and handle an empty result on purpose rather than by accident.
You can combine a capability filter with a table template too:
$ docker plugin ls --filter capability=volumedriver --format 'table {{.ID}}\t{{.Name}}'
ID Name
The table prefix tells Docker to print column headings; drop it and the same template prints only the rendered values. --no-trunc stops output being truncated, while --quiet or -q prints just the plugin IDs:
$ docker plugin ls --quiet
Do not parse the default table by column position when a template or JSON output can give you the exact field you need. Names and descriptions can contain spaces, and that breaks naive column splitting.
6. Tell a CLI failure from an empty inventory
Separate a CLI problem from a genuine inventory result before you act on either. command -v docker checks the executable; docker plugin ls checks daemon access and plugin state. A non-zero exit status or an error message means the check did not complete, so never read a blank-looking result as "no plugins installed" until you have confirmed the command actually ran.
Common traps:
- Using a capability name outside the four documented values and getting an empty result that looks like a real answer.
- Assuming
enabled=falsemeans safe to remove. It only means inactive right now. - Running against the wrong Docker context without realising it.
Confirm the daemon context through your usual Docker administration procedure before you write down a result. This guide does not touch contexts, plugin state or daemon configuration anywhere.
There is nothing to undo here, since every command above is read-only. If a later task installs, enables, disables or removes a plugin, treat that as its own separate change, with its own approval and its own recovery plan for whatever depends on it.
Done means
- Confirmed the CLI path and the installed
docker-ce-cliversion. - Captured an unfiltered plugin list and told an empty list apart from an error.
- Used only documented filters for enabled state and capability.
- Picked a template, JSON, no-trunc or quiet output to suit the job.
- Left plugin state untouched: nothing installed, enabled, disabled or removed.