Coding Agent 的沙箱到底保护了什么?又有哪些东西仍然能越界?
有光 / 2026-07-21
一个让我不安的瞬间
每次有人把"运行在沙箱里"当作完整的安全答案说出口,我都会停顿一下。
不是因为沙箱没有用。沙箱有用,而且通常有很大的用。而是因为这句话太容易被理解成一种包票——Agent 进程被关在笼子里,它碰不到外面的东西。我在机器上放了多少 SSH key、多少云凭据、多少 Git hook、多少编辑器扩展、多少有权访问 Docker socket 的本地 daemon,这些似乎都不在"沙箱"这个词的射程之内。
2026 年 7 月 20 日,Pillar Research 发布了一组涉及 Cursor、Codex CLI、Gemini CLI 和 Antigravity 的沙箱边界研究,BleepingComputer 同日进行了独立报道。让我最不舒服的,不是 Agent 正面击穿沙箱壁——而是研究者描述了一类更安静的路径:Agent 进程始终待在被允许的 workspace 范围之内,什么规则都没有直接违反,它只是写下一份文件,或者影响一个本地服务的状态,然后等沙箱外面那个被信任的组件替它完成剩余的动作。
这种"待在笼里,让笼外的人替你动手"的方式,是这篇文章想说清楚的事情。
先给出真正的边界答案
一句话先说完:
Coding Agent 的沙箱只能保护它真正执行的那条边界。只要 Agent 能影响沙箱外组件将要信任的文件、配置、命令参数或本地服务,它的实际爆炸半径就不只是在 Agent 进程里。
这不是在说沙箱没有意义。这是在说,沙箱保护的是一个执行边界,不是一个信任边界。这两件事经常不一样。
理解这个差异需要一个稍微精确一点的模型。
三层边界模型
Pillar Research 的研究框架用了三个层次来描述 Agent 的实际作用范围,我认为这是目前最清晰的一种切分方式:
第一层:直接执行
Agent 进程本身可以直接调用什么命令、可以访问哪些系统能力。沙箱控制的主要就是这一层,具体机制视产品和平台而定,例如:哪些可执行文件被 allowlist 允许,哪些系统调用被 seccomp 拦截,哪些网络连接被防火墙阻断。这是最直观的那道围栏。
第二层:Workspace 写入
Agent 可以创建或修改哪些文件——包括但不限于:源代码文件、项目配置文件、构建脚本、语言环境配置(比如 .npmrc、pyproject.toml)、编辑器扩展配置、Git hook 脚本、.github/workflows 下的 CI 定义、以及各种形式的元数据。
这一层是问题开始变得复杂的地方。Agent 写下一个文件,这个动作本身可能完全在允许范围之内。沙箱并没有被打穿。但这个文件接下来会被谁读、被谁执行、被谁信任——这些关系存在于第三层。
第三层:Host trust
沙箱外面有哪些工具、扩展、helper 进程和 daemon 会读取这些写入内容并采取行动。这可能是:编辑器本身(当它加载项目配置时)、Git(当它执行 pre-commit 或 post-checkout hook 时)、语言包管理器(当它安装依赖时)、CI 系统(当它运行工作流定义时)、Docker daemon(当它根据某个 socket 请求创建容器时)、以及任何定时任务或文件监视进程。
沙箱通常在第一层做了相当完整的工作。研究者发现的问题,绝大多数不是在第一层直接打穿,而是第二层的写入在第三层得到了信任——沙箱外部的可信组件把 Agent 写的东西当成自己的指令来执行。
这就是那个"信任交接"。
四类失败模式
Pillar Research 的研究在多个产品里发现了重复出现的失败模式,而不是几个孤立的 bug。我在这里只用概念层面的描述来解释这些模式,不提供任何具体的利用步骤或命令。
失败模式一:Denylist 漏掉一种操作系统能力
Denylist 的本质弱点是你需要列举所有危险的东西。在一个操作系统里,可以达到类似效果的路径通常不止一条。如果安全策略把某个高危操作符加入了 denylist,但同一个操作系统上还存在另一种调用方式能达到类似效果,而 denylist 没有覆盖到——那么这个安全策略就有漏洞。这类问题在 allowlist 设计中负担会小一些:你允许的是一个已知安全的正集合,而不是在一个无限集合里做减法。但如本文第三种失败模式所指出的,只检查命令名的 allowlist 本身仍然不够——还需要审查完整调用形式、参数语义、工作目录和副作用。
失败模式二:项目配置被当成可执行自动化
很多工具会把项目根目录下的配置文件当成可执行指令的来源——比如 hook 定义、构建前脚本、lint 前置任务、环境初始化命令。这类配置文件的存在是完全合理的,它们的设计初衷就是让项目行为可以被配置。但如果 Agent 可以写入这类文件,而宿主机上的工具又会在下一次触发时自动执行其中的命令,那么 Agent 就获得了一条不经过直接执行层的间接执行路径。
失败模式三:命令名称看起来安全,但参数和副作用并不安全
Allowlist 按命令名称放行,是一种常见且直觉上合理的设计。问题在于,同一个命令,配合不同的参数,可以有非常不同的副作用。一个通常用来查看只读信息的命令,在某些参数组合下可能会触发网络请求、写入文件、或者以特定权限执行代码。如果 allowlist 只检查命令名称本身,而不审查完整的调用形式和参数语义,那么这个 allowlist 所提供的保护就是不完整的。这也是为什么 Codex CLI 的 git show allowlist 问题值得单独记录——这个命令名看起来是一个完全无害的只读操作,但研究者发现了特定场景下的问题,该问题据研究方和媒体报道已在 Codex CLI 0.95.0 修复(CVE 在报道时仍在等待分配)。
失败模式四:特权本地 daemon 变成第二个执行环境
Docker daemon 是这类问题里最典型的例子。Docker socket 通常权限极高,能访问它就等同于能在宿主机上获得相当程度的能力。如果 Agent 能访问 Docker socket,它实际上就拥有了一个独立于自身沙箱的第二个执行环境。研究者在 Codex、Cursor 和 Gemini CLI 中都发现了 Docker socket 相关问题,据研究方和媒体报道这些问题已经修复。
把这四类模式放在一起:
| 失败模式 | 核心原因 | 被绕过的边界层 |
|---|---|---|
| Denylist 遗漏 OS 能力 | 危险路径很难被完整穷举 | 第一层(直接执行) |
| 可执行的 workspace 配置 | 写入和执行的主体被分离 | 第二层→第三层(写入→信任) |
| 只看命令名的 allowlist | 没有审查完整调用和参数副作用 | 第一层(不完整的直接执行控制) |
| 特权 daemon 作为第二执行环境 | Daemon 访问权限未被纳入沙箱边界 | 第一层+第三层(直接执行+外部信任) |
具体修复状态记录
我必须在这里说清楚信息来源。Pillar Research 的研究披露涉及四个产品,我查阅了研究方报告和 BleepingComputer 的独立报道,但在发布时无法从 GitHub advisory endpoint 读取对应 GHSA 的结构化数据,因此以下修复状态来自研究方和媒体报道,不是官方 advisory 的直接引用。
Cursor:workspace Hook 相关问题被标记为 CVE-2026-48124,据研究方和媒体报道在 Cursor 3.0.0 中修复。
Codex CLI:git show allowlist 问题据研究方和媒体报道在 0.95.0 中修复,CVE 报道时仍在等待分配。Docker socket 相关问题据报已修复。
Gemini CLI:Docker socket 相关问题据研究方和媒体报道已修复。
Antigravity:Google 将研究者提交的两份报告视为有效问题,但以可利用条件为由进行了降级处理。具体条件我没有直接来源,不做扩展。
我不打算做一个"哪家厂商做得更好"的排名。响应速度和修复质量需要比这篇文章更多的数据。我注意到的是,具名问题大部分已经修复或得到厂商确认——这比"问题被发现、被无视"的情况要好得多。但修复了已知问题不等于没有未知问题;这个区别在评估任何安全状态时都应该被保留。
为什么这次研究值得认真对待
有人可能会说:都修了,那就没事了。
我不完全这么想。修复一个具体的 bug 和修复导致这个 bug 的结构性设计,是两件不同的事情。
如果一个产品的 allowlist 是按命令名称检查的,那修复"命令 X 在参数 Y 下有问题"之后,对"命令 Z 在参数 W 下有问题"的防护并不因此自动增强。如果一个产品的 workspace 配置文件被宿主机工具信任执行,那修复"配置文件 A 里的问题"之后,对"配置文件 B 里的问题"的防护也不因此自动增强。
这不是在说厂商在偷懒。修复 bug 和重新设计安全模型,在工程量和时间上根本不是同一个量级的事情。能在披露后快速修复具体问题,本身已经是负责任的响应。但作为使用者,把"修了"等同于"这类问题不会再出现",是一个不应该做的推断。
四类失败模式在不同产品里同时出现,意味着这不是实现层面的粗心,而是这个领域在设计 Agent 执行环境时面临的一些共同困难——你需要给 Agent 足够的能力让它有用,同时需要精确地限制什么算"足够"。这条线很难划,而它被划在什么位置,对实际安全影响极大。
防御检查:真正能执行的那种
以下是一套围绕三层边界模型组织的检查清单。这不是给审计员准备的——这是给在自己机器上运行 Coding Agent 的人准备的,用来确认自己真正知道边界在哪里。
关于直接执行(第一层)
Agent 能直接执行什么?
你应该能准确回答这个问题。如果你用的是 allowlist 模式,看一下这个列表——每一条命令,你能说清楚在最坏的参数组合下会发生什么吗?如果用的是 denylist 模式,停下来想一想:你是否真的能穷举所有危险路径?
命令策略检查的是完整调用,还是只看命令名?
能访问命令配置的地方,找到策略的实际实现,确认它是否检查了参数。只检查命令名的 allowlist 是一个结构性薄弱点。
哪些操作会跳过审批?
大多数 Coding Agent 都有"需要人工确认"和"自动执行"两种模式,通常可以按命令类型或风险等级配置。知道你的配置里哪些操作被放行了自动执行,这是最基本的前提。
关于 Workspace 写入(第二层)
Agent 能写什么?
这个问题比第一层更难回答,因为"写文件"通常不需要特殊权限。更精确的问题是:Agent 能写哪些目录,这些目录下有没有会被宿主机工具自动执行的配置类文件?
Agent 改过的配置是否会进入 diff 和 review?
如果你的工作流里,Agent 提交的变更需要经过 code review,这是一个很有价值的检查点。可以用 AI Code Review 工作流建立一套基于证据的审查顺序。但要注意:有些配置文件可能不在你日常 review 的视野里——比如 .git/hooks/ 目录下的文件(它不会被 Git 追踪和推送,但在本地会被执行)。
关于 Host Trust(第三层)
哪些宿主机组件会信任 Agent 的写入?
这需要你列举清楚运行 Agent 的那个环境里,哪些工具会监视文件变化、哪些工具会在项目根目录触发时读取配置、哪些 hook 系统处于激活状态。Git hook、语言包管理器的安装脚本、编辑器扩展、CI 工作流定义——这些都是潜在的信任链节点。
Agent 能访问哪些 socket 和 daemon?
Docker socket 是最明显的高风险项,但不是唯一的。任何以高权限运行并监听本地 socket 的 daemon,都需要被检查是否在 Agent 的可访问范围之内。
同一个用户会话里是否放着 SSH key、云凭据和生产工具?
这是最容易被忽视的问题,因为这不只是 Agent 的配置问题,也是工作环境的配置问题。如果凭据文件(如 ~/.ssh/、AWS credentials)、kubectl context、已登录的 CLI 工具或相关环境变量处于 Agent 的可达范围之内,它们会扩大实际风险面——具体可达性取决于产品的权限设计和当前环境配置。
关于任务隔离
任务能否放进一次性环境?
对于你完全信任来源和内容的任务,在本地使用 Agent 加审批工作流是合理的。对于不可信仓库(比如你第一次 clone 的开源项目、未经验证的 PR、客户代码)、高自治运行(长时间无人监督的 Agent 执行)或实验性场景,一次性 VM、临时容器、远程开发环境或低权限专用账号可以提供额外一层结构性保护——前提是不挂载宿主机敏感目录、不传入生产凭据、不开放特权 daemon 访问。满足这些前提时,隔离本身比依赖 allowlist 配置的完整性更稳健。
关于工作间和围栏的那个比喻
沙箱像一间有围栏的工作间。围栏界定了工人可以直接走到哪里、可以直接操作哪些机器。这是有用的限制。
但工作台上写出的文件仍然可以成为围栏外机器的操作指令——如果有人会把那份文件带出去、放进另一台机器执行的话。工人没有越过围栏,他只是写了一份文件。是围栏外那个人信任了这份文件。
这个比喻我不想展开太多,因为真正重要的是技术机制:第二层的写入权限,乘以第三层的宿主机信任关系,决定了 Agent 的实际爆炸半径。围栏之内发生的事情,并不总是围栏之内的影响。
结尾:该如何选择运行环境
如果你还在建立终端 Agent 的基础审批工作流,可以先看 Codex 新手指南和 Claude Code 新手指南,再考虑扩大权限。
不存在"对所有场景都正确的一种配置",但有两个极端是清楚的:
可信任务 + 人工审批工作流 + 受控环境
如果你在自己熟悉的代码库上工作、清楚任务边界、审批链完整——这种场景下,本地运行 Coding Agent 配合窄权限和显式审批是合理的。这是大多数日常使用场景。
不可信仓库 + 高自治运行 + 未知内容
如果你在处理来源不确定的代码、让 Agent 长时间自主运行、或者任务本身涉及大量外部内容——这种场景下,应该使用更强的一次性隔离环境。临时容器、专用低权限账号、远程沙箱——在不挂载敏感路径、不传入生产凭据、不开放特权 daemon 的前提下,任何能把这个任务的执行上下文与你的日常工作会话物理隔开的方案,都比依赖 allowlist 配置的完整性要稳健。
这不是悲观主义,而是工程意义上的最小爆炸半径设计。你给 Agent 的权限应该是完成当前任务所需要的最小集合,你给 Agent 的信任范围应该和你自己能验证的范围对齐。
Coding Agent 是强大的工具,Pillar Research 这次研究提醒的不是"不要用 Agent",而是"不要把运行环境当成一个不需要继续思考的变量"。
参考来源
- Pillar Research,《The Week of Sandbox Escapes》,2026-07-20:https://www.pillar.security/blog/the-week-of-sandbox-escapes
- BleepingComputer,《Cursor, Codex, Gemini CLI, Antigravity hit by sandbox escapes》,2026-07-20:原始报道
- Cursor 发布说明:https://cursor.com/changelog(该页面不直接验证具体 CVE,修复状态仍以研究方与媒体报道为准)
- OpenAI Codex CLI GitHub 仓库及发布说明:https://github.com/openai/codex
- Google Gemini CLI GitHub 仓库:https://github.com/google-gemini/gemini-cli
修复状态说明:本文中涉及的具体修复版本和 CVE 信息,来自 Pillar Research 研究报告和 BleepingComputer 独立报道,非官方 GitHub Security Advisory(GHSA)直接引用。发布前如取得可访问的官方 advisory,建议核对并更新相关条目。