diff --git a/.env.example b/.env.example index aec43adcf..971cf8b2b 100644 --- a/.env.example +++ b/.env.example @@ -66,3 +66,18 @@ INFOQUEST_API_KEY=your-infoquest-api-key # alias, or behind a different port). docker-compose already sets these. # DEER_FLOW_INTERNAL_GATEWAY_BASE_URL=http://localhost:8001 # DEER_FLOW_TRUSTED_ORIGINS=http://localhost:3000,http://localhost:2026 + +# ── Claude Code / Codex CLI subscription as a model provider (optional) ─────── +# If you configure a ClaudeChatModel / Codex model provider (or an ACP agent) +# that reuses your CLI subscription login, prefer passing a token via env over +# bind-mounting your whole ~/.claude / ~/.codex into the container. The Gateway +# credential loader reads these first, so no directory mount is needed. +# CLAUDE_CODE_CREDENTIALS_PATH points at a single .credentials.json (Claude) +# rather than the whole dir. docker-compose.cli-auth.yaml is the opt-in +# directory-mount fallback for adapters that need the full CLI config. +# ACP adapters often take their own env API key (e.g. ANTHROPIC_API_KEY) and +# need no mount at all — check the adapter's docs. See SECURITY.md. +# CLAUDE_CODE_OAUTH_TOKEN=your-claude-code-oauth-token +# ANTHROPIC_AUTH_TOKEN=your-anthropic-auth-token +# CLAUDE_CODE_CREDENTIALS_PATH=/path/to/.claude/.credentials.json +# CODEX_AUTH_PATH=/path/to/codex/auth.json diff --git a/SECURITY.md b/SECURITY.md index 459654a0a..d83e190e3 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -10,3 +10,32 @@ Currently, we have two branches to maintain: ## Reporting a Vulnerability Please go to https://github.com/bytedance/deer-flow/security to report the vulnerability you find. + +## CLI Credential Mounts (Claude Code / Codex) + +DeerFlow can reuse your Claude Code / Codex CLI subscription login as a model +provider (`ClaudeChatModel`, the Codex provider) or for ACP agents that run the +CLI in-container. The Compose stack used to bind-mount the **entire** `~/.claude` +and `~/.codex` directories (read-only) into the gateway container in **every** +configuration — exposing not just credentials but full conversation history, +per-project session data, and global CLI config. A gateway compromise (prompt +injection, tool/MCP misuse, RCE) would leak all of it. + +These directories are **no longer mounted by default**. Supply CLI credentials +with the least exposure that fits your setup: + +| Need | How | Exposure | +|------|-----|----------| +| Claude model provider | env `CLAUDE_CODE_OAUTH_TOKEN` / `ANTHROPIC_AUTH_TOKEN` (via `.env`), or `CLAUDE_CODE_CREDENTIALS_PATH` → a single mounted `.credentials.json` | none / one file | +| Codex model provider | env `CODEX_AUTH_PATH` pointing at a single mounted `auth.json` | one file | +| ACP agent | the adapter's own auth — many ACP adapters take an env API key (e.g. `ANTHROPIC_API_KEY` / `OPENAI_API_KEY`) and need no mount; use the opt-in `docker/docker-compose.cli-auth.yaml` overlay only if your adapter reads the full CLI config dir | none / full dir | + +The Gateway credential loader checks environment variables **before** the +default credential files, so the env-token paths need no bind mount at all. ACP +adapters authenticate independently of DeerFlow via their own documented env — +for example the common `claude-code-acp` adapter starts as +`ANTHROPIC_API_KEY=… claude-code-acp` and honors `CLAUDE_CONFIG_DIR` to redirect +its config directory, so it needs no `~/.claude` mount at all. Prefer the +adapter's documented env auth, and reach for the +`docker-compose.cli-auth.yaml` overlay only as a fallback for an adapter that +genuinely reads the full CLI config directory. diff --git a/docker/docker-compose-dev.yaml b/docker/docker-compose-dev.yaml index d36981a27..f06bdf803 100644 --- a/docker/docker-compose-dev.yaml +++ b/docker/docker-compose-dev.yaml @@ -148,19 +148,12 @@ services: - gateway-uv-cache:/root/.cache/uv # DooD: AioSandboxProvider runs inside the Gateway process. - /var/run/docker.sock:/var/run/docker.sock - # CLI auth directories for auto-auth (Claude Code + Codex CLI) - - type: bind - source: ${HOME:?HOME must be set}/.claude - target: /root/.claude - read_only: true - bind: - create_host_path: true - - type: bind - source: ${HOME:?HOME must be set}/.codex - target: /root/.codex - read_only: true - bind: - create_host_path: true + # 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 + # the Claude/Codex CLI login as a model provider or ACP agent, via the + # opt-in docker-compose.cli-auth.yaml overlay. Prefer an env token + # (CLAUDE_CODE_OAUTH_TOKEN, see .env.example / SECURITY.md). working_dir: /app environment: - CI=true diff --git a/docker/docker-compose.cli-auth.yaml b/docker/docker-compose.cli-auth.yaml new file mode 100644 index 000000000..ff5733ffd --- /dev/null +++ b/docker/docker-compose.cli-auth.yaml @@ -0,0 +1,36 @@ +# DeerFlow — CLI auth overlay (OPT-IN, NOT loaded by default) +# +# Bind-mounts the host Claude Code / Codex CLI config dirs into the gateway so: +# - ClaudeChatModel / Codex model providers can reuse the CLI subscription +# login (~/.claude/.credentials.json, ~/.codex/auth.json), and +# - ACP agents (acp_agents in config.yaml) that run the claude/codex CLI +# inside the container can read their config. +# +# SECURITY: these mounts expose the ENTIRE ~/.claude and ~/.codex dirs +# (conversation history, projects, global config, long-lived credentials) into +# the gateway container, read-only. A gateway compromise leaks all of it. That +# is why they are NOT mounted by default. +# +# Prefer passing only a token via env instead (no directory exposure): +# CLAUDE_CODE_OAUTH_TOKEN / ANTHROPIC_AUTH_TOKEN for Claude, CODEX_AUTH_PATH +# for a single Codex auth file — see .env.example and SECURITY.md. +# Use this overlay only when you need the full CLI config (e.g. ACP adapters +# that run the CLI in-container and read more than just the credential file). +# +# Manual use (works with both prod and dev compose): +# docker compose -f docker-compose.yaml -f docker-compose.cli-auth.yaml up -d +services: + gateway: + volumes: + - type: bind + source: ${HOME:?HOME must be set}/.claude + target: /root/.claude + read_only: true + bind: + create_host_path: true + - type: bind + source: ${HOME:?HOME must be set}/.codex + target: /root/.codex + read_only: true + bind: + create_host_path: true diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index 746bfe3ee..7370d0219 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -86,19 +86,12 @@ services: - ${DEER_FLOW_HOME}:/app/backend/.deer-flow # DooD: AioSandboxProvider starts sandbox containers via host Docker daemon - ${DEER_FLOW_DOCKER_SOCKET}:/var/run/docker.sock - # CLI auth directories for auto-auth (Claude Code + Codex CLI) - - type: bind - source: ${HOME:?HOME must be set}/.claude - target: /root/.claude - read_only: true - bind: - create_host_path: true - - type: bind - source: ${HOME:?HOME must be set}/.codex - target: /root/.codex - read_only: true - bind: - create_host_path: true + # 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 + # the Claude/Codex CLI login as a model provider or ACP agent, via the + # opt-in docker-compose.cli-auth.yaml overlay. Prefer an env token + # (CLAUDE_CODE_OAUTH_TOKEN, see .env.example / SECURITY.md). working_dir: /app environment: - CI=true