Docker 内启用 Claude Code 沙箱的陷阱
作者测试发现,默认 Docker 容器中的 bubblewrap 因无法创建命名空间而启动失败,并提醒沙箱失败后可能回退为无沙箱执行。文章还区分内置沙箱仅覆盖 Shell 命令的边界,以及不同操作系统的支持情况。
AI 深度解读
把 Claude Code 放进 Docker,再打开 /sandbox,看起来像多加了一层保险。作者实际测到的却是:默认容器里,负责 Linux 沙箱隔离的 bubblewrap 连启动都失败了,而 Claude Code 在沙箱不可用时,默认仍会执行命令。
这篇最有价值的提醒,是把「打开了沙箱选项」和「命令确实受到隔离」分开看。对准备让 AI 自动跑测试、改代码,甚至跳过权限确认的程序员,这个区别直接决定了哪些文件和凭据会暴露。
/sandbox 管的是命令,不是整个 Claude Code
Claude Code 的内置沙箱会约束 Bash、PowerShell、Monitor 命令,以及这些命令启动的所有子进程。Linux 和 WSL2 使用 bubblewrap,macOS 使用 Seatbelt,原生 Windows 不支持。
子进程也受限很关键。Claude 启动的测试、构建脚本或 Node 脚本,即使内部藏了删除操作,也不能随意写入隔离范围之外的目录。默认可写范围包括项目、临时目录和额外放行的路径,网络则通过代理限制到获准域名。
但这个边界没有罩住整个工具。
Claude 自己的 Read、Edit、Write 文件工具在内置沙箱之外,依靠权限规则约束;denyRead 也挡不住 Read 工具。MCP servers、hooks、plugin monitors 和状态栏命令同样不受这层沙箱保护。用户通过 ! 输入的命令、excludedCommands 中的命令,以及失败后获准在沙箱外重试的命令,也有各自的绕行路径。
项目内还有部分受保护的配置,例如 .claude 下的设置与 hooks、.mcp.json、.vscode、.idea 和 .git 内的部分配置。但普通项目文件依然可以被修改、删除。作者通过 sandbox runtime 执行项目内目录的 rm -rf,删除成功了。
内置沙箱主要保护项目周围的环境,不能承担项目备份的职责。

Docker 里再套沙箱,为什么启动不了
作者最后检查日期是 2026 年 10 月 30 日,对应 Claude Code 2.1.314、sandbox runtime 0.0.81。测试环境是 Windows 11 上的 Docker Desktop,使用 WSL2 backend,镜像为 node:22-bookworm-slim,bubblewrap 版本为 0.8.0。
在默认容器内,以非 root 的 node 用户运行沙箱命令,全部遇到同一个错误:bwrap: No permissions to create new namespace。
作者将原因定位到 Docker 默认的 seccomp 配置:它拦住了非特权进程创建所需的用户命名空间。命名空间是 Linux 用来隔开进程所见环境的一种机制,bubblewrap 需要先建立这个边界,才能执行里面的命令。
打开 enableWeakerNestedSandbox 没有改善。Claude Code 对应的配置是 sandbox.enableWeakerNestedSandbox,文档将它用于另一类容器内错误 Can't mount proc,不能据此认为它能解决所有嵌套沙箱问题。
加上 --security-opt seccomp=unconfined 后,bubblewrap 可以启动。不过这同时撤掉了容器的一项保护,不能只把它理解成「修好了内层沙箱」。
这里还有一条实验边界:作者没有在容器里登录 Claude Code,实际运行的是 sandbox runtime。因此,直接证据是 bubblewrap 和 runtime 在该环境中的行为;关于 Claude Code 启动失败后的处理,则来自作者引用的官方文档。原文也没有完整展示放开 seccomp 后的逐项结果表,不能补出一份全面通过的测试清单。
先关闭失败降级,再验证隔离有没有生效
作者提出的配置里,最重要的不是 enabled,而是沙箱不可用时如何处理。
下面这段配置同时开启沙箱、阻止启动失败后降级,以及关闭沙箱外重试:
{
"sandbox": {
"enabled": true,
"failIfUnavailable": true,
"allowUnsandboxedCommands": false,
"network": {
"allowedDomains": ["registry.npmjs.org", "github.com"]
}
}
}
最该先看的是 "failIfUnavailable": true:按原文描述,缺少它时,沙箱启动不了,Claude Code 默认会继续执行未沙箱化的命令。allowUnsandboxedCommands: false 则关闭失败后到沙箱外重试的出口,否则匹配的 allow 规则可能直接放行重试。
通过 /sandbox 启用,设置会写入项目的 .claude/settings.local.json;希望所有项目生效,可配置 ~/.claude/settings.json。Auto-allow 模式减少沙箱内命令的确认,但 deny 规则、Bash(git push *) 这类规则和危险删除检查仍然有效;Regular permissions 保留命令确认。
Linux、WSL2 要先安装依赖:Ubuntu、Debian 使用 sudo apt-get install bubblewrap socat,Fedora 使用 sudo dnf install bubblewrap socat。macOS 无须安装这两项。
验证时,让 Claude 执行 touch ~/sandbox-probe。Linux、WSL2 应报 Read-only file system,macOS 应报 Operation not permitted。不要自己通过 ! 执行,那没有验证到同一条路径,也不要接受沙箱外重试。
Windows 用户还需要分清 WSL2 与原生环境。可用 wsl --install -d Ubuntu 安装发行版,通过 wsl -l -v 检查版本;WSL1 会报告 Sandboxing requires WSL2。Ubuntu 24.04 及以后还可能受到 AppArmor 限制,可检查 sysctl kernel.apparmor_restrict_unprivileged_userns。返回 1 时,需按文档处理针对 bwrap 的限制;从 Claude Code 2.1.310 起,/sandbox 会指出这一原因。
我的判断
作者最有说服力的地方,是把「权限确认」「命令隔离」「整个进程隔离」拆开了。确认弹窗解决是否批准操作的问题,系统隔离限制操作最终能碰到哪里,两者不能互相替代。
无人值守运行 --dangerously-skip-permissions 时,把整个 Claude Code 放进非 root 容器、VM 或 sandbox runtime,比仅依赖 /sandbox 更符合其隔离需求。作者测试过的 Dockerfile 如下:
FROM node:22-bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends git ca-certificates \
&& rm -rf /var/lib/apt/lists/*
RUN npm install -g @anthropic-ai/claude-code
USER node
RUN mkdir -p /home/node/.claude
ENV CLAUDE_CONFIG_DIR=/home/node/.claude
WORKDIR /workspace
重点看 USER node 和 CLAUDE_CONFIG_DIR:前者避免以 root 运行,后者配合配置卷持久化状态。作者测到 node uid=1000,镜像大小为 1.18 GB;root 执行跳过权限参数会被拒绝,非 root 执行则走到未登录提示。
但「大多数人把容器当作边界即可」仍是作者的取舍建议,没有容器、VM、嵌套沙箱之间的系统性对照数据。一次 Docker Desktop 实测,也不足以断言所有 Docker 环境都无法嵌套运行。
容器本身也不是自动安全。挂载到 /workspace 的项目会双向同步,容器删文件,宿主机也会丢文件;恶意代码还可能把容器可读内容,包括 Claude Code 凭据,通过网络发出去。
另一条路线是 npm install -g @anthropic-ai/sandbox-runtime 后执行 srt claude,把整个进程纳入边界。不过 0.0.81 仍属 beta research preview;缺失 ~/.srt-settings.json 时它也会按默认设置启动,启动成功不能证明自定义规则已加载。
能拿来做什么
- 日常让 Claude 跑前端测试或 Node 脚本时,先配置
failIfUnavailable和allowUnsandboxedCommands,再用touch ~/sandbox-probe检查实际隔离效果,别只确认/sandbox已打开。 - 长时间自动改代码前,先提交当前工作。使用 Docker 时,只挂载任务需要的项目目录,并把挂载目录里的文件仍然可能被删除纳入预期。
- 需要跳过权限确认时,采用非 root 容器等完整进程隔离方案。Docker 可用
docker build -t claude-sandbox .构建,再执行docker run -it --rm -v "$PWD:/workspace" -v claude-config:/home/node/.claude claude-sandbox claude;PowerShell 将$PWD换成${PWD}。 - 处理不可信仓库时,同时限制网络出口。
registry.npmjs.org、github.com只是原文配置示例,应按真实依赖调整;不要为了让 bubblewrap 启动,就直接把seccomp=unconfined当作通用修复。