Codex Harness 安全沙箱机制原理:AI 编程代理如何安全地执行命令
本文讨论 Codex 本地客户端与其命令执行 Harness 的通用安全模型。具体实现会随 Codex 版本、操作系统、宿主环境和管理员策略变化,应以运行时显示的权限配置与官方文档为准。
一、为什么 AI 编程代理需要沙箱
传统聊天模型只生成文字,而 Codex 这类编程代理会读取代码、修改文件、运行测试、调用 Git,甚至执行安装依赖和网络请求。它的能力越接近一名真实开发者,潜在影响范围也越大:一条错误命令可能覆盖文件,恶意仓库中的提示注入可能诱导代理读取密钥,依赖安装脚本也可能执行任意代码。
因此,Codex 不能只依靠“提示词要求模型小心”。可靠的安全机制必须建立在操作系统能够强制执行的边界之上。Codex Harness 的核心作用,就是把模型提出的操作转换成受约束的工具调用,并在命令真正执行之前套上文件系统、网络、进程和审批策略。
可以把整个体系理解为四层:
- 模型层:分析任务,提出命令或文件操作;
- Harness 层:检查工具参数、当前权限和审批条件;
- 沙箱层:通过操作系统机制强制限制文件、网络和系统调用;
- 宿主系统层:Linux、macOS、Windows 或云端容器提供最终执行环境。
关键结论是:模型决定“想做什么”,Harness 决定“是否允许尝试”,操作系统决定“实际上能不能做到”。
二、沙箱与审批不是一回事
Codex 的权限控制由两个相互独立、又彼此配合的概念组成。
1. Sandbox Mode:技术边界
沙箱模式规定命令在操作系统层面能做什么。常见模式可以概括为:
| 模式 | 文件读取 | 文件写入 | 网络 | 适用场景 |
|---|---|---|---|---|
read-only | 允许读取授权范围 | 禁止或严格限制 | 默认关闭 | 代码审查、分析、制定方案 |
workspace-write | 可读取必要路径 | 仅允许写工作区等授权根目录 | 默认关闭,可单独配置 | 日常编码、测试、构建 |
danger-full-access | 接近宿主用户权限 | 接近宿主用户权限 | 取决于配置 | 明确信任且确有必要的任务 |
沙箱不是简单地检查命令字符串。例如,禁止写/etc不能只靠拦截rm /etc/...,因为程序还可以通过脚本、符号链接、子进程或另一个解释器写文件。真正的限制必须作用到进程最终发起的系统调用上。
2. Approval Policy:越界时由谁决定
审批策略控制 Harness 何时停下来请求许可。命令若需要写工作区之外、访问被禁止的网络,或使用更高权限,Harness 可以拒绝、询问用户,或把请求交给独立的自动审查器。
因此:
- 沙箱解决能力边界问题;
- 审批解决越界授权问题;
- 审批通过后,Harness 才会使用更宽的权限重新执行;
- 审批本身不会神奇地修改原沙箱中的进程权限。
将二者分开非常重要。只有提示确认、没有 OS 沙箱,一旦程序开始运行就很难约束;只有沙箱、没有合理审批,则许多正常开发任务会因为安装依赖、访问私有仓库或写入外部目录而无法完成。
三、Linux 上的底层实现
根据 Codex 官方公开说明,Linux 与 WSL2 的当前实现主要组合使用Bubblewrap、seccomp,并在兼容路径中使用Landlock。实际采用哪条强制路径,取决于内核能力、用户命名空间是否可用,以及宿主是否已经处于受限容器中。
1. Bubblewrap:构造受限的文件系统视图
Bubblewrap(bwrap)是一个轻量级沙箱工具。它利用 Linux namespace 和 bind mount,为目标进程创建新的挂载视图。它并不是完整虚拟机,也不会模拟一套新内核;沙箱进程与宿主共享内核,但看到的文件系统可以完全不同。
典型思路如下:
- 将系统目录以只读方式映射进沙箱;
- 将当前项目目录以可写方式映射;
- 隐藏或不映射敏感目录;
- 创建独立的
/tmp、/proc等运行环境; - 根据策略隔离网络、进程或其他 namespace;
- 最后在新环境中启动 shell、编译器或测试命令。
这也解释了为什么 Bubblewrap 里“可以安装 Python”,但含义需要区分:如果宿主的 Python 被只读映射,沙箱可以直接运行它;如果工作区可写,也可以把虚拟环境或依赖安装到工作区。要修改系统级/usr或使用系统包管理器,则通常会被文件系统边界阻止,除非显式提升权限。
2. seccomp:限制危险系统调用
文件视图隔离仍不足以覆盖所有风险。Linux 程序最终通过系统调用访问内核,seccomp 可以为进程安装过滤规则,对特定 syscall 直接拒绝、返回错误或终止进程。
它适合限制某些高风险内核接口,缩小进程可用的攻击面。子进程通常会继承相关约束,所以代理即使从 shell 再启动 Python、Node.js 或编译后的二进制,也不能自然摆脱过滤器。
seccomp 主要回答“允许调用哪些内核功能”,而不是“允许访问哪个具体路径”。路径级权限通常需要挂载隔离、Landlock 或传统 Unix 权限共同完成。
3. Landlock:进程自我施加的文件访问控制
Landlock 是 Linux 内核提供的无特权安全模块。进程可以为自己以及后代增加文件系统访问限制,例如只允许读取某些目录、只允许在工作区写入。规则一旦生效,通常只能继续收紧,不能由被限制的进程自行放宽。
Landlock 的优势是不一定要求 root,适合本地开发工具对自身执行的命令施加限制。但它依赖内核版本和宿主配置,并且不同 ABI 版本支持的权限类型不同。因此 Harness 必须先探测系统能力;如果目标策略无法可靠执行,应拒绝运行或选择明确的兼容路径,而不能悄悄退化成无限制执行。
4. 网络隔离
Codex 默认关闭本地代理命令的网络访问,以降低提示注入、恶意依赖下载和数据外传风险。在 Linux 上,网络限制可以由 namespace、seccomp 或宿主策略组合实现;具体手段取决于所选后端。
联网并不是“沙箱开或关”的附属状态,而是一项独立能力。合理策略可以允许文件写入工作区但禁网,也可以在明确许可后为某次安装或查询开放网络。企业环境还可以叠加域名白名单、代理和防火墙策略。
四、一次命令是怎样被执行的
假设代理准备运行:
pipinstall-rrequirements.txt&&pytestHarness 大致会经历以下过程:
- 模型产生结构化工具调用,而不是直接控制终端;
- Harness 解析工作目录、命令、超时和所需权限;
- 当前策略判断工作目录是否在允许范围内,以及该操作是否需要网络;
- 若权限不足,命令会失败、被拒绝,或触发审批;
- 若允许执行,Harness 根据当前平台生成沙箱配置;
- 沙箱启动 shell,shell 再启动
pip与pytest; - 所有后代进程继承沙箱边界;
- Harness 收集标准输出、标准错误、退出码和超时状态,并返回给模型;
- 模型根据结果继续修改、重试,或向用户报告阻塞原因。
这里最值得注意的是子进程继承。限制若只包裹最外层 shell、却不能约束其后代,那么程序只需启动另一个解释器就能绕过控制,沙箱便失去了意义。
五、文件系统权限的细节
workspace-write并不等于“项目目录中任何东西都绝对安全”。实际系统还需要处理以下边界问题。
符号链接与路径逃逸
工作区内的符号链接可能指向外部敏感路径。因此安全判断不能只检查字符串是否以工作区路径开头,还必须依赖内核最终解析后的访问控制,或在执行前进行可靠的路径解析与策略校验。
Git 仓库与未提交修改
沙箱可以限制写入范围,却无法判断某次合法写入是否符合用户意图。例如覆盖工作区内未提交的代码在权限上可能完全合法,但仍会造成数据损失。因此 Harness 还需要更高层的安全规则:避免破坏性命令、尊重脏工作区、优先使用可恢复操作,并在目标不明确时请求确认。
临时目录和缓存目录
编译器、测试框架与包管理器经常写/tmp、用户缓存或语言工具链目录。如果策略只开放项目目录,一些命令会失败。这不是沙箱故障,而是最小权限的直接结果。解决方式通常是把缓存重定向到工作区、增加一个精确的可写根目录,或者对必要命令申请一次性授权。
读取权限同样重要
很多人只关注防止写坏系统,却忽略读取 SSH 密钥、云凭据、浏览器数据和环境变量同样危险。尤其当网络被开放时,“可读秘密 + 可访问外网”会形成数据外传通路。因此高安全配置应同时限制敏感文件读取、秘密在代理阶段的暴露和网络出口。
六、云端 Codex 与本地沙箱的区别
本地 Codex 的命令最终运行在用户机器上,主要依赖平台原生强制机制;Codex Cloud 则运行在 OpenAI 管理的隔离容器中,与用户宿主系统天然分离。
官方描述的云端模式通常区分两个阶段:
- Setup 阶段:可以按环境配置安装依赖并访问网络;
- Agent 阶段:默认离线执行任务,除非为该环境启用互联网访问。
配置给云环境的秘密可以只在 Setup 阶段出现,并在 Agent 阶段开始前移除。这种设计把“准备可信构建环境”与“让模型自主操作”分开,降低代理在处理仓库内容时接触长期凭据的机会。
七、不同操作系统上的实现
| 平台 | 主要机制 | 特点 |
|---|---|---|
| Linux / WSL2 | Bubblewrap、seccomp,Landlock 兼容路径 | 利用 namespace、挂载视图、系统调用过滤和内核访问控制 |
| macOS | Seatbelt sandbox profile | 使用系统原生沙箱规则限制文件与网络访问 |
| 原生 Windows | 低权限用户或受限令牌、ACL、Firewall 等 | elevated模式强于unelevated;WSL2 使用 Linux 路径 |
| Codex Cloud | OpenAI 管理的隔离容器 | 与本地主机分离,可区分 Setup 与 Agent 网络/秘密权限 |
这些实现追求相同的抽象目标,但并非能力完全一致。例如某个平台无法表达特定的读写拆分策略时,安全实现应拒绝该策略,而不是静默地以更宽权限运行。
八、它能防什么,不能防什么
沙箱主要能够降低以下风险:
- 意外修改工作区之外的系统或用户文件;
- 未经许可访问网络;
- 恶意仓库诱导代理读取或外传敏感信息;
- 构建脚本、测试程序和依赖安装器扩大影响范围;
- 利用部分危险系统调用攻击宿主。
但沙箱不是万能边界:
- 已明确开放为可写的工作区仍可能被破坏;
- 工作区中本来就存在的秘密仍可能被读取;
- 一旦用户批准全权限,OS 沙箱保护可能大幅减少;
- 沙箱与 Linux 宿主共享内核,不能等同于虚拟机;
- 内核或沙箱工具自身的漏洞理论上可能导致逃逸;
- 允许网络后,依赖投毒和外部恶意内容的风险会上升;
- MCP、浏览器或外部应用工具可能拥有独立权限,不能仅靠 shell 沙箱覆盖。
因此,更准确的说法是:沙箱显著缩小爆炸半径,但不能替代备份、代码审查、秘密管理、最小权限账户和供应链安全。
九、推荐的安全配置思路
对于日常开发,推荐从以下原则出发:
- 默认使用
workspace-write,仅把实际项目目录设为可写; - 默认关闭网络,需要下载依赖时按任务临时开放;
- 代码审查和方案分析使用
read-only; - 不把 SSH 私钥、云凭据、生产配置放进代理可读工作区;
- 对外部仓库先审查项目级配置、Hook、
AGENTS.md与安装脚本; - 保持 Git 提交或其他备份,以便恢复工作区内的合法但错误写入;
- 将全权限视为例外,并限定到明确、短时、可核查的操作;
- 企业环境通过系统策略限制用户自行选择危险配置。
一个典型的本地自动模式可采用如下思路:
codex--sandboxworkspace-write --ask-for-approval on-request它允许 Codex 在项目中读取、修改和运行常规命令;当任务需要访问边界之外的资源时,再进入审批流程。实际配置项和可用值应以当前 Codex 版本的帮助信息与配置参考为准。
十、如何验证沙箱是否真的生效
不要仅凭配置文件推断安全状态。Codex 提供平台沙箱调试命令,可在与代理相同的边界中运行测试命令,例如:
# Linuxcodex sandbox linuxbash-lc'touch /tmp/codex-test && curl https://example.com'# macOScodex sandbox macosbash-lc'touch /tmp/codex-test && curl https://example.com'# Windowscodex sandbox windows powershell-Command'Get-ChildItem'测试时应检查:工作区写入是否成功、外部路径写入是否失败、敏感文件读取是否受限、网络是否符合策略,以及子进程是否继承相同限制。不要用生产秘密作为测试对象。
十一、总结
Codex Harness 的安全性不是来自单一技术,而是来自一组互补机制:模型只提出操作,Harness 负责工具编排与审批,操作系统沙箱负责不可绕过的强制限制,Git、备份和秘密管理则承担更高层的数据保护。
在 Linux 上,Bubblewrap 负责构造受限运行视图,seccomp 缩小可调用的内核接口,Landlock提供文件访问限制与兼容路径;网络权限又作为独立能力受到控制。审批机制位于沙箱边界之上,使代理在低风险范围内保持自动化,在确实需要越界时交还决定权。
理解这一体系最简单的一句话是:不要只信任 AI 会谨慎,也不要只信任一条配置;应让每个进程都在最小权限边界中运行,并让每次越界都可见、可审查、可拒绝。
参考资料
- OpenAI Codex Sandbox:https://developers.openai.com/codex/sandboxing
- OpenAI Agent approvals & security:https://developers.openai.com/codex/agent-approvals-security
- OpenAI Codex Permissions:https://developers.openai.com/codex/permissions
- OpenAI Codex Configuration Reference:https://developers.openai.com/codex/config-reference