Skip to content

no-broad-bind-mount

Bind-mounting /, $HOME, ~/.ssh, or a parent directory into a Compose service exposes far more of the host than the service needs. Mount the narrowest path, read-only.

On this page

- ~:/home/agent is the fastest way to give a container access to something under your home directory, and it also gives it everything else: SSH keys, cloud credentials, browser profiles, every other project. This rule flags bind mounts whose host source is the root filesystem (/, C:\), the home directory (~, $HOME), a hidden directory under it (~/.ssh, ~/.aws, ~/.docker, …), a parent of the Compose project (../), or a host system directory (/etc, /proc, /run, /home, …). Relative paths inside the project and narrow absolute paths like /opt/models pass. It understands both the short and long volumes syntax and resolves ${VAR:-default} interpolation to its default.

What the rule catches

compose.yaml — the whole home directory and cloud credentials
services:
  agent:
    image: my-agent:1.2.0
    volumes:
      - ~:/home/agent
      - ~/.aws:/root/.aws

Scanning this file reports:

⚠ WARN [docker-doctor/no-broad-bind-mount]
  Service 'agent' bind-mounts '~', the whole home directory. Everything under it is readable by the container, and a writable mount is the foothold for VM-escape bugs like CVE-2026-77179.

Why it matters

A bind mount is a hole in the container boundary by design, and its size is whatever directory you name. Mounting ~ hands over ~/.ssh, ~/.aws, and ~/.docker/config.json, so one compromised dependency in the service becomes a credential theft on the host. The problem got sharper when Docker Desktop and Docker Sandboxes moved to running containers in a VM: the file server for a bind mount runs on the host, and bugs in it turn a writable mount into a full VM escape. CVE-2026-77179 did exactly that with an open file, a deleted directory, and a symlink, all from inside a mounted folder. A VM does not protect the host from a mount it shares with the guest; the only reliable defenses are mounting less and mounting read-only.

How to fix it

Mount the narrowest directory the service actually reads (./data, not ~ or /), and add :ro unless the service must write to it. Host paths the service only needs at build time belong in the image instead.

compose.yaml — one project directory, credentials read-only
services:
  agent:
    image: my-agent:1.2.0
    volumes:
      - ./workspace:/home/agent/workspace
      - ./config/aws:/root/.aws:ro

Two things usually fix a broad mount:

  • Narrow the source: mount ./data or /srv/app/uploads, not the directory that happens to contain it. For credentials, copy the one profile the service needs into a project-local directory that is gitignored, or hand the value over as a Compose secrets entry.
  • Make it read-only: append :ro (short syntax) or set read_only: true (long syntax). The prefer-read-only-bind-mount rule tracks that half.

Host-monitoring agents (cAdvisor, node exporters) legitimately mount /proc and /sys. Keep those read-only, and set this rule to off in docker-doctor.config.json if the warning is noise in a project dedicated to host monitoring.

The Docker socket is a special case with its own rule, no-docker-socket-mount, and is not reported here.

Rule details

  • Rule keydocker-doctor/no-broad-bind-mount
  • Category — Compose
  • Default severitywarning
  • Applies to — Docker Compose files

Explain this rule from the CLI:

npx @docker-doctor/cli@latest rules explain docker-doctor/no-broad-bind-mount

Change its severity — or turn it off — in your config file:

// docker-doctor.config.ts
export default {
  rules: {
    "docker-doctor/no-broad-bind-mount": "off",
  },
};

Severity affects the health score: error findings cost more points than warning, and info costs the least.