fix(security): mount host Docker socket only in aio (DooD) sandbox mode (#3517)

* fix(security): mount host Docker socket only in aio (DooD) sandbox mode

The default Compose stack mounted /var/run/docker.sock read-write into the
root gateway container in every sandbox mode, including the default `local`
mode that never uses it -- an unnecessary host-escape surface (DooD =
root-equivalent host control). deploy.sh already gated the socket *check* on
sandbox_mode != local, but the Compose files mounted it unconditionally.

Move the socket mount to an opt-in docker/docker-compose.dood.yaml overlay
that deploy.sh / docker.sh append only when detect_sandbox_mode() returns
`aio`. Default (local) and provisioner/Kubernetes modes no longer expose the
host daemon. Tighten the socket existence check from != local to == aio.
Document the DooD threat model in SECURITY.md.

Reported by @greatmengqi.

* refactor(docker): address review on socket-hardening PR

- docker.sh: use absolute path for the dood overlay (match deploy.sh, drop cwd dependency)
- deploy.sh: drop now-dead DEER_FLOW_DOCKER_SOCKET exports in down/build paths
- docker-compose.yaml: fix stale header comment to point at the overlay

Addresses codex + reviewer feedback on #3517.

---------

Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
This commit is contained in:
Xinmin Zeng
2026-06-14 11:03:50 +08:00
committed by GitHub
parent 474c89bac2
commit 5d61718c80
6 changed files with 96 additions and 15 deletions
+4 -2
View File
@@ -146,8 +146,10 @@ services:
# On macOS/Docker Desktop, uv may fail to create symlinks inside shared
# host directories, which causes startup-time `uv sync` to crash.
- gateway-uv-cache:/root/.cache/uv
# DooD: AioSandboxProvider runs inside the Gateway process.
- /var/run/docker.sock:/var/run/docker.sock
# DooD: the host Docker socket is NOT mounted by default. It is added only
# for aio (pure-DooD) sandbox mode via the opt-in docker-compose.dood.yaml
# overlay (appended by scripts/docker.sh). See SECURITY.md.
# CLI auth dirs (Claude Code / Codex) are NOT mounted by default: they
# expose the entire ~/.claude and ~/.codex (history, projects, global
# config, credentials) into the container. Mount them only when you use
+25
View File
@@ -0,0 +1,25 @@
# DeerFlow — Docker-out-of-Docker (DooD) overlay (OPT-IN, NOT loaded by default)
#
# Mounts the host Docker socket into the gateway container so that
# AioSandboxProvider running in pure-Docker mode — config.yaml:
# sandbox.use: deerflow.community.aio_sandbox:AioSandboxProvider
# with NO provisioner_url — can start per-thread sandbox containers via the
# host Docker daemon.
#
# SECURITY: the host Docker socket grants the gateway container
# root-equivalent control of the host. Only load this overlay when you have
# explicitly chosen aio (DooD) sandbox mode and accept that trade-off. The
# default LocalSandboxProvider and the provisioner/Kubernetes mode do NOT need
# it and never load this file. See SECURITY.md for the full threat model.
#
# scripts/deploy.sh and scripts/docker.sh append this overlay automatically
# only when detect_sandbox_mode() returns "aio". Manual use:
# docker compose -f docker-compose.yaml -f docker-compose.dood.yaml up -d
#
# Compatible with both docker-compose.yaml (prod) and docker-compose-dev.yaml
# (dev): both define a `gateway` service, and Compose merges this volume entry
# onto it. DEER_FLOW_DOCKER_SOCKET defaults to /var/run/docker.sock.
services:
gateway:
volumes:
- ${DEER_FLOW_DOCKER_SOCKET:-/var/run/docker.sock}:/var/run/docker.sock
+5 -3
View File
@@ -13,7 +13,7 @@
# DEER_FLOW_CONFIG_PATH — path to config.yaml
# DEER_FLOW_EXTENSIONS_CONFIG_PATH — path to extensions_config.json
# DEER_FLOW_SKILLS_PATH — skills dir, default $DEER_FLOW_PROJECT_ROOT/skills
# DEER_FLOW_DOCKER_SOCKET — Docker socket path, default /var/run/docker.sock
# DEER_FLOW_DOCKER_SOCKET — Docker socket path for aio/DooD mode, default /var/run/docker.sock (used only by the opt-in docker-compose.dood.yaml overlay)
# DEER_FLOW_REPO_ROOT — repo root (used for skills host path in DooD)
# BETTER_AUTH_SECRET — required for frontend auth/session security
# DEER_FLOW_INTERNAL_AUTH_TOKEN — shared internal Gateway auth token for multi-worker IM channels
@@ -84,8 +84,10 @@ services:
- ${DEER_FLOW_EXTENSIONS_CONFIG_PATH}:/app/backend/extensions_config.json:ro
- ../skills:/app/skills:ro
- ${DEER_FLOW_HOME}:/app/backend/.deer-flow
# DooD: AioSandboxProvider starts sandbox containers via host Docker daemon
- ${DEER_FLOW_DOCKER_SOCKET}:/var/run/docker.sock
# DooD: the host Docker socket is NOT mounted by default. It is added only
# for aio (pure-DooD) sandbox mode via the opt-in docker-compose.dood.yaml
# overlay (appended by scripts/deploy.sh). See SECURITY.md.
# CLI auth dirs (Claude Code / Codex) are NOT mounted by default: they
# expose the entire ~/.claude and ~/.codex (history, projects, global
# config, credentials) into the container. Mount them only when you use