codex - 💡(How to fix) Fix Code Mode `exec` doesn't fire `PreToolUse` hooks (fix patch attached) [1 comments, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openai/codex#23411Fetched 2026-05-20 03:50:32
View on GitHub
Comments
1
Participants
1
Timeline
11
Reactions
0
Author
Participants
Timeline (top)
labeled ×4cross-referenced ×3closed ×1commented ×1

Fix Action

Fix / Workaround

Code Mode's freeform exec tool — the JavaScript-execution surface in codex-rs/core/src/tools/code_mode/ — is not emitting PreToolUse hook events. This is the same bug class that #18391 fixed for apply_patch: a freeform tool whose handler doesn't opt into pre_tool_use_payload is silently invisible to the hook runtime.

Concretely, CodeModeExecuteHandler::pre_tool_use_payload is unimplemented and inherits the default None from ToolHandler, so tools::registry::run_pre_tool_use_hooks is never invoked for Code Mode dispatches. Hook-based policy, auditing, and write coordination observe shell commands (Bash) and apply_patch edits but miss every Code Mode execution — including the nested tool calls those executions issue via tools.exec_command, tools.apply_patch, and friends.

For users running Code Mode behind hook-based sandboxing or access control, this means policy enforcement that appears to be in effect for shell tools is silently bypassed whenever the model routes the same intent through a Code Mode dispatch.

RAW_BUFFERClick to expand / collapse

Why

Code Mode's freeform exec tool — the JavaScript-execution surface in codex-rs/core/src/tools/code_mode/ — is not emitting PreToolUse hook events. This is the same bug class that #18391 fixed for apply_patch: a freeform tool whose handler doesn't opt into pre_tool_use_payload is silently invisible to the hook runtime.

Concretely, CodeModeExecuteHandler::pre_tool_use_payload is unimplemented and inherits the default None from ToolHandler, so tools::registry::run_pre_tool_use_hooks is never invoked for Code Mode dispatches. Hook-based policy, auditing, and write coordination observe shell commands (Bash) and apply_patch edits but miss every Code Mode execution — including the nested tool calls those executions issue via tools.exec_command, tools.apply_patch, and friends.

For users running Code Mode behind hook-based sandboxing or access control, this means policy enforcement that appears to be in effect for shell tools is silently bypassed whenever the model routes the same intent through a Code Mode dispatch.

Reproduction

Verified on rust-v0.130.0. Probe a model in Codex via any client with hooks configured (e.g. via Openclaw's @openclaw/codex plugin); request a tool call. The model often routes through Code Mode exec (a custom_tool_call with name: "exec", input = raw JavaScript). The configured PreToolUse hook command is never invoked. Direct function_call: exec_command dispatches DO fire the hook correctly, confirming the bug is specifically that Code Mode's handler doesn't opt in.

Proposed Fix

Branch ready in fork: https://github.com/Kaspre/codex/tree/fix/code-mode-pretooluse-hook Compare URL (for direct review): https://github.com/openai/codex/compare/main...Kaspre:codex:fix/code-mode-pretooluse-hook

What Changed

  • Added PreToolUse payload support to CodeModeExecuteHandler via pre_tool_use_payload, extracting the raw JavaScript source from ToolPayload::Custom { input } and exposing it as tool_input.command.
  • Added HookToolName::code_mode_exec() modeled on HookToolName::apply_patch() — canonical hook name code_mode_exec (distinct in logs and policies from Bash shell tools), with exec accepted as a matcher alias for hook configurations written against the model-facing tool name.

The tool_input.command field name matches the existing convention shared by apply_patch, shell_command, and unified_exec — all carry "the thing to execute" under command regardless of whether the underlying input is shell text, patch text, or (with this change) JavaScript source. This lets a single hook policy expression apply uniformly across execution surfaces.

PostToolUse payload support is intentionally out of scope for this change — happy to add it as a follow-up if maintainers want symmetric coverage with apply_patch.

Verification

Added focused handler coverage in code_mode/execute_handler_tests.rs:

  • Freeform Code Mode (ToolPayload::Custom) dispatches produce a PreToolUsePayload whose tool_name is code_mode_exec and whose tool_input.command matches the raw JavaScript source.
  • Non-Custom payloads return None (defensive — the registry's matches_kind already gates this, but the handler shouldn't assume).

The pre-existing execute_handler_tests.rs in this directory was orphaned (#[path] declaration removed; references a parse_freeform_args function that no longer exists) and has been replaced. Wired in via the standard #[cfg(test)] #[path = "execute_handler_tests.rs"] mod tests; declaration at the bottom of execute_handler.rs, matching the convention used by apply_patch.rs and shell.rs.

Filing notes

External PR creation appears to be staff-restricted on this repo (gh pr create returns does not have the correct permissions to execute CreatePullRequest). Filing as an issue with the patch attached as a fork-branch ref for cherry-pick. Happy to convert this to a PR if a maintainer can open it on my behalf, or to follow whatever the preferred contribution flow is.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING