You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Slice 4 of #399, and a decision that stands on its own.
The hole
Under Codex the guard inspects a shell command string. guard.ts's Bash branch records rather than blocks, on its own stated grounds that string matching is "too weak to be a boundary and too eager to be harmless".
That is fine while the guard is the only control. It becomes load-bearing the moment a sink check depends on the provenance record (#399): a command string structurally cannot tell us which files it read.cat, a script, a pipeline, a subshell — the guard sees one opaque string and the reply then ships against a record that is silently incomplete for that call.
No logging change closes this.#401's gap marker helps where the guard failed; here the guard succeeded and still learned nothing. This is not a bug to fix, it is a boundary of the mechanism.
The decision
A run that used Bash cannot release a reply above the caller's clearance. Fail-closed, consistent with "unlabelled is secret". Cost: a Codex line answering anything that shelled out is capped at public.
Document that the guarantee does not hold for Bash, and keep serving. Cost: the guarantee has an asterisk that owners will not read.
Recommendation: (1), with (3) as the mechanism. Bash is already absent from CLAUDE_READ_ONLY_TOOLS, so this is close to free on Claude; the cost lands entirely on Codex, where #391 is separately arguing for a public ceiling anyway.
What is not acceptable
Saying nothing. agentcall policy claiming a bound the runtime does not keep is exactly the defect #390 fixed in the documentation — this issue exists so it does not reappear in the runtime with the fix applied only to the prose.
Slice 4 of #399, and a decision that stands on its own.
The hole
Under Codex the guard inspects a shell command string.
guard.ts'sBashbranch records rather than blocks, on its own stated grounds that string matching is "too weak to be a boundary and too eager to be harmless".That is fine while the guard is the only control. It becomes load-bearing the moment a sink check depends on the provenance record (#399): a command string structurally cannot tell us which files it read.
cat, a script, a pipeline, a subshell — the guard sees one opaque string and the reply then ships against a record that is silently incomplete for that call.No logging change closes this. #401's gap marker helps where the guard failed; here the guard succeeded and still learned nothing. This is not a bug to fix, it is a boundary of the mechanism.
The decision
public.public. Removes the capability rather than the guarantee. Interacts with A Codex line enforces none of the sensitivity model — should it be callable? #391 option 3 (forcepublicon a Codex line), which would make this moot there — but Claude lines can reach Bash too if the allowlist ever widens (todayCLAUDE_READ_ONLY_TOOLSexcludes it, and The owner's skills and MCP servers are still unreachable — #372 wired only the path half #392's research is a reminder that the allowlist is not the only thing deciding what runs).Recommendation: (1), with (3) as the mechanism. Bash is already absent from
CLAUDE_READ_ONLY_TOOLS, so this is close to free on Claude; the cost lands entirely on Codex, where #391 is separately arguing for apublicceiling anyway.What is not acceptable
Saying nothing.
agentcall policyclaiming a bound the runtime does not keep is exactly the defect #390 fixed in the documentation — this issue exists so it does not reappear in the runtime with the fix applied only to the prose.Related
#399 (epic) · #391 (Codex enforces nothing) · #401 (gap marker) · #390