1. CodexCLI 默认裸跑这件事,得先聊清楚
CodexCLI 是一个能在你本机读代码、改文件、执行 shell 命令的 AI 开发代理。它和普通代码补全工具最大的区别在于:补全工具只往编辑器里塞文本,而 CodexCLI 会真的去动你的文件系统、真的去起子进程。这意味着一旦权限配置没做好,一条rm -rf或者一次把.env内容读走并 POST 出去的操作,都是它能力范围内的事。
很多人装完 CodexCLI 直接codex进去就开始用,觉得"反正每步都弹确认,能出什么事"。这个判断在suggest档位下基本成立,但问题在于:CodexCLI 的安全模型不是"默认安全",而是"分层开关你自己开"。它的默认状态是裸机权限加逐条审批,一旦你为了省事切到full-auto又不加沙箱,等于把终端控制权交了出去。
这篇要解决的就是这个问题:怎么用配置文件加权限分层,把 CodexCLI 从"能用"变成"敢在真实项目里用"。我会给出可复制的settings.json/config.toml骨架,配合 TaoToken 统一 Key 和 API 通道的接入示例,最后用最小任务逐层验证拦截和放行是否符合预期。适合已经在用 CodexCLI、或者准备把它接进团队工作流的开发者。
2. 三层安全开关:审批、沙箱、网络与文件系统
在动手写配置之前,先把 CodexCLI 的安全模型拆成三层,这样后面每一行配置你都知道它在控制什么。
第一层是审批策略(Approval Policy),控制 AI 能不能自动改文件、自动跑命令。三档分别是suggest(全问你)、auto-edit(改文件自动、跑命令仍问)、full-auto(全自动)。默认是suggest,最稳。
第二层是沙箱(Sandbox),控制命令跑在哪。可选none(裸机)、darwin(macOS 的 Seatbelt)、linux(Landlock + seccomp)、docker(容器)。默认是none,也就是没有隔离。
第三层是网络与文件系统隔离,在沙箱内部进一步收紧:能不能联网、能碰哪些目录。默认全开放。
三层叠加起来才是完整的安全姿态。只开审批不开沙箱,full-auto下依然危险;只开沙箱不控网络,AI 仍可能把代码外传。下面按层给配置。
2.1 审批策略的配置骨架
审批策略可以写在配置文件里,也可以用启动参数覆盖。我建议写进配置,避免每次手敲漏掉。
# ~/.codex/config.toml(用户级,可含敏感信息) approval_policy = "auto-edit" [model] provider = "taotoken" name = "gpt-4o"// 项目级 .codex/settings.json(提交到 git,绝不放 key) { "approval_policy": "auto-edit", "sandbox": { "mode": "docker", "image": "myorg/codex-sandbox:node22", "mounts": [ { "source": "./test-output", "target": "/app/test-output", "mode": "rw" } ] }, "network": "none" }这里的关键分工:用户级config.toml放 provider 和 key 相关的东西,项目级settings.json只放非敏感的审批、沙箱、网络配置。项目级文件要提交到 git 让团队共享,所以里面出现任何密钥都是事故。
2.2 沙箱模式按操作系统选
沙箱模式的选择逻辑很直接:macOS 本地开发用darwin,Linux 开发机或 CI 用linux,敏感仓库或全自动 PR 流用docker。
# macOS 本地:Seatbelt 沙箱 + 禁网 codex --approval-policy auto-edit --sandbox darwin --network none # Linux 开发机 / CI:Landlock + seccomp codex --approval-policy auto-edit --sandbox linux # 敏感仓库 / 生产感场景:Docker 容器沙箱 + 禁网 codex --approval-policy full-auto --sandbox docker --network nonedarwin和linux这两种原生沙箱的共同点是:项目目录以只读方式挂进沙箱,临时目录可写,不需要装 Docker,启动快。docker最彻底,整个 session 跑在容器里,你可以定制镜像预装运行时和测试工具,项目目录挂:ro,输出目录挂:rw。
2.3 网络与文件系统的收紧
开了沙箱之后,网络和文件系统还能再收一层。禁网是防 AI 把代码或密钥 POST 出去最直接的手段。
# 在 config.toml 里固化禁网 network = "none" # 文件系统排除(实验性,看版本支持度) exclude = [ "**/.env*", "**/id_rsa*", "**/.aws/**", "**/.ssh/**" ]Docker 模式下更细:项目目录:ro让 AI 改不动源码,但它仍能在容器里跑npm test,测试结果通过挂载的out/或reports/目录带出来。~/.ssh、~/.aws、.env这些绝对不要挂进容器。
3. 接入 TaoToken 统一 Key 与 API 通道
安全配置做完,接下来解决 Key 管理的问题。CodexCLI 默认读OPENAI_API_KEY环境变量或~/.codex/config.yaml里的api_key字段。直接把这些散落在各处,既不好轮换,也容易在项目级配置里误提交。
TaoToken 提供统一的 Key 和 API 通道,把模型调用收敛到一个入口,配置和轮换都集中管理。官网入口在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 端点是 https://taotoken.net/api 。
3.1 获取 Key 并写入用户级配置
先在控制台创建 API Key,然后写进用户级配置,不要写项目级。
# 方式一:环境变量(推荐,不落盘) export TAOTOKEN_API_KEY="sk-你的key" # 方式二:写入用户级 config.toml mkdir -p ~/.codex cat >> ~/.codex/config.toml <<'EOF' [model] provider = "taotoken" base_url = "https://taotoken.net/api" api_key_env = "TAOTOKEN_API_KEY" name = "gpt-4o" EOF用api_key_env指向环境变量,比把 key 明文写进文件更安全。这样即使config.toml被同步或备份,里面也没有真实密钥。
3.2 项目级配置只放非敏感项
项目级settings.json里只保留审批、沙箱、网络这些可以公开的配置,provider 和 key 全部走用户级或环境变量。
{ "approval_policy": "auto-edit", "sandbox": { "mode": "linux" }, "network": "none", "model": { "provider": "taotoken", "name": "gpt-4o" } }注意这里没有api_key字段。CodexCLI 会从用户级配置和环境变量里补齐认证信息。团队共享这个文件时,每个人用自己的 Key,互不干扰。
3.3 验证通道连通
配置写完后,先跑一个最小请求确认通道通。
codex --approval-policy suggest --sandbox none \ -p "只回复 OK 两个字母,不要做任何其他操作"如果返回OK,说明 Key 和 API 通道都正常。这一步故意用suggest加none,因为只是验证连通性,不涉及文件操作,不需要沙箱。确认通道没问题后,再切到带沙箱的配置跑真实任务。
4. 逐层启用与最小任务验证
配置写完不等于生效,得逐层验证拦截和放行是否符合预期。我的做法是分三步:先验证审批拦截,再验证沙箱隔离,最后验证网络封锁。
4.1 验证审批拦截
用suggest档位跑一个会改文件的任务,确认它弹确认。
codex --approval-policy suggest --sandbox none \ -p "在项目根目录创建一个 test-approval.txt,内容写 hello"预期行为:CodexCLI 提出创建文件的动作,然后停下来等你确认。如果你不按确认,文件不会出现。这一步验证的是审批层在工作。
4.2 验证沙箱隔离
切到linux或darwin沙箱,跑一个试图写项目目录的任务,确认被拦截。
codex --approval-policy full-auto --sandbox linux \ -p "尝试往项目根目录的 README.md 追加一行文字"预期行为:因为项目目录在沙箱里是只读挂载,写入会被拒绝,CodexCLI 报权限错误。这一步验证的是沙箱的文件系统隔离在工作。如果你用的是 Docker 模式,项目目录挂:ro,效果一样。
4.3 验证网络封锁
最后验证禁网。跑一个试图联网的任务,确认出不去。
codex --approval-policy full-auto --sandbox linux --network none \ -p "用 curl 请求 https://example.com 并返回状态码"预期行为:请求失败,报网络不可达。这一步验证的是网络隔离在工作。三层都验证通过后,你就有了一套可复制的安全基线。
4.4 放行验证:确认正常任务不被误伤
拦截验证完,还要确认正常任务能跑通,否则配置过严会影响效率。
codex --approval-policy auto-edit --sandbox linux \ -p "在 test-output/ 目录下生成一个 summary.md,写入当前目录的文件列表"预期行为:因为test-output/是可写挂载,任务正常完成,文件出现在test-output/里。这一步确认放行路径没被误拦。
5. 本篇常见错排查
配置过程中踩过的坑基本集中在这几类,逐个说。
Key 写进了项目级配置被 git 蹭走。这是最常见的事故。项目级settings.json提交到 git 后,里面的api_key就公开了。排查方法:git log -p -- .codex/settings.json看历史里有没有密钥痕迹。预防方法:项目级只放非敏感项,key 走环境变量或用户级配置,并把.codex/加进.gitignore作为兜底。
沙箱开了但项目目录仍可写。检查挂载模式是不是写成了:rw。Docker 模式下项目目录应该是:ro,只有输出目录才:rw。原生沙箱模式下检查配置里有没有把项目目录误设为可写。
--network none没生效。确认这个参数是加在启动命令上,而不是只写在配置文件里被后续参数覆盖。启动参数的优先级高于配置文件,如果你在命令行又传了--network,会覆盖配置。
Landlock 在老内核上降级。Linux 内核低于 5.13 时,Landlock 不可用,沙箱会降级或报错。排查方法:uname -r看内核版本。如果低于 5.13,改用 Docker 沙箱,别指望原生 Landlock。
full-auto配了沙箱但忘了禁网。沙箱管文件系统,网络是独立的一层。full-auto加沙箱但不加--network none,AI 仍可能把代码外传。两个都要配。
审批策略和沙箱模式冲突。比如suggest配docker,每步都问,沙箱的意义被审批稀释了。反过来full-auto配none,就是最危险的组合。选型时按场景对齐:第一次跑陌生 repo 用suggest,日常本地开发用auto-edit加原生沙箱,敏感仓库用full-auto加 Docker 加禁网。
6. 把安全基线固化下来
三层验证通过后,把这套配置固化到团队工作流里。用户级config.toml管认证和 provider,项目级settings.json管审批、沙箱、网络,.gitignore兜底防泄漏。新成员加入时,拉下项目配置,自己配好用户级 Key,就能在同样的安全基线下工作。
如果你还在调 Key 和通道,可以先从 API Keys 页面把 Key 建好,再对照接入文档把base_url和api_key_env配进用户级配置。想先验证模型通道通不通,用模型对话跑一个最小请求最快。长期在 CodexCLI 里做编码和 Agent 任务的,Coding Plan 能把调用额度集中管理,省得每个项目单独配。
安全这件事没有一劳永逸,但把分层开关开对,CodexCLI 就能从"敢用"变成"放心用"。