Background
agent-tunnel now supports tunneling Codex CLI sessions (#102). Access levels (read/write/bash/all) are enforced through Codex's OS sandbox, which governs shell command execution (filesystem + network).
The gap
Codex's OS sandbox does not govern its non-shell tool surfaces. Codex ships ~20 default-on "features" (see codex features list) — e.g. apps, browser_use*, computer_use, in_app_browser, image_generation, code_mode_host, hooks, MCP servers, web search — that can take external actions (write files, hit the network, drive a browser) outside the sandbox. So a read handle, which is supposed to be look-but-don't-touch, could in principle trigger one of these.
Contrast with the Claude backend, which is airtight here because it uses a strict tool allowlist (--allowedTools Read,Grep,Glob) — anything not on the list simply doesn't exist for the fork.
What PR #102 already does (the mitigation shipped)
For every non-all codex handle, build_codex_flags disables the clear external-action surfaces:
-c mcp_servers={} (MCP connectors)
-c tools.web_search=false
--disable for: apps, browser_use, browser_use_external, browser_use_full_cdp_access, computer_use, in_app_browser, image_generation, code_mode_host, hooks
It also strips -o/--output-last-message (a host-side file write) from headless_extra_args. This is documented in docs/agent-tunnel-spec.md (Security model + "Codex CLI sessions").
Why this is a follow-up, not "done"
The --disable set is hard-coded and codex-version-specific (captured from codex features list on codex-cli 0.144.4). A newer Codex release can add an external-action feature that isn't on our list, silently reopening the gap. There is no single "restrict to a minimal toolset" switch equivalent to Claude's allowlist.
Options to consider
- Dynamic denylist: at
serve startup (or per turn), run codex features list, and --disable every stable/true feature that isn't on a small explicit allowlist of safe/passive ones. This inverts the model (allowlist, like Claude) and auto-tracks new features. Cost: a codex features list call + maintaining the safe-allowlist.
- Upstream ask: request a first-class "read-only / minimal-tools" mode from Codex (a single flag that disables all external-action tools), and depend on it when present.
- Accept + document (status quo): keep the curated
--disable set, and rely on the doc note telling publishers to audit codex features list before sharing Codex sessions with less-trusted colleagues.
Acceptance criteria
- A non-
all codex handle cannot invoke any external-action tool feature, and this stays true as Codex adds features (i.e. an allowlist-based approach, or a version check that fails loudly on unknown enabled features).
- Regression test that a newly-added (mocked) enabled feature is disabled/blocked without a code change.
Refs: PR #102, claude_code_tools/agent_tunnel/codex_backend.py (_DISABLED_FEATURES, build_codex_flags).
Background
agent-tunnelnow supports tunneling Codex CLI sessions (#102). Access levels (read/write/bash/all) are enforced through Codex's OS sandbox, which governs shell command execution (filesystem + network).The gap
Codex's OS sandbox does not govern its non-shell tool surfaces. Codex ships ~20 default-on "features" (see
codex features list) — e.g.apps,browser_use*,computer_use,in_app_browser,image_generation,code_mode_host,hooks, MCP servers, web search — that can take external actions (write files, hit the network, drive a browser) outside the sandbox. So areadhandle, which is supposed to be look-but-don't-touch, could in principle trigger one of these.Contrast with the Claude backend, which is airtight here because it uses a strict tool allowlist (
--allowedTools Read,Grep,Glob) — anything not on the list simply doesn't exist for the fork.What PR #102 already does (the mitigation shipped)
For every non-
allcodex handle,build_codex_flagsdisables the clear external-action surfaces:-c mcp_servers={}(MCP connectors)-c tools.web_search=false--disablefor:apps,browser_use,browser_use_external,browser_use_full_cdp_access,computer_use,in_app_browser,image_generation,code_mode_host,hooksIt also strips
-o/--output-last-message(a host-side file write) fromheadless_extra_args. This is documented indocs/agent-tunnel-spec.md(Security model + "Codex CLI sessions").Why this is a follow-up, not "done"
The
--disableset is hard-coded and codex-version-specific (captured fromcodex features liston codex-cli 0.144.4). A newer Codex release can add an external-action feature that isn't on our list, silently reopening the gap. There is no single "restrict to a minimal toolset" switch equivalent to Claude's allowlist.Options to consider
servestartup (or per turn), runcodex features list, and--disableeverystable/truefeature that isn't on a small explicit allowlist of safe/passive ones. This inverts the model (allowlist, like Claude) and auto-tracks new features. Cost: acodex features listcall + maintaining the safe-allowlist.--disableset, and rely on the doc note telling publishers to auditcodex features listbefore sharing Codex sessions with less-trusted colleagues.Acceptance criteria
allcodex handle cannot invoke any external-action tool feature, and this stays true as Codex adds features (i.e. an allowlist-based approach, or a version check that fails loudly on unknown enabled features).Refs: PR #102,
claude_code_tools/agent_tunnel/codex_backend.py(_DISABLED_FEATURES,build_codex_flags).