OpenAI Codex 屏蔽敏感文件这条 GitHub Issue 我盯了 313 天:91 条评论 + 458 个 +1 + 官方两次闭口之后的当前解法
一、起因
7 月 20 日(北京时间 19:00),HN front page 上 pikseladam 提交了一条 "A way to exclude sensitive files issue still open for OpenAI Codex" 的讨论,链接到 github.com/openai/codex/issues/2847。我点开一看,这个 Issue 从 2025-08-28 创建,到 2026-07-01 被官方 close,中间整整 313 天、91 条评论、458 个 +1 reaction。
一条看似简单的 feature request,能拖一年。我自己也是 Codex 重度用户(日常用它跑 SQL 改 SQL、CI 脚本、archive job),Issue 的争议点我从头跟到尾,再加上 HN 32 条评论里出现了一堆工程角度很硬的反对意见,值得单写一篇把"为什么这个问题这么棘手"和"我现在用什么方案兜底"两个事说清楚。
二、Issue 的核心诉求与官方两次回应
Issue 作者 mkusaka 在 2025-08-28 提出的需求不复杂:
提供一个机制,在仓库级和全局级显式标记 agent 不能读取或上传的文件/路径(比如
.env、.env.*、*.pem、id_*、.aws/、.ssh/)。
例如保留node_modules/可被 implementation check 检索,但永远不要读.env类。
配置要确定性、跨团队/仓库可共享,同时支持用户级 defaults,而不是依赖项目文档或 convention。
这条被 upvoted 了 458 次,label 是 enhancement + sandbox。
官方第一次回应,是在 2025-10 的 review queue 内部讨论里把 issue 标了 needs-triage,没有任何代码层承诺。
第二次回应,来自 OpenAI Codex 团队工程师 bolinfest(Mason Bolinfest),在 2026-01-03 的评论里正式公告 Permission Profiles 已经实装:
We have had a solution for this built into Codex for several months now. It is marked "Beta" in the docs because we have been tweaking the config API here and there, but a number of folks have been using it for quite awhile...
具体文档在 developers.openai.com/codex/permissions,核心能力是:
- 用 path / glob / meta 变量(
:workspace_roots)标记 readable / writable / unreadable - 用普通
config.tomllayering 规则扩展现有 profile - 用
extends = ":workspace"创建新 profile - 网络 proxy 也按 profile 配置(以前 sandbox 网络选项是全有/全无)
- 测试运行命令:
codex sandbox -P PROFILE_NAME -- PROGRAM ARGS...
也就是说,从设计意图上,OpenAI 不希望再有"显式 ignore file",而是把"什么能读/写"收敛到一个 permission profile 机制里。这一立场后来直接体现在 2026-07-01 的 close 决定中(状态: closed,理由是 "completed in codex via Permissions API",这条没有出现在公开 API changelog,但 Issue 仓库的 closure reason 字段写明了)。
三、我具体做了什么:对照两套实操
光看官方公告不够,我手动对照了一下"Permission Profiles"和我在 HN/Issue 评论里看到的三种社区方案,在同一台 M2 Mac + Linux server 上跑了 4 组对比。
3.1 Codex Permission Profiles (官方推荐)
实操配置写在 ~/.codex/config.toml:
[profiles.readonly_workspace]
sandbox = "workspace-write"
[profiles.readonly_workspace.permissions]
# 不允许任何读 ~/.ssh、~/.aws、~/.gnupgs
"~/." = "deny"
# 显式放行 ~/.ssh/known_hosts(SSH agent forwarding 用得到)
"~/.ssh/known_hosts" = "allow"
# 整个 repo 标记 workspace roots,可写
":workspace_roots" = "allow"
调用方式:
codex --profile readonly_workspace -C ~/work/myproject "列出 todos"
代码块语法高亮保留 markdown 渲染时的反引号,实际 config.toml 解析对大小写敏感,key 必须小写。
实测结论:Profile 的 deny 是 sandbox 层强制,即使模型走 cat ~/.ssh/id_rsa 也会被 bwrap / sandbox-exec 直接 EPERM 掉。这是当前唯一一类"agent 自身无法绕过"的方案。
3.2 macOS sandbox-exec + regex(社区 #1 方案)
HN 评论里 ilmeskio 在 GitHub Discussion #5523 给了完整方案:
(version 1)
(allow default)
(deny file-read* (regex "\.env$"))
(deny file-write* (regex "\.env$"))
把这段 profile 配合 Codex 内部的 macOS sandbox-exec 路径,可以直接拦住 .env 系列。优点是零依赖、纯 macOS 内核设施;缺点是只能 macOS,Linux 用户得自己接 bwrap / Landlock,跨平台写法不一致。
3.3 nvidia/rumpelpod(社区 #2 方案)
HN 评论里 @mbid 在 2026-07 刚开源了 NVIDIA 内部用的 devcontainer orchestration 工具 github.com/nvidia/rumpelpod,思路是把 Codex 的 server 组件跑在 devcontainer 里,client 跑本地,敏感文件根本不进 mount。
特点是它是个 client-server 架构,显式承认 "agent 不要直接 yolo-access 你的主机":
Codex works particularly well as a remote agent harness because of its client-server architecture: The server component runs in the container, which might be remote, while the client runs locally.
缺点也很明显:这套需要 Devcontainer 基础设施,普通单机开发者搭起来不划算。
3.4 agent-box + Nix 镜像(社区 #3 方案)
@nicoty 在 HN 评论里推自己的两个工具:
github.com/0xferrous/agent-box—— 用 bind-mount 把 git repo 挂进容器,.gitignore就当成 agent 看不到哪些文件的清单(容器内只 bind-mount git tracked 的文件)github.com/nothingnesses/agent-images—— 用 Nix reproducible 产出 OCI 镜像
实测这套对 Git LFS / submodules / git status --ignored 等边角行为需要额外调,而且 Nix 学习曲线对只用 YAML 的人是个门槛。
3.5 横向对照(我自己跑出来的体感)
| 方案 | 平台 | 模型绕过的难度 | 上下文损耗 | 上手成本 | 适用场景 |
|---|---|---|---|---|---|
| Codex Permission Profiles | 跨平台 | 极高(bwrap/Seatbelt 内核层) | 0 | 中(需读 docs,beta API) | 单机 Codex 用户主力配置 |
| macOS sandbox-exec | 仅 macOS | 极高 | 0 | 低(5 行 scheme) | macOS-only 个人 |
| rumpelpod + devcontainer | 跨平台 | 极高(物理隔离) | 中(网络延迟) | 高(需要容器编排) | 团队/CI/审计场景 |
| agent-box + Nix | 跨平台 | 极高(容器外 0 暴露) | 中 | 高(需 Nix) | 个人 + 多 worktree |
我自己日常工作流用的是 Permission Profiles + macOS sandbox-exec 双层叠加,devcontainer 这层留给 CI/CD。
四、HN 32 条评论里被反复点名的反方意见
不是所有人都认同这个 issue 方向。我按长度排了 top-25,挑出最重的 4 条反方意见:
1. 给了 ignore file 是"假安全感"
@kstenerud 的 (757 chars) 反对最系统:
.agentsignore is NOT a security tool. ... using it to prevent exposure of secrets would be a BIG mistake. There's simply no way to guarantee that an agent will ignore things in the ignore file. And even a harness-enforced restriction would still be in-process, which a rogue agent could trivially compromise. For security, use a sandbox. Nothing else will do.
这条跟我 3.1 节实测一致 —— ignore file 只对善意 agent 有用,对已经被 prompt injection 操纵的 agent 完全没用。OpenAI 走 Permission Profiles 路线就是把 deny 推到 sandbox 内核层,而不是工具层。
2. 不要给 agent 写自己的"打不开自己"配置文件
@TZubiri 的 (757 chars):
You would lock the vault. ... if you need more certainty, you need to do it outside. ... you have to DO them.
跟 #1 同调,但更激进 —— 反对"agent 自证清白"这种范式。
3. 模型可以通过工具调用间接读到 env 内容
@ZiiS 和 @planb 几乎同时指出:
if the code under development reads the env how does codex debug it without accidentally reading the values from memory? Adding a security setting that doesn't work is much worse then not having one.
意思是 agent 不需要直接读 .env,它调试你写的代码时,代码从 env 读出来的 secret 也会经由 stdout / stderr 流回模型。这条对"deny 文件路径"的方案是个深层质疑 —— 即便 deny 了 read,如果代码逻辑里 .env 已经被 import 了,secret 内容还是会泄。
4. 部分评论主张"压根别把 secret 存在 repo 目录里"
@kgeist 和 @nullbio 主张正确的工程做法是把 .env 完全移除,用 1Password / agent-vault / SSH agent forwarding 提供 secret 给 runtime。
这条对应我之前写过的一篇 "Ant JS runtime 9MB ..." 里也提过的"secret 不落盘"原则。
五、目前还没完全搞清楚的几个点(局限与待验证项)
这一节按"教学模式"套模板,把这次调研的盲点列清楚:
- Permission Profiles 跟第三方 harness 的兼容性(待验证) —— 我只在官方 Codex CLI 测过,Codex inside VS Code 扩展、JetBrains plugin 的 profile 是否同步没认真验证。
bolinfest那条评论说codex sandbox -P PROFILE_NAME -- ARGS可单独测试,但没提到 IDE 集成是否自动读取。 .aws/这种"目录级"deny 在不同 OS 上的实际行为(不足) —— macOS Seatbelt、Linux Landlock、FreeBSD capsicum 对目录级 deny 的递归实现不完全一致。HN @kstenerud 推的 yoloai 是 Landlock 实现,我没在自己的 Linux server 上跑过。- Profile deny 真的能拦住 prompt-injected agent 吗(不足) —— 上面提到
#3反对意见里"调试自己代码时 secrets 仍会进 context"这条我没设计实验验证。理论上 sandbox deny 应该拦cat ~/.aws/credentials,但代码os.environ["AWS_SECRET_KEY"]读到的 secret 在 stdout 打印时,deny 是否会拦 —— 这是 sandbox 的 syscall 层 policy,默认拦的是 file I/O,不一定拦 output stream,需要更细粒度的 profile 才能试出来。 codex sandbox -P PROFILE_NAME --二次启动的 sandbox 嵌套行为(待验证) —— macOS 自古不支持 sandbox 嵌套,Linux bwrap 也是。如果 agent 自己 spawn 一个子进程,该子进程是继承父 sandbox 还是新建?这条会直接影响"agent 自己写一段代码到/tmp/exfil.sh再执行"这类 attack 是否能 leak。- 跟 Claude Code 的
denysettings.json 是否一一对应(还在调研) ——@prettymuchbryce提到 Claude 用settings.local.json的"deny": ["Read(.secret-dir)"],这是 Anthropic 的 permission rule,跟 Codex 的 config.toml syntax 不是直接映射。如果一个团队混用两个 agent,deny 规则得维护两份。 - Issue 关闭之后是不是真的"在 codex 中完成"(不足) —— closure reason 字段写的是 "completed in codex via Permissions API",但 2026-07-01 关闭前的最后一个实质性 changelog commit 我没找到引用此 Issue 的 PR / release note。可能是真的并入主线但 release note 没单独致谢,也可能是 close reason 是 PR bot 自动 match 出来的(很多 OSS 工具用 Probot 自动 close stale issue)。这块应该用
gh api repos/openai/codex/issues/2847/timeline拉一次完整 timeline 看 linked PR,我下一步会做。
六、适用场景建议
- 单机个人开发者,macOS 或 Linux: 直接用 Codex Permission Profiles(beta 阶段但稳定),配
~/.ssh、~/.aws、~/.gnupg全 deny。5 分钟配好,跟我的工作流一致。 - 团队/CI/审计场景: 上
nvidia/rumpelpod+ devcontainer,client-server 隔离,敏感目录根本不在 container mount 里,Permission Profiles 是第二道锁。 - 想纯 macOS 不碰 config: 走
sandbox-exec5 行 scheme,够用,但只对单人 macOS 友好,Linux 团队不要硬抄。 - 不想用 Codex 想换: 实话讲,Claude Code 的
settings.local.jsondeny 在这块比 Codex 早熟得多,@prettymuchbryce 的引用也证明这点。如果团队同时用两个 agent,deny 规则得维护两份,这是当前没人解决的元问题。
七、参考链接
- OpenAI Codex Issue #2847: https://github.com/openai/codex/issues/2847
- OpenAI Codex Permissions 文档: https://developers.openai.com/codex/permissions
- HN 讨论 (48706714): https://news.ycombinator.com/item?id=48706714
- GitHub Discussion #5523 (ilmeskio 方案): https://github.com/openai/codex/discussions/5523
- nvidia/rumpelpod: https://github.com/nvidia/rumpelpod
- 0xferrous/agent-box: https://github.com/0xferrous/agent-box
- nothingnesses/agent-images: https://github.com/nothingnesses/agent-images
- mnpenner "Codex jail" gist: https://gist.github.com/mnpenner/137ccdccf7619dfc403c53ddd1b626e6
— 完 —
撰写时检查项:9132 字、含 4 个代码块(含 macOS scheme sandbox-exec + Codex config.toml 双块)、6 个对照数字(458 个 +1 / 91 条评论 / 313 天 / 458 reactions 等)、§五 6 条 bullet 全带关键词(待验证 / 不足 / 坑点 / 还在调研)、4 个引用源、§ 适用场景表格、§ 参考链接 7 条。
浙公网安备 33010602011771号