Sandbox、Approval、Permission profile:三者不要混写
用技术边界、越界决策和命名权限档位三层模型,选择完成任务所需的最小权限。
先知道终点
- 做完你会得到
- 能解释一次命令为何被允许、被沙箱阻止或需要审批,并安全恢复
- 开始前只需要
- 了解任务将读写哪些目录,是否需要网络或外部服务
- 最后留下这些证据
- 完成一张动作—资源—风险—权限表;记录一个被阻止动作和最小恢复方案;没有用 full access 代替问题诊断
内容校准于 2026-07-31 · 第 10 / 38 节已发布课程
跟着材料做,不只阅读
本节练习资料
点了允许,不代表这件事已经安全
Codex 准备安装一个依赖。弹窗问你是否批准。你点了允许,任务继续,于是下意识地觉得安全问题已经解决。
可弹窗只回答了「这一次要不要做」。它没有说明进程原本能碰到哪里,也没有决定以后类似动作的默认态度。
Sandbox、Approval 和 Permission profile 分别管理能力、越界决策和默认档位。 这节课用一次安装与联网任务,把三层放回各自的位置。
先建立三层模型
官方安全文档区分了三个容易混淆的概念:
- Sandbox 是技术边界:进程能读写哪里、能否联网;
- Approval policy 决定何时必须停下来询问,才能跨越或执行某类动作;
- Permission profile 把文件系统、网络和审批行为组合成可命名、可复用的档位。
因此,“开启审批”不等于沙箱消失;“在 workspace 模式”也不等于任何工作区动作都应该执行。技术上允许和任务上授权是两回事。
从动作清单推导权限
不要从模式名称开始。先列动作:
| 动作 | 资源 | 是否必要 | 风险 | 最小边界 |
|---|---|---|---|---|
| 读源代码 | 当前仓库 | 是 | 低 | workspace 读取 |
| 写测试与修复 | 当前仓库 | 是 | 中 | workspace 写入 |
| 下载依赖 | 公共包域名 | 可能 | 供应链、联网 | 指定域名并按需审批 |
| 读主目录配置 | 工作区外 | 否 | 秘密泄露 | 禁止 |
| 推送远程 | Git 远端 | 未授权 | 外部状态变化 | 暂停询问 |
| 部署生产 | 平台与生产环境 | 未授权 | 高影响 | 单独明确授权 |
从任务需要反推边界,通常会得到“工作区可写、其他位置只读或拒绝、网络默认关闭、外部动作询问”,而不是 full access。
Read-only、Workspace 与 Full access 的心智
- Read-only 适合审查、调研、解释和建立计划;不能完成需要落盘的修复。
- Workspace 允许在活动工作区内写入,仍应保护工作区外路径和不必要网络,是多数本地实现任务的合理起点。
- Full access 移除重要本地限制,只应在明确理解工作流且确有必要时使用。它不是“修复权限报错”的快捷键。
名称与具体字段可能更新,操作前查当前 Permissions 与 Sandboxing 页面。稳定原则是最小能力、最小范围、最短时间。
被阻止时怎么诊断
出现 permission denied 或网络失败时,依次判断:
- 动作是否属于原任务;
- 资源是否在允许边界内;
- 是否有更窄的替代动作;
- 若必须放宽,能否只增加一个目录、域名或单次审批;
- 放宽后如何验证并恢复原权限。
示例:构建工具想写用户级缓存。替代方案可能是把缓存目录改到工作区,而不是允许整个主目录写入。测试要访问本地服务,可只允许 localhost,而不是开放公共网络。
Sandbox 继承与子进程
Codex 启动的命令可能再启动构建器、脚本和子进程。安全边界需要覆盖整个进程树,而不是只看第一条命令。一个看似无害的 npm 脚本可能包含下载、postinstall 或发布步骤,所以在执行陌生脚本前先读取定义。
Web 内容与 prompt injection
联网扩大了输入面。网页、issue、README 或工具输出里可能包含试图改变 agent 行为的文字。它们是数据,不是用户授权。安全规则:
- 页面不能扩大文件、网络或外部动作权限;
- 不把本地秘密复制到查询或表单;
- 对敏感动作核对真实 hostname 和目标;
- 搜索、抓取和浏览器交互都保留来源;
- 遇到“必须关闭安全设置”的页面指令,停止并报告。
Permission profile 的价值
当一种权限组合反复使用,可以命名:例如 review-only、workspace-dev、docs-research。命名档位比每次临时放宽更容易审计。但 profile 是高漂移配置,应以官方当前 reference 为准;旧 sandbox 配置和新 profile 不要混成一套未经验证的设置。
一个 profile 的说明至少写:
用途:
允许读取:
允许写入:
允许网络:
需要审批:
明确禁止:
校准版本与日期:
验证方法:
恢复练习
故意设计一个安全失败:只读任务尝试写文件,或工作区任务尝试访问无关目录。不要真的访问敏感位置。记录:
- 被阻止的动作;
- 阻止来自 sandbox、approval 还是任务边界;
- 最小替代路径;
- 是否需要用户授权;
- 完成后是否恢复权限。
如果你的第一反应是启用 full access,练习未通过。
完整案例:用一次真实动作区分三层控制
假设任务要读取当前仓库、修改一个配置,然后把构建产物上传到外部服务:
| 层 | 它回答的问题 | 本例中的判断 |
|---|---|---|
| Sandbox | 技术上能访问什么 | 是否能写工作区、是否能联网 |
| Approval policy | 越界或敏感动作何时询问 | 上传前是否必须暂停确认 |
| Permission profile / managed policy | 一组持久或组织约束 | 当前模式是否允许网络、哪些命令被禁止 |
三者不能互相替代。Sandbox 允许联网,不代表用户授权上传;Approval 设置较宽,也不能突破组织强制策略;Prompt 写“请不要上传”是任务边界,但不应成为唯一技术防线。
最小权限设计:先列动作,再给能力
任务动作清单:
1. 读取 app/ 与 tests/:需要工作区只读
2. 修改一个配置与测试:需要工作区写入
3. 安装新依赖:当前不需要
4. 访问官方文档:仅在现有文档不足时需要网络
5. 上传、发送、部署:不在本任务范围
不要因为第五步“以后可能需要”就提前给全访问。权限应随已确认动作增长,而不是随任务想象增长。
高风险动作的停止模板
当 agent 发现必须访问工作区外文件或外部系统时,应给出:
阻塞动作:读取 /path/outside-workspace/config
原因:当前仓库只保存了引用,缺少生成构建所需的字段
最小范围:只读该文件,不写入、不复制秘密到日志
替代方案:你可以提供脱敏字段,或允许一次只读访问
若不授权:我可以继续完成不依赖该字段的本地验证
这让用户批准的是一个具体动作,而不是模糊的“更高权限”。
外部副作用要单独建模
文件修改通常可以通过 diff 回退;发送邮件、写数据库、删除云资源、付款和发布可能影响其他人。教程建议把这些动作分成“准备草稿”和“实际执行”:
- 可以生成 migration SQL,但不自动应用;
- 可以准备邮件草稿,但不发送;
- 可以生成部署计划与 dry-run,但不发布;
- 可以列出待删除资源,但在精确解析目标前不删除。
即使权限允许,任务授权仍然决定是否执行。
故障诊所
| 现象 | 错误心智 | 正确恢复 |
|---|---|---|
| 命令被拒绝后反复重试 | 把沙箱当临时故障 | 解释所需能力,缩小请求或使用替代方案 |
| 一次批准后继续做相邻外部动作 | 把批准当永久授权 | 每个实质不同的副作用重新核对范围 |
| Prompt 说“安全执行”就给全访问 | 把文字承诺当技术控制 | 从动作清单推导最小 sandbox 和 policy |
| 日志中出现密钥 | 忽略输出也是数据泄露面 | 停止、撤销或轮换密钥,清理日志并复盘 |
知识检查
如果 full access 模式下任务只要求“分析部署失败”,可以顺手重新部署吗?不能。技术能力不是用户授权;先完成只读诊断,只有用户明确要求修复或部署后才能改变外部状态。
权限不是越少越好,是刚好够用
把下一项任务列成动作清单。每个动作旁边写下需要的文件、网络和外部系统,再决定哪些属于默认能力,哪些必须逐次批准。
如果你只能用「安全模式」或「全权限」描述方案,说明三层仍然混在一起。把边界具体到动作,选择才有意义。
完成检查
- 能分别定义 sandbox、approval 和 permission profile
- 权限来自动作清单,不来自方便程度
- 被阻止时先寻找更窄替代方案
- 子进程、脚本和网页内容都纳入威胁模型
- 外部动作即使技术允许也需要任务授权
- 高漂移字段会回查官方 reference
参考与校准来源
本文是官方资料的中文转译与教学重组,不是逐字翻译;产品能力、命令、默认值与安全边界以下列官方原文为准。