Docker socket security: why /var/run/docker.sock is root access
Mounting /var/run/docker.sock into a container grants that container a root-equivalent privilege boundary. This is not a Docker vulnerability. The daemon runs as root, listens on a filesystem socket, and trusts any client that can write to it.
Symptoms of abuse look like container escape or host compromise, but the container never escaped. It asked the root-owned daemon to perform privileged operations on its behalf. This guide explains the mechanism, how to audit exposure, and what constraints you can apply without rebuilding your pipeline.
What this means
The Docker daemon (dockerd) runs as root on the host and exposes a Unix domain socket at /var/run/docker.sock. By default the socket is owned by root:docker with mode 0660. Any process that can write to it can send API commands, which dockerd executes with root privileges. The daemon does not re-authenticate the client.
For an unprivileged host user, membership in the docker group is equivalent to passwordless root. That user can create a container that bind-mounts the host root filesystem, start it with --privileged, and execute a shell on the host. Inside a container, a volume mount of /var/run/docker.sock grants the same capability to any process in that container. The container does not need --privileged, dangerous capabilities, or a kernel namespace escape. It asks the root-owned daemon to do the work.
Read-only socket mounts reduce filesystem-level risk but do not eliminate it. The Docker API still exposes container creation, execution, and image management endpoints. A client with read access can query daemon state, inspect other containers, and use that information for lateral movement or to craft further attacks.
Common exposure paths
| Exposure path | What it looks like | First thing to check |
|---|---|---|
| Container mounts the Docker socket for CI/CD, monitoring, or job runners | docker run -v /var/run/docker.sock:/var/run/docker.sock or compose equivalent | docker inspect --format '{{json .Mounts}}' on running containers |
User added to the docker group for convenience | User runs docker ps without sudo | getent group docker or groups <user> |
| Daemon bound to unauthenticated TCP port 2375 | Legacy or dev configs using -H tcp://0.0.0.0:2375 | ss -tlnp | grep 2375 |
| Socket permissions relaxed to 0666 | Stack Overflow “fix” allowing any user to connect | stat -c '%a' /var/run/docker.sock |
Quick checks
# Containers mounting the Docker socket
docker ps -q | xargs -I{} docker inspect --format '{{.Name}}: {{range .Mounts}}{{.Source}}->{{.Destination}} {{end}}' {} | grep docker.sock
# Processes currently holding the socket open
sudo lsof /var/run/docker.sock
# Socket ownership and permissions (expected: 0660 or stricter)
stat -c '%U:%G %a' /var/run/docker.sock
# Members of the docker group
getent group docker
# Unauthenticated TCP exposure
ss -tlnp | grep -E '2375|2376'
# Check if a container runs as privileged
docker ps -q | xargs -I{} docker inspect --format '{{.Name}} Privileged={{.HostConfig.Privileged}}' {}
How to diagnose it
Inventory socket mounts. Run the
docker inspectloop from quick checks. Record the container name, image, and mount mode (read-only or read-write).Verify host users and processes with socket access. Check
getent group docker. Runsudo lsof /var/run/docker.sockto see which processes hold the socket open. Processes other thandockerd,containerd, or known management tools warrant investigation.Inspect socket permissions. The mode should be
0660or stricter. If it is0666, any local user can connect. Correct this withchmod 660 /var/run/docker.sock. Warning: This immediately revokes access for any client relying on the broader permissions. Verify active consumers first.Check for TCP exposure. If the daemon listens on TCP, verify whether it uses TLS mutual authentication. Port
2375without TLS is remote root access. Port2376with TLS is safer, but still requires certificate management and authorization plugins for fine-grained control.Trace blast radius per consumer. For every container with the socket mounted, determine which process inside actually uses it. If the container runs as root with the socket mounted, container compromise is immediate host compromise. If the container runs as non-root but mounts the socket, privilege escalation inside the container still yields host root.
Validate read-only mounts are not treated as safe. Confirm that runbooks and security reviews do not classify
rosocket mounts as low-risk. The API is the same regardless of filesystem mount flags.
Metrics and signals to monitor
| Signal | Why it matters | Warning sign |
|---|---|---|
| Containers with Docker socket mounts | Each mount is a root-equivalent escape path | Unexpected container mounting the socket |
| Docker socket access by process | Detects unknown consumers outside baseline | New process holding the socket FD outside of dockerd, containerd, or authorized agents |
| Privileged container count | Socket compromise is often exploited by starting privileged containers | Sudden increase in privileged containers |
| Container creation rate | Attackers with socket access may spawn containers for persistence | Container churn that does not correlate with deployments |
| Daemon error logs | Failed authorization or unusual API patterns may appear here | Repeated authentication failures or denied operations |
| Host path mounts | Socket mounts are a subset of sensitive host path exposure | Bind mounts from /, /etc, /root, or /var/run |
Fixes
If a container needs Docker API access
Do not mount the raw socket into application containers. Re-architect the workload to issue commands through an external, authenticated gateway. If you must mount the socket, run the container with the least-privileged user, drop all capabilities, and use a read-only mount only as a marginal improvement. Treat the container as if it were running directly on the host as root.
If the docker group is overpopulated
Remove users from the docker group who do not require direct daemon access. Require sudo for Docker commands and audit escalations through standard logging. Any user in the docker group can launch a container that accesses any host path or device node.
If the daemon is exposed on TCP
Disable unauthenticated TCP immediately. Port 2375 without TLS is remote root access. If remote access is required, configure TLS mutual authentication on port 2376, or use SSH tunneling with docker -H ssh://user@host. If you must use TCP, layer an authorization plugin on top of TLS for fine-grained control.
If socket permissions are too broad
Reset the socket to mode 0660 and ownership root:docker. Warning: Verify no legitimate clients require the broader permissions before changing. Investigate whether a startup script, udev rule, or configuration management drift caused the change. Some storage appliances reset socket ownership on reboot. Automate post-boot verification to catch drift before containers start.
Prevention
Audit every container definition in CI for volume mounts containing docker.sock and fail the build unless the mount is explicitly allow-listed with a documented justification. Maintain a registry of authorized socket consumers and review it quarterly.
Monitor socket access continuously. Use auditd rules on /var/run/docker.sock or periodic lsof checks to detect new consumers. Alert when a process outside your baseline opens the socket.
Avoid the docker group as a convenience shortcut. Do not add developers or application accounts to the docker group to avoid sudo prompts. The time saved is not worth full root equivalence.
Never expose TCP 2375. Treat any playbook or tutorial recommending -H tcp://0.0.0.0:2375 as a security incident waiting to happen. If remote access is required, prefer SSH or TLS on 2376 with mutual authentication.
Review read-only mounts quarterly. Security reviews often classify ro mounts as safe. Schedule explicit reviews of read-only socket mounts to ensure they are not treated as benign. Document the exact API endpoints each socket consumer requires and verify that the consumer cannot reach anything beyond that scope.
How Netdata helps
Netdata tracks system and service metrics that help identify socket abuse:
- Container count anomalies: Netdata monitors per-cgroup resource usage; a sudden increase in active cgroups indicates container churn that may follow unauthorized API calls.
- Docker daemon load: Track
dockerdCPU, memory, and process activity. Sustained spikes can indicate abusive API usage. - Host resource correlation: Correlate unexpected host I/O or network utilization with container events to spot unauthorized operations.
- Log patterns: If Netdata is configured to collect system journal or file-based logs, alert on
dockerderror spikes or authentication failures.
Related guides
- Docker commands hang: docker ps, inspect, and exec freezes
- Docker container cannot connect to another container
- Docker container cannot connect to the internet: diagnosis and fixes
- Docker container exits immediately: how to diagnose it
- Docker container high CPU usage: causes and fixes
- Docker container high memory usage: how to diagnose it
- Docker container keeps restarting: causes, checks, and fixes
- Docker container memory leak: how to find one and prove it
- Docker container running but unhealthy: how to diagnose health check failures
- Docker CPU throttling: the hidden cause of container latency
- Docker daemon not responding: how to troubleshoot a hung dockerd
- Docker disk space full: how to troubleshoot /var/lib/docker





