# CL-0001: Container Runtime Socket Mounted

**Severity:** CRITICAL

**References:**
- [OWASP Docker Security Rule #1](https://cheatsheetseries.owasp.org/cheatsheets/Docker_Security_Cheat_Sheet.html#rule-1-do-not-expose-the-docker-daemon-socket-even-to-the-containers)
- CIS Docker Benchmark 5.32 — Ensure that the Docker socket is not mounted inside any containers

## What it detects

Any service whose `volumes:` list contains a container-runtime control socket — `docker.sock`, `containerd.sock`, `crio.sock`, or `podman.sock` — including read-only mounts (`:ro`) and rootless variants (`$XDG_RUNTIME_DIR/docker.sock`). Detection is substring-based, so atypical paths (e.g. a named volume literally called `docker.sock`) can produce false positives; suppress with a `reason:` if so.

## Why it matters

Mounting the Docker socket gives a container full root-level access to the host's Docker daemon. A compromised container can:

- Create new privileged containers
- Access data from all other containers
- Escape to the host entirely

Read-only mounts (`:ro`) do not mitigate this — `:ro` only affects the inode permissions on the socket file. The Docker API is read-write over any open connection regardless of the mount flag, and `docker run --privileged` is a single API call.

Rootless Docker and Podman sockets are slightly less catastrophic — escape lands you as the unprivileged daemon user, not host root — but they still grant full container-management privilege over every container that user controls. Treat them as the same severity unless you've verified the threat model.

## Fix

Use a Docker socket proxy that exposes only the API endpoints your service needs, and harden the proxy itself so it isn't the new weakest link:

```yaml
services:
  socket-proxy:
    image: tecnativa/docker-socket-proxy:0.3.0  # pin a version (CL-0004)
    environment:
      CONTAINERS: 1
      SERVICES: 0
      TASKS: 0
      POST: 0          # deny mutating endpoints unless required
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    read_only: true
    cap_drop:
      - ALL
    cap_add:
      - SETUID         # haproxy entrypoint switches users
      - SETGID
    security_opt:
      - no-new-privileges:true
    restart: unless-stopped
    networks:
      - proxy

  traefik:
    environment:
      DOCKER_HOST: tcp://socket-proxy:2375
    networks:
      - proxy
```

This is the fix recommended in canonical Traefik / portainer-with-proxy guides. The proxy itself still mounts the socket — that's why it must be at least as hardened as anything else holding that mount.

## When to suppress

- The service *is* the daemon-management tool you trust (Portainer, Watchtower) and you've accepted the blast radius. Suppress with a `reason:` naming the tool and the user/network boundary that contains it.

## See also

- [CL-0013](CL-0013.md) — `/var/run` host mount (parent directory of the socket)
- [CL-0011](CL-0011.md) — `cap_add: ALL` is functionally similar in blast radius
