沙盒化
运行时可以将工具调用封装在操作系统级别的沙箱中,从而将文件系统访问限制在工作区内,并移除对父进程机密信息的访问权限。这与自治系统和命令允许列表不同:后者是决定工具是否可以运行的_策略_层;而沙箱是_机制_层,用于在工具运行时限制其可以访问的范围。
沙盒设置位于风险配置文件中。每个 agent 通过 agents.<alias>.risk_profile 指向一个风险配置文件;agent 的沙盒启用状态/后端将从该配置文件中读取。
**CLI 模型提供商(例如 grok_cli):**外部 CLI 位于 ZeroClaw 原生工具审批路径之外。上文的风险配置沙箱无法约束它。因此,grok_cli ACP 提供商默认注入 --sandbox strict、--permission-mode dontAsk,并使用空的内置工具集,同时拒绝 ACP 权限请求(当 CLI 提供 reject_once 时选择该选项,否则取消请求)。别名 extra_args 中的显式绕过标志则选择请求的 allow_once 选项;这不会禁用 Grok 已启用的操作系统沙箱,也不会覆盖其拒绝规则。其他权限模式仍会安全失败。请参阅目录 → Grok Build CLI。
sandbox_enabled = false(或 sandbox_backend = "none")会禁用该配置文件额外的操作系统级沙箱封装层。在原生运行时下,这会使工具不具备操作系统沙箱。在 [runtime] kind = "docker" 下,Docker 运行时仍是容器边界,并被报告为 docker-runtime;这些设置会阻止第二个沙箱容器封装运行时自身的 docker run。有关如何将风险配置文件纳入其余配置,请参阅规范的最小可运行示例。
自动检测
sandbox_backend = "auto" 在启动时选择最佳可用后端:
| 平台 | 首选顺序 |
|---|---|
| Linux | Landlock(内核 5.13+)→ Bubblewrap → Firejail → Docker → 无 |
| macOS | Seatbelt(sandbox-exec,原生)→ Docker → 无 |
| Windows | AppContainer(实验性)→ Docker → 无 |
| 任何 | Docker(如果守护进程可达)→ 无 |
要强制使用特定后端,请将 sandbox_backend 设置为上面列出的字面值之一。
沙箱所限制的内容
文件访问
- 读取访问权限:仅限于工作区、
/usr、/lib、/etc(只读)以及明确列出的额外路径。 - 写入权限:仅限于工作区和
/tmp。 - 禁止路径:来自
[risk_profiles.<alias>].forbidden_paths的绝对组件前缀规则。竞争的允许前缀和拒绝前缀采用最具体匹配优先级,匹配程度相同时拒绝优先;请参阅 Autonomy 路径规则。
网络
默认情况下,沙盒化工具拥有完整的网络出站能力,但不允许入站监听。各后端的注意事项如下:
- Landlock 不控制网络,它仅作用于文件系统。
- 配置后,Bubblewrap 和 Firejail 可以阻止网络访问。
- 当
[runtime].kind = "docker"时,Docker 容器网络模式遵循[runtime.docker].network设置。
特定工具的网络访问控制(browser、HTTP、web_fetch)位于这些工具各自的配置块中([browser].allowed_domains、[http_request].allowed_domains、[web_fetch].allowed_domains)。
对于 http_request,私有/本地目标默认仍处于阻止状态。使用 [http_request].allowed_private_hosts 仅允许指定的私有/本地主机(如 localhost 或 10.0.0.1),同时保持 [http_request].allowed_domains 非空;allowed_domains = [] 仍会禁用请求。现有的 [http_request].allow_private_hosts = true 设置仍作为更宽泛的兼容性选项。
环境
沙箱仅传递 [risk_profiles.<alias>].shell_env_passthrough 中列出的环境变量。继承的密钥除非显式传递,否则不会进入沙箱化的工具。
进程限制
每个工具的实际运行超时设置位于该工具自身的配置块中([shell_tool].timeout_secs 等)。Docker 专属限制(内存、CPU)则位于 [runtime.docker] 中,前提是该代理的运行时类型设置为 docker:
Shell 二进制文件
默认情况下,原生运行时通过 /bin/sh 调用命令。将 [runtime].shell 设置为使用其他 shell:
[runtime]
shell = "bash" # 通过 PATH 解析,或使用绝对路径
在 Unix 上,POSIX 兼容的 shell 会以 <shell> -c "<command>" 的形式调用。powershell/pwsh 会在每个受支持的桌面主机上选择 PowerShell 语法和策略,并以 <interpreter> -NoProfile -NonInteractive -Command <command> 的形式运行,因此配置文件脚本无法绕过策略重新定义命令,提示也无法阻止执行。该值必须是 PATH 中找到的裸命令名(例如 "bash" 或 "pwsh"),或可执行文件的绝对路径(例如 "/bin/bash");带分隔符的相对路径(例如 "./sh"、"bin/sh")会被拒绝。运行时启动时会对其进行验证,因此 shell 为空、缺失、不可执行或格式错误时,会快速失败并显示清晰错误,而不会在执行第一个命令时才出错。未设置时默认为 "sh"。
在 Windows 上,该值根据其文件名选择解释器系列:
[runtime]
shell = "pwsh" # PowerShell 7+ -> pwsh -NoProfile -NonInteractive -Command <cmd>
# shell = "powershell" # Windows PowerShell 5.x
# shell = "cmd" # 或留空 -> cmd.exe /C "<cmd>" (默认)
powershell 和 pwsh(作为通过 PATH 解析的裸名称,或诸如 "C:\\Program Files\\PowerShell\\7\\pwsh.exe" 这样的绝对路径)通过 PowerShell 运行;其他任何值(包括默认的 sh 和显式的 cmd)均通过 cmd.exe /C 运行,与历史行为一致。仅拒绝空值或仅包含空白的值;解释器在启动进程时定位。
shell 工具、由 shell 支持的技能工具以及 cron/调度 shell 作业都使用此运行时选择。运行时还会将 shell 方言报告给安全策略,因此策略会验证将执行该命令的同一种语言。
向模型报告的是同一个运行时选择结果。系统提示中的 ## Runtime 行包含一个 Shell: 字段,用于标明已配置的解释器(bash、zsh、pwsh、powershell、cmd);当已注册的工具接收模型编写的命令(shell、cron_add、cron_update、schedule)时,## Shell 部分会列出该方言所接受的命令形式,因此模型在 PowerShell 下会编写 Get-ChildItem,在 cmd.exe 下会编写 dir /a,而不是根据操作系统名称进行猜测。两者都来自用于构建命令的同一个适配器,因此报告的 Shell 不会与实际执行的 Shell 发生偏差。无法访问 Shell 的运行时(例如 WASM)会省略这两项。安全部分中的删除建议也会遵循相应的方言:只有在存在 trash 的地方才会建议使用它。
PowerShell 策略接受受限语法:简单命令调用、普通或带引号的参数,以及管道。类似 $PSHOME 和 $PSVersionTable.PSVersion 的简单变量读取仅限于独立的 Write-Output/echo 命令,因此无法向后续命令隐藏文件系统路径。表达式和其他调用形式(包括子表达式、括号、脚本块、类型字面量/静态方法调用、调用运算符、重定向、语句分隔符、反引号转义、$env:NAME 等作用域变量、PowerShell 提供程序路径、直接脚本执行和嵌套命令解释器)均被归类为高风险。仅限 PowerShell 的命令名称不会添加到跨方言默认允许列表中;将所需的 cmdlet 添加到 allowed_commands,或者启用 "*",并配置相应的审批和高风险设置。已知的变更 cmdlet 遵循中/高风险审批门槛;未知的裸命令和 Verb-Noun cmdlet 默认属于高风险。
Cron shell 作业在验证和执行时都会继承全局运行时边界。Native 作业使用配置的原生 shell,而 Docker 作业则通过配置的镜像、挂载、网络、CPU、内存和只读根目录设置运行。cron 条目存储的是命令,而不是复制的运行时或方言。守护进程重新加载并重新创建调度器和工具注册表后,现有作业因此会在下一次运行时使用新加载的 [runtime] 配置。计划的 cron 运行会重新验证,绝不会预先批准。
仅适用于原生运行时类型。Docker 使用其容器的 shell,而 Android(始终为 /system/bin/sh)会忽略此设置,且不会对其进行验证。
各后端的说明
Landlock
Linux 原生路径。零配置,内核强制实施,开销极低。需要内核 5.13 或更高版本。
限制:
- 无网络限制:Landlock 仅控制文件系统访问。
forbidden_paths是通过基于路径的规则强制执行的,而非基于 inode,因此巧妙构造的符号链接有时可以绕过限制(我们会在交给 Landlock 之前解析链接以缓解此问题)。
Bubblewrap (bwrap)
基于用户命名空间的 Flatpak 沙箱。可限制文件系统访问并阻止网络连接。需要安装 bubblewrap。
Debian/Ubuntu
sudo apt install bubblewrap
Arch
sudo pacman -S bubblewrap
Fedora
sudo dnf install bubblewrap
Firejail
基于 SUID 的沙箱。较旧但广泛可用。
sh
sudo apt install firejail
Firejail 的默认配置文件权限较为宽松;ZeroClaw 会应用自定义配置文件。可在风险配置文件上通过 firejail_args 传递额外参数。
Docker
可在任何支持 Docker 的环境中运行。Docker 运行时类型([runtime] kind = "docker")会在临时容器中运行每次 shell 调用;有关镜像和资源控制,请参阅上方的 [runtime.docker] 配置块。
sh
docker build -t zeroclaw-sandbox:local dev/sandbox/ # 构建捆绑的工具包镜像
优点:隔离性强,适用于任何操作系统。缺点:每次调用时容器启动开销较大(100–500 毫秒)。最适合对开销可接受的生产环境部署。
安全带 (macOS)
原生 macOS 沙箱(sandbox-exec)。配置文件采用 SBPL 格式:ZeroClaw 内置了一个用于工具运行。支持 macOS 10.11+。
限制:某些 CLI 工具(较旧版本的 git、部分通过 Homebrew 链接的二进制文件)无法与 Seatbelt 的文件访问规则正常协作。如果你在 macOS 上看到 agent 的 shell 调用返回 “Operation not permitted” 错误,说明该工具需要更广泛的文件系统访问权限:可以考虑改用 Docker。
none
无沙盒机制。工具以 ZeroClaw 服务用户的完整权限运行。这正是 YOLO 模式所启用的特性。明确、显著且有意为之。
故障排除
- 启动时出现 “Sandbox backend unavailable”:请检查
zeroclaw service status和 journal 日志;自动检测会记录它尝试过哪些后端。 - 工具在开发环境正常但在服务中失败:服务用户通常与 CLI 用户不同。请确认两者都拥有所需的沙箱相关权限(Landlock:无;Bubblewrap:启用 userns;Docker:服务用户在
docker组中)。 - 在 Docker 运行时上工具调用缓慢:首次调用会拉取镜像,后续调用则很快。可使用
docker pull <image>预先拉取镜像。
代码参考
- 检测:
crates/zeroclaw-runtime/src/security/detect.rs - 后端:
crates/zeroclaw-runtime/src/security/sandbox/(每个后端一个文件) - 架构:
crates/zeroclaw-config/src/schema.rs中的RiskProfileConfig和DockerRuntimeConfig