Command escalation information look to be not available in Codex hooks

Open 💬 6 comments Opened Jun 13, 2026 by patatoid
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What version of Codex CLI is running?

0.139.0

What subscription do you have?

Pro 5x

Which model were you using?

gpt-5.5 medium

What platform is your computer?

Linux 6.12.90+deb13.1-amd64 x86_64 unknown

What terminal emulator and version are you using (if applicable)?

neovim

Codex doctor report

What issue are you seeing?

The escalated command was approved and executed successfully. From the hook side, escalation does not seem available or enforceable enough to distinguish this from other command authorization cases.

What steps can reproduce the bug?

Uploaded thread: 019ec28d-72b9-7d10-8f21-0f4f32c88dba

What is the expected behavior?

Hook payloads should expose escalation state and target command details in a way that allows a hook to make an enforceable decision before the command runs. If a hook returns a block decision, the escalated operation should not execute.

Additional information

I encountered the issue while working on a hook https://github.com/malach-it/boruta-server/pull/163, I am discovering hooks then I may be wrong, sorry if it is the case.

Thank you for your work on Codex

View original on GitHub ↗

6 Comments

github-actions[bot] contributor · 1 month ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #27833
  • #27342

Powered by Codex Action

patatoid · 1 month ago

A rephrase suggestion from Codex

Command escalation appears to surface to Codex’s approval system, and hooks have a PermissionRequest lifecycle event, but the hook documentation does not clearly define whether escalation metadata is available to hooks in a stable payload field. This makes it hard for policy hooks to reliably distinguish normal command execution from sandbox-escalated command execution.
SylvainWinning · 1 month ago

I think the key distinction here is not only whether hooks can see the shell command, but whether they can make a policy decision on the permission transition.

From a hook author perspective, the useful contract would be something like:

  • PreToolUse for Bash includes the command as it does today.
  • PermissionRequest includes a stable reason/category for the requested elevation, e.g. sandbox escape vs network vs write outside workspace.
  • If a hook blocks the PermissionRequest, the elevated command is not executed even if the normal tool call would otherwise be allowed.

That would let policy hooks distinguish “ordinary command inside current permissions” from “same command after an escalation request”. Without that, a hook can block broad command patterns, but cannot express rules such as “allow this command in the sandbox, deny it if it requests filesystem escalation”.

A useful test case would be: configure a hook that allows Bash generally, blocks only permission requests with an escalation marker, then run a command that requires escalation. Expected: command never runs and the user sees the hook block reason.

patatoid · 1 month ago

Hi @SylvainWinning,

Thank you for your reply, would you have more information about the category/reason you highlighted. I tested to get the information from sandbox_permissions in hook payload and did not get any meaningful results. Maybe is there other keys I am missing?

A useful test case would be: configure a hook that allows Bash generally, blocks only permission requests with an escalation marker, then run a command that requires escalation. Expected: command never runs and the user sees the hook block reason.

This is exactly the test case I am trying to solve, I have pretty good results with other markers but not with the escalation one.

SylvainWinning · 1 month ago

Thanks for checking. The field I had in mind is on the PermissionRequest hook payload, not sandbox_permissions.

For the current documented payload, the relevant pieces are:

  • tool_name should be Bash
  • tool_input.command has the command being requested
  • tool_input.description may contain the human-readable approval reason, when Codex has one

So for that test case I would try matching the PermissionRequest event for Bash and inspecting tool_input.description, then returning a deny decision from that hook.

That said, I think your core point is still valid: I don’t see a stable/documented field today that says “this request is specifically a sandbox escalation” or exposes the escalation category as structured data. If description is empty or too generic for this path, then this is probably not something your hook can enforce robustly yet, and the issue should stay open as a request/bug for a structured escalation marker in the PermissionRequest payload.

Necmttn · 29 days ago

The useful boundary here is the permission transition, not just the shell command. A hook can already reason about Bash; what it needs is a stable way to say "this same command is fine inside the current sandbox, but not after escalation."

A minimal PermissionRequest contract that would make that enforceable:

  • permission_request_id and tool_call_id, so later allow/deny/audit events can be tied back to the exact request
  • permission.kind, e.g. sandbox_escape, network, write_outside_workspace, or whatever categories Codex actually uses internally
  • current_sandbox and requested_sandbox, not just a human-readable description
  • structured escalation_reason.code plus optional escalation_reason.text; hooks should not have to parse prose
  • tool_name, tool_input.command, and cwd copied into the request payload so the hook does not need to correlate separate events before deciding

Ordering matters too: if a hook denies the PermissionRequest, the elevated operation should not run, and no successful PostToolUse/exec-result event should be emitted for that elevated attempt. If Codex emits an audit event, it should carry the same permission_request_id with decision=denied.

The regression test I would want is narrow: allow ordinary Bash, deny only PermissionRequest where permission.kind == sandbox_escape, run a command that requires escalation, and assert the command never executes.

---

_Generated with ax._