Skip to content

Codex + 第三方模型:沙箱静默拒绝网络与工作区外写入,用户无提示、无出路 #2556

Description

@zqchris

问题描述 / What happened

Codex + 第三方模型(网关 / BYOK)在 Auto 档下,网络请求与工作区外写入被沙箱静默拒绝,用户看不到原因、也不知道能怎么办。

这不是审核器的问题——审核器根本没机会介入。链路是串联的两层,沙箱在前:

模型要跑命令
      ↓
  Codex 进程内的沙箱先执行
      ├─ 沙箱允许 → 直接跑完                    Cindy 不知道
      ├─ 沙箱拒绝 + 模型主动申请升级 → 审批请求 → Cindy 审核器 ✔
      └─ 沙箱拒绝 + 模型没申请 → 命令报错        Cindy 也不知道

第三条分支就是这个 issue:curlexit=6(DNS 解析被拒)、写 ~
operation not permitted没有任何提示说明这是沙箱拦的、也没提示切到完全访问可以执行
Agent 自己也不知道,可能反复重试。

为什么说是我们配置得过严

sandboxModeToPolicypackages/maker-core/src/agents/codex/index.ts:622-634)在 workspace-write
下只传了 writableRoots

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.tomldanger-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-*.logauto 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 ❌ 未文档化 同上,配套 GranularApprovalConfigsandbox_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 要解决的问题。

相关

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions