Codex + 第三方模型:沙箱静默拒绝网络与工作区外写入,用户无提示、无出路
- Dominant language
- TypeScript
- Stars
- 2.7k
- Forks
- 395
- Avg merge
- 21h 48m
- Merged PRs (30d)
- 776
Description
## 问题描述 / What happened
**Codex + 第三方模型(网关 / BYOK)在 Auto 档下,网络请求与工作区外写入被沙箱静默拒绝,用户看不到原因、也不知道能怎么办。**
这不是审核器的问题——审核器根本没机会介入。链路是串联的两层,沙箱在前:
```
模型要跑命令
↓
Codex 进程内的沙箱先执行
├─ 沙箱允许 → 直接跑完 Cindy 不知道
├─ 沙箱拒绝 + 模型主动申请升级 → 审批请求 → Cindy 审核器 ✔
└─ 沙箱拒绝 + 模型没申请 → 命令报错 Cindy 也不知道
```
第三条分支就是这个 issue:`curl` 报 `exit=6`(DNS 解析被拒)、写 `~` 报
`operation not permitted`,**没有任何提示说明这是沙箱拦的、也没提示切到完全访问可以执行**。
Agent 自己也不知道,可能反复重试。
### 为什么说是我们配置得过严
`sandboxModeToPolicy`(`packages/maker-core/src/agents/codex/index.ts:622-634`)在 `workspace-write`
下只传了 `writableRoots`:
```ts
case 'workspace-write':
return {
type: 'workspaceWrite',
...(extraWritableRoots.length > 0 ? { writableRoots: extraWritableRoots } : {}),
};
```
而协议里 `workspaceWrite` 有四个可调项(`codex/app-server/protocol.ts:444-450`):
| 字段 | 我们传了吗 | 后果 |
|---|---|---|
| `writableRoots` | ✅ 传了(塞了 codex memories 目录) | — |
| **`networkAccess`** | ❌ **从未设置**,走 server 默认(关) | **网络全断** |
| `excludeTmpdirEnvVar` | ❌ 未设 | 默认允许写 `/tmp`(实测通过) |
| `excludeSlashTmp` | ❌ 未设 | 同上 |
对照原生 codex:社区把 DeepSeek 等第三方模型接入 codex 时,普遍在
`~/.codex/config.toml` 里配 `sandbox_mode = "danger-full-access"` + `approval_policy = "never"`,
**网络与工作区外写入都是通的**。我们给出的环境比原生默认更压制,而且没有暴露任何放宽入口。
### 建议的三档(倾向 A)
| 档 | 改动 | 结果 | 审核器 |
|---|---|---|---|
| **A** | `networkAccess: true` | 网络通,写仍限工作区 | 保留 |
| B | A + `writableRoots` 纳入用户配置的额外目录 | 网络通、指定目录可写 | 保留 |
| C | 换 `danger-full-access` | 全通(等同原生常见配置) | **失效** |
倾向 A 的理由:**网络请求本来就在 `reviewAction` 的判据范围内**(`shared/auto-review.ts`
有 `network` 分支与内网地址判据)。沙箱把网络整个掐掉,等于让审核器没机会审;打开之后,
判断权回到审核器——能放行就放行,红线才拦。这与「减少无意义阻断」的产品方向一致。
C 能解决所有阻断,但审核器一起失效,需要产品决策。
## 环境 / Environment
- Cindy v0.1.44(macOS)
- codex-cli 0.147.0-alpha.6.5
- 会话:Codex + `moonshot/kimi-k3` + Auto 档 + xd 网关路由
- 对照:本机 `~/.codex/config.toml` 为 `danger-full-access` / `approval_policy = "never"`
## 复现步骤 / Steps to reproduce
1. 新建 Codex 会话,模型选任一第三方 / 网关模型(如 Kimi K3、DeepSeek)
2. 权限档选「自动审批」
3. 让 agent 执行 `curl https://registry.npmjs.org/react`
→ 报 `exit=6`,无任何提示
4. 让 agent 执行 `echo x > ~/probe.txt`
→ 报 `operation not permitted`,无任何提示
5. 查 `main-*.log`:`auto permission reviewer` **零条调用记录**,审批请求一条未产生
## 日志与截图 / Logs & screenshots
实测会话 `d52af8e9-8c4c-4c87-8a6c-1c7050d09695`(16 条命令):
| 命令 | 结果 |
|---|---|
| `whoami` / `pwd` / `uname` / `sw_vers` | 通过 |
| `echo > 工作区文件` | 通过(工作区内写入正常) |
| `echo > /tmp/...` | 通过 |
| `git status`(只读) | 通过 |
| **`curl https://...`** | **拦截 exit=6** |
| **`ping 8.8.8.8`** | **拦截 Operation not permitted** |
| **`echo > ~/...`** | **拦截 operation not permitted** |
| `ps aux` / `sudo -n ls` | 拦截 |
日志侧:`grep -c "auto permission reviewer" main-2026-08-12.log` = **0**。
---
## 需要上游确认的两点
### 1. `networkAccess: true` 之后网络请求走哪条路
两种可能,未实证:
- 沙箱直接放行 → 审核器同样看不到(与读文件相同)→ 用户体验最好,零打扰
- 走审批流 → 审核器介入判断
两种都比现状好,但行为需要确认,以免误判「已生效」。
### 2. 两个未文档化的审批策略值
`AskForApproval` 的内部枚举有 **5** 个值,但 `codex --help` 的
`--ask-for-approval` 只文档化了 **3** 个:
| 值 | CLI 文档 | 官方说明 |
|---|---|---|
| `untrusted` | ✅ | 只自动跑「可信」命令(ls/cat/sed),其余升级给用户 |
| `on-request` | ✅ | 模型自己决定何时问用户(**我们现在用这个**) |
| `never` | ✅ | 永不询问用户;执行失败直接把错误返回给模型 |
| **`on-failure`** | ❌ 未文档化 | 仅存在于二进制枚举表 |
| **`granular`** | ❌ 未文档化 | 同上,配套 `GranularApprovalConfig`(`sandbox_approval` / `rules` / `skill_approval` / `request_permissions` / `mcp_elicitations`) |
`on-failure` 从名字看正是我们需要的语义——**命令失败后自动请求审批**,不依赖模型
主动申请升级(第三方模型往往不会用 `sandbox_permissions: require_escalated`)。
但它未被文档化,可能是已废弃、未发布或仅内部可用。**贸然切换的风险是 server 静默忽略
——我们以为策略生效、实际没有,用户照样被拒。** 需要确认这两个值的真实状态与语义,
再决定是否可用。
## 风险边界(本 issue 不主张的事)
- 不主张收紧任何读权限。沙箱设计上允许读全盘(codex 自己的 Guardian 提示词原文:
*"The sandbox allows it read access everywhere"*),这是 codex 的既定策略,且
Guardian 明确写了 *"Do not treat reads as high risk simply because they may contain
some credentials"*。本 issue 的方向是**减少阻断**,不是增加。
- 不主张改动 codex 已实现的沙箱机制本身。
- 审核器覆盖面窄(只看升级请求)在此仅作背景,用于解释沙箱拒绝为何我们管不到;
它本身不是本 issue 要解决的问题。
## 相关
- PR #2474(已合并)修的是另一半:审阅器故障时不再静默拒绝,改为重试 + 降级给用户确认,
并按模型能力给足审核额度。那个 PR 解决「审核器自己拒绝用户」,本 issue 是「沙箱拒绝用户」。
Contributor guide
Assessment
This issue has not been assessed yet.