
OpenClaw 沙箱:让 AI 在笼子里动手
谁都知道 AI agent 能做事。问题是,它做的事,你兜不兜得住?
不开沙箱的时候,agent 跟你共享一台电脑。它执行的 shell 命令,直接跑在你的操作系统上。它读写的文件,就是你硬盘上的真实文件。它跑的进程,和你自己开的进程没有任何区别。模型说一句 rm -rf /important-stuff,你的文件就真没了。
沙箱做的事情只有一件:在你的电脑上造一个假的小电脑,让 agent 在里面跑。
默认后端是 Docker。开启沙箱后,OpenClaw 启动一个 Docker 容器,基于精简的 Debian 镜像 openclaw-sandbox:bookworm-slim。agent 要执行工具的时候,命令不发给你的主机,而是发到容器里面。
容器有自己独立的三样东西:
- 文件系统:容器里的
/是它自己的根目录,不是你主机的。你的~/Documents、~/.ssh、~/.openclaw,对它来说默认不存在 - 进程空间:容器里的进程跟你主机上的进程互相看不到。agent 执行
ps aux,只能看到容器内自己的进程 - 网络:默认没有网络(
docker.network: "none")。agent 在沙箱里跑curl或者apt-get都会失败,它连不上任何外部地址
Gateway 进程始终在你的主机上运行,不受沙箱影响。沙箱隔离的,只是 agent 的工具执行。
这不是完美的安全边界。Docker 容器逃逸在极端情况下确实存在。但是它实实在在地把"模型犯蠢时的爆炸半径"从整台电脑缩小到了一个容器。够不够用?看你的场景。但总比裸奔强。
拿走了什么,留下了什么
理解沙箱,关键在一个字:界。什么被挡在外面了,什么还能通行。
拿走的
| 能力 | 没有沙箱 | 有沙箱 |
|---|---|---|
| 文件系统 | agent 看得到你主机上所有文件 | 只看得到容器内的文件系统,你的真实文件默认不可见 |
| 网络访问 | agent 能访问任何地址 | 默认无网络,需手动设 docker.network: "bridge" |
| 进程可见性 | agent 看得到主机所有进程 | 只看得到容器内自己的进程 |
| 系统命令 | agent 跑得了主机上任何命令 | 只跑得了容器镜像里有的命令,默认连 Node、Python、curl 都没有 |
| 环境变量 | agent 读得到主机的 process.env | 沙箱不继承主机环境变量,API key 要通过 sandbox.docker.env 显式传入 |
| 持久化 | agent 写的文件留在主机上 | 容器销毁,文件跟着没了,除非通过绑定挂载写回主机 |
没有拿走的
这些在沙箱内照常工作:
exec(执行命令):能跑,只是跑在容器里。镜像里有bash、ls、cat、grep,就能用read(读文件):能读容器内的文件。配了workspaceAccess: "ro"或"rw",也能读到挂载进来的工作区write/edit/apply_patch(写文件):能写容器内的文件。workspaceAccess: "rw"时,写操作直接反映到你的真实工作区process(进程管理):容器内的进程照常管理- 会话工具(
sessions_list、sessions_send等):Gateway 级别的东西,不受沙箱限制 - 消息发送:agent 发 WhatsApp、Telegram 的能力不受影响,消息路由在 Gateway 侧处理
- 模型推理:沙箱不管脑子,只管手脚
一句话讲清楚:沙箱限制的是 agent 在哪动手、能碰什么文件,不限制它说话和思考。
工作区访问的三档开关
沙箱和你真实文件之间的关系,由 workspaceAccess 精确控制。三档:
| 设置 | 能看到什么 | 能改什么 |
|---|---|---|
"none"(默认) | 只有沙箱内部的 ~/.openclaw/sandboxes | 只能改沙箱内部的文件 |
"ro" | 你的工作区以只读方式挂载到 /agent | 能读你的文件,但 write/edit/apply_patch 被禁用 |
"rw" | 你的工作区以读写方式挂载到 /workspace | 能读写你的真实文件,沙箱此时主要隔离进程和网络 |
"none" 模式下,OpenClaw 会把 agent 需要的 skills 文件镜像到沙箱内,让 read 工具照样读得到。入站媒体文件也会被复制到沙箱的 media/inbound/ 目录。
默认配置这么严,agent 不是废了?
默认开箱确实很严:没网络、看不到你的文件、镜像里连 curl 都没有。什么都不调的话,agent 能做的事非常有限。
这是故意的。OpenClaw 的思路是:默认给最小权限,你按需逐项打开。每一项限制都对应一个旋钮。
要操作你的项目文件?
workspaceAccess 从 "none" 改成 "rw"。agent 就能读写你的工作区了。
{ sandbox: { workspaceAccess: "rw" } }
只需要读不需要写,用 "ro",更稳妥。
要装包、调 API、访问网络?
docker.network 从 "none" 改成 "bridge"。容器就有网了。
{ sandbox: { docker: { network: "bridge" } } }
容器里缺命令?
默认 Debian 精简镜像只有最基本的 shell 工具。两条路:
- 临时装:用
setupCommand在容器创建时装一次,前提是先开网络 - 换镜像:用
sandbox-common-setup.sh构建一个带 curl、jq、nodejs、python3、git 的镜像,或者自己烤一个
需要访问主机上特定目录?
用 docker.binds 把指定目录挂进容器。
{ sandbox: { docker: { binds: ["/home/user/data:/data:ro"] } } }
有一个命令确实需要在主机上跑?
用 elevated 模式。沙箱里的 agent 可以临时把 exec 提升到主机执行:
/elevated on # 当前会话的 exec 跑在主机上,需要审批
/elevated full # 跳过审批
实际用起来的典型搭配
大部分人不会用默认最严的配置。根据用途选一个合理的组合就好:
| 用途 | workspaceAccess | network | 说明 |
|---|---|---|---|
| 家庭群机器人 | "none" | "none" | 纯聊天,不碰文件不碰网络 |
| 帮你读代码的助手 | "ro" | "none" | 能读项目文件,不能改,不能联网 |
| 跑测试的开发助手 | "rw" | "bridge" | 能读写项目、装依赖、跑测试 |
| 全功能个人助手 | "rw" | "bridge" + 自定义镜像 | 接近不开沙箱的体验,但进程和系统层面仍然隔离 |
所以沙箱不是"开关一扔,agent 变废物"。它是一套可调的限制,默认最严,你按信任程度逐项放开。核心价值在于:即使你放开了文件读写和网络,agent 的进程空间、系统目录、其他用户的文件,仍然是看不到的。
三个核心配置维度
沙箱的行为由三个维度决定:模式、范围、后端。搞清楚这三个,配置就不会乱。
模式(mode):什么时候启用沙箱
通过 agents.defaults.sandbox.mode 控制:
| 模式 | 行为 |
|---|---|
"off" | 不沙箱,所有工具直接在主机跑 |
"non-main" | 只对非主会话沙箱。群组和频道的会话天然是非主会话,会被沙箱 |
"all" | 所有会话都沙箱 |
有一个坑要留意:"non-main" 模式判断的是 session.mainKey(默认 "main"),不是 agent id。群组和频道的会话有自己的 key,会被当作 non-main 而隔离。你在群组里发现工具被意外限制了,原因就在这里。想让某个 agent 永远不沙箱,直接写 mode: "off"。
范围(scope):创建多少个容器
通过 agents.defaults.sandbox.scope 控制:
| 范围 | 行为 |
|---|---|
"session"(默认) | 每个会话一个容器 |
"agent" | 每个 agent 一个容器 |
"shared" | 所有被沙箱的会话共享一个容器 |
怎么选看隔离需求。"session" 最安全,会话间完全隔离。"shared" 最省资源。多 agent 场景下,"agent" 通常最合理。
后端(backend):用什么跑沙箱
通过 agents.defaults.sandbox.backend 控制:
| 后端 | 适用场景 |
|---|---|
"docker"(默认) | 本地 Docker 容器,完全隔离 |
"ssh" | 任意 SSH 可达的远程主机 |
"openshell" | OpenShell 托管的远程沙箱 |
大部分人用 Docker 就够了。
从零开始设置 Docker 沙箱
第一步:构建沙箱镜像
最小镜像:
想看更多实战拆解?
AI、工程与实验,每月 1–2 封。
无垃圾邮件,随时取消。
scripts/sandbox-setup.sh
出来的是 openclaw-sandbox:bookworm-slim,基于 Debian,非常精简。
需要常用工具(curl、jq、nodejs、python3、git)的话:
scripts/sandbox-common-setup.sh
出来的叫 openclaw-sandbox-common:bookworm-slim。
第二步:最小配置
在 ~/.openclaw/openclaw.json 里写:
{
agents: {
defaults: {
sandbox: {
mode: "non-main",
scope: "session",
workspaceAccess: "none",
},
},
},
}
这是最保守的配置:只沙箱非主会话,每会话一个容器,不让容器看到你的真实文件。
第三步:验证
openclaw sandbox explain
这条命令打印出当前生效的沙箱模式、范围、工具策略。对不对,看这里就知道。
自定义 Docker 镜像和 setupCommand
默认的 bookworm-slim 镜像很精简,连 Node 都没有。你的 skill 需要特定运行时,两条路。
第一条路:setupCommand
容器创建后运行一次(不是每次执行都运行):
{
agents: {
defaults: {
sandbox: {
mode: "all",
docker: {
network: "bridge", // setupCommand 需要网络来装包
setupCommand: "apt-get update && apt-get install -y nodejs npm curl",
},
},
},
},
}
几个坑:
- 默认
docker.network是"none",没有网络,apt-get 会失败。装包之前先把 network 改成"bridge" - 设了
readOnlyRoot: true的话写操作会失败 - 容器用户必须是 root 才能装包。省略
user配置或者写user: "0:0" - 沙箱不继承主机的
process.env。skill 需要的 API key 通过sandbox.docker.env传入
第二条路:烤一个自定义镜像
需求比较固定的话,直接做一个包含所有依赖的镜像更干净:
{
agents: {
defaults: {
sandbox: {
docker: {
image: "my-custom-sandbox:latest",
},
},
},
},
}
自定义绑定挂载
docker.binds 把主机目录挂进容器:
{
agents: {
defaults: {
sandbox: {
docker: {
binds: [
"/home/user/source:/source:ro",
"/var/data/myapp:/data:ro",
],
},
},
},
},
}
格式是 host:container:mode。不写 mode 默认是 rw。
安全方面几条规矩:
- 绑定会穿透沙箱文件系统,小心使用
- 密钥文件、SSH key、凭证用
:ro - OpenClaw 会阻止挂载
docker.sock、/etc、/proc、/sys、/dev这些危险路径 scope: "shared"时忽略每 agent 的绑定,只看全局配置
沙箱内浏览器
沙箱也能跑一个隔离的浏览器。先构建浏览器沙箱镜像:
scripts/sandbox-browser-setup.sh
相关配置在 agents.defaults.sandbox.browser 下:
autoStart:浏览器工具需要时自动启动,默认开启network:浏览器容器用专用 Docker 网络openclaw-sandbox-browsercdpSourceRange:CIDR 白名单,限制 CDP 连接来源allowHostControl:是否允许沙箱会话控制主机浏览器
浏览器沙箱的 noVNC 访问有密码保护,OpenClaw 生成的是带密码的短期 token URL。
工具策略:沙箱之外的第二道防线
沙箱管的是"工具在哪里跑",工具策略管的是"工具能不能跑"。两个独立的系统。
三个控制层
OpenClaw 的安全控制分三层:
- 沙箱(
sandbox.*):决定工具在 Docker 容器里跑还是在主机上跑 - 工具策略(
tools.*):决定哪些工具可用、哪些被禁止 - Elevated(
tools.elevated.*):exec 专用的逃生通道,允许被沙箱的会话在主机上跑命令
工具策略的规矩
deny永远赢。一个工具被 deny 了,沙箱加不回来,elevated 也救不了allow列表非空的话,不在列表里的工具全部被阻止- 工具策略是硬限制,
/exec命令不能覆盖被 deny 的exec工具
工具组快捷方式
不用一个个写工具名,可以用组:
{
tools: {
sandbox: {
tools: {
allow: ["group:runtime", "group:fs", "group:sessions", "group:memory"],
},
},
},
}
可用的组:
| 组 | 包含的工具 |
|---|---|
group:runtime | exec, bash, process |
group:fs | read, write, edit, apply_patch |
group:sessions | sessions_list, sessions_history, sessions_send, sessions_spawn, session_status |
group:memory | memory_search, memory_get |
group:ui | browser, canvas |
group:automation | cron, gateway |
group:messaging | message |
group:nodes | nodes |
group:openclaw | 所有内置 OpenClaw 工具,不含 provider 插件 |
Elevated:exec 的逃生通道
沙箱启用后,有时你确实需要在主机上跑一个命令。Elevated 干的就是这件事:
/elevated on:让当前会话的 exec 在主机上跑,仍需审批/elevated full:跳过审批
Elevated 只影响 exec,不给额外工具权限。exec 被工具策略 deny 了,elevated 也没用。
使用条件:
tools.elevated.enabled必须为 true- 发送者必须在
tools.elevated.allowFrom.<provider>白名单里
几个典型配置
只读 agent
只能读文件,不能改任何东西:
{
tools: {
allow: ["read"],
deny: ["exec", "write", "edit", "apply_patch", "process"],
},
}
安全执行 agent(能跑命令但不能改文件)
{
tools: {
allow: ["read", "exec", "process"],
deny: ["write", "edit", "apply_patch", "browser", "gateway"],
},
}
纯通信 agent(只能收发消息)
{
tools: {
sessions: { visibility: "tree" },
allow: ["sessions_list", "sessions_send", "sessions_history", "session_status"],
deny: ["exec", "write", "edit", "apply_patch", "read", "browser"],
},
}
多 agent 差异化配置
个人 agent 全权限在主机跑,家庭 agent 沙箱隔离且只读:
{
agents: {
list: [
{
id: "personal",
workspace: "~/.openclaw/workspace-personal",
sandbox: { mode: "off" },
},
{
id: "family",
workspace: "~/.openclaw/workspace-family",
sandbox: {
mode: "all",
scope: "agent",
},
tools: {
allow: ["read"],
deny: ["exec", "write", "edit", "apply_patch", "process", "browser"],
},
},
],
},
}
SSH 后端:远程主机当沙箱
不想在本地跑 Docker,可以把沙箱放到远程服务器上:
{
agents: {
defaults: {
sandbox: {
mode: "all",
backend: "ssh",
scope: "session",
workspaceAccess: "rw",
ssh: {
target: "user@remote-host:22",
workspaceRoot: "/tmp/openclaw-sandboxes",
strictHostKeyChecking: true,
identityFile: "~/.ssh/id_ed25519",
},
},
},
},
}
工作原理四步:
- OpenClaw 在远程主机上创建一个按 scope 隔离的目录
- 首次使用时把本地工作区同步到远程
- 之后 exec、read、write 等操作都在远程执行
- OpenClaw 不会自动把远程改动同步回本地
这是一个"远程即权威"的模型。远程工作区在初始同步后就是沙箱的真实状态。你在本地改了文件,远程看不到,除非用 openclaw sandbox recreate 重新同步。
SSH 后端不支持沙箱浏览器。
调试沙箱问题
最有用的命令:
# 查看当前生效的沙箱配置
openclaw sandbox explain
# 查看特定会话的沙箱状态
openclaw sandbox explain --session agent:main:main
# 查看特定 agent 的配置
openclaw sandbox explain --agent work
# JSON 输出,方便脚本处理
openclaw sandbox explain --json
常见问题
"工具 X 被沙箱策略阻止了"
两个解法:关掉沙箱(agents.defaults.sandbox.mode: "off"),或者在沙箱内允许该工具(加到 tools.sandbox.tools.allow 或从 deny 中移除)。
"我以为这是主会话,怎么被沙箱了?"
"non-main" 模式下,群组和频道的会话不算 main。用 sandbox explain 看一下实际的会话 key。要么切到 "off" 模式,要么接受群组会话就是会被沙箱。
"设了 mode: all 但 agent 没被沙箱"
查一下是不是有全局的 agents.defaults.sandbox.mode 在覆盖。Agent 级配置优先级更高,确认没被冲掉。
"setupCommand 运行失败"
十有八九是默认网络 "none" 造成的。装包需要网络,把 docker.network 改成 "bridge"。另外检查 readOnlyRoot 是不是 true,用户是不是 root。
"容器没有按 agent 隔离"
scope 默认是 "session",要每 agent 一个容器就设 scope: "agent"。
小结
OpenClaw 的沙箱分三层:
- 沙箱(sandbox):决定工具在哪里跑。Docker 容器、SSH 远程、还是主机
- 工具策略(tool policy):决定哪些工具可用。allow 和 deny 列表
- Elevated:被沙箱后仍需在主机跑 exec 时的逃生通道
三者独立但叠加。deny 永远赢,沙箱不能绕过工具策略,elevated 只管 exec。搞明白这三层,配置起来就不会犯糊涂。
核心三步:建镜像、在 openclaw.json 里写配置、用 sandbox explain 验证。
新文章,直接发到你的邮箱。
AI、工程与实验,每月 1–2 封。
无垃圾邮件,随时取消。