CLI: prefix_rule matching fails for shell wrappers and env-prefix commands

Resolved 💬 3 comments Opened Mar 1, 2026 by ignatremizov Closed Mar 1, 2026
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What version of Codex CLI is running?

codex-cli 0.106.0

What subscription do you have?

Pro

Which model were you using?

gpt-5.3-codex high

What platform is your computer?

MacOS Darwin 24.x arm64

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

Terminal.app (also reproducible in iTerm2)

What issue are you seeing?

Approval rules (prefix_rule) do not consistently apply when command execution is shell-wrapped (/bin/zsh -lc or /bin/bash -lc) or when a command uses leading environment assignments.

Two related failure modes:

  1. Existing prefix rules for the underlying command do not match if the executed command is seen as a shell wrapper script instead of normalized inner commands.
  2. Commands with env-prefix style invocation (for example GH_TOKEN=... gh ...) are treated as starting with the assignment token, so rules for gh do not match.

Result: Codex repeatedly asks for approval and proposes/stores overly specific rules like full /bin/zsh -lc '...' scripts, which are brittle and do not generalize.

What steps can reproduce the bug?

  1. Add this rule:

prefix_rule(pattern=["gh", "api"], decision="allow")

  1. Model executes a shell-wrapped command with redirection/connector (representative form):

/bin/zsh -lc 'gh api repos/openai/codex/issues/1 > /tmp/issue.json && jq ".number" /tmp/issue.json'

  1. Observe approval is requested even though gh api is allow-listed.
  2. Choose “Yes, and don't ask again…”.
  3. Observe saved rule is often wrapper/script specific (for example full /bin/zsh -lc '...') rather than a stable command prefix.
  4. Repeat with a small command variation (different output path/flags) and observe approval prompts again.
  5. Env-prefix variant: run GH_TOKEN=dummy gh api user with the same ["gh", "api"] allow rule; observe prompt instead of a match.

What is the expected behavior?

Policy evaluation and suggested amendments should use a normalized command representation:

  1. Shell wrappers should be unwrapped to the actionable inner command(s) when safely parseable.
  2. Leading env assignments (KEY=VALUE) prefixes should not prevent matching command-prefix rules.
  3. Approval rule suggestions should prefer stable/minimal prefixes (for example ["gh", "api"]) instead of full shell wrapper scripts.
  4. When parsing is ambiguous/unsafe, fallback should remain conservative (prompt) and avoid incorrect broad approvals.

Additional information

Potential implementation plan (codebase points):

  • Normalize command tokens for exec-policy matching and amendment derivation in codex-rs/core/src/exec_policy.rs:571.
  • Reuse wrapper extraction robustness similar to codex-rs/core/src/tools/runtimes/shell/unix_escalation.rs:544 (which scans argv for -c/-lc triples instead of requiring strict argv shape).
  • Extend shell command extraction/parsing beyond strict 3-token shell forms in codex-rs/shell-command/src/bash.rs:97.
  • Handle env-prefix forms (KEY=VALUE cmd ...) before policy lookup.
  • Keep approval-cache canonicalization and policy normalization aligned (codex-rs/core/src/command_canonicalization.rs:14, codex-rs/core/src/tools/runtimes/shell.rs:127, codex-rs/core/src/tools/runtimes/unified_exec.rs:87).

Relevant current behavior in code:

  • commands_for_exec_policy(...) falls back to raw argv when shell script parsing fails (codex-rs/core/src/exec_policy.rs:571).
  • Shell extraction currently assumes exact [shell, -c/-lc, script] form (codex-rs/shell-command/src/bash.rs:97).
  • Tests explicitly reject variable assignment prefixes in the shell parser (codex-rs/shell-command/src/bash.rs:425), which likely contributes to env-prefix mismatch behavior.

Potentially related reports:

  • #10920
  • #12095
  • #10321
  • #8980

View original on GitHub ↗

3 Comments

github-actions[bot] contributor · 5 months ago

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

  • #12095
  • #11298
  • #13117

Powered by Codex Action

marcindulak · 3 months ago

This issue is not a duplicate of https://github.com/openai/codex/issues/11298.

The original issue is about the prefix_rule forbidden rules bypassed by the models by the use of bash -lc, zsh -lc or other prefixes. In that sense this issue is duplicate of https://github.com/openai/codex/issues/10920.

adamncsu · 3 months ago

I’ve done additional testing and I think the issue is slightly different than I originally thought.

Environment:

  • Codex Windows Desktop 26.513.40821
  • Windows 11
  • Flutter/Dart workflow

Current behavior

During normal coding workflows, Codex frequently requests escalations using full PowerShell-wrapped command invocations such as:

[
    "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
    "-Command",
    "& 'C:\\dev\\flutter\\bin\\dart.bat' format lib\\foo.dart"
]

When I click “Always allow”, Codex persists that wrapped invocation directly into:

%USERPROFILE%\.codex\rules\default.rules

Example generated rule:

prefix_rule(
    pattern=[
        "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
        "-Command",
        "& 'C:\\dev\\flutter\\bin\\dart.bat' format lib\\foo.dart"
    ],
    decision="allow"
)

This behaves almost like an exact-command match rather than a reusable prefix rule.

For example:

  • approve:

``powershell
dart format lib/foo.dart
``

  • later Codex runs:

``powershell
dart format lib/bar.dart
``

  • Codex prompts again

I also reproduced this in a completely fresh test workspace. Asking Codex to create a Flutter project generated this rule:

prefix_rule(
    pattern=[
        "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
        "-Command",
        "& 'C:\\dev\\flutter\\bin\\flutter.bat' create --platforms=windows ."
    ],
    decision="allow"
)

Manual workaround

I manually edited default.rules and added broad rules myself:

prefix_rule(
    pattern=["C:\\dev\\flutter\\bin\\dart.bat", "format"],
    decision="allow"
)

prefix_rule(
    pattern=["C:\\dev\\flutter\\bin\\dart.bat", "analyze"],
    decision="allow"
)

prefix_rule(
    pattern=["C:\\dev\\flutter\\bin\\flutter.bat", "test"],
    decision="allow"
)

prefix_rule(
    pattern=["C:\\dev\\flutter\\bin\\flutter.bat", "analyze"],
    decision="allow"
)

These rules do work in some scenarios, which suggests the underlying rule engine is capable of evaluating generalized inner-command prefix rules correctly.

Important additional observation

I originally thought the issue was specifically that the “Always allow” flow was writing rules incorrectly. However, after more testing, I no longer think that is the complete explanation.

In one controlled test, I explicitly asked Codex to generate an escalation request for flutter analyze, and the resulting approval request was normalized correctly. Clicking “Always allow” generated a reusable rule in the expected format.

So Codex Desktop is clearly capable of generating normalized inner-command escalation requests that produce reusable prefix_rule entries.

However, during normal coding workflows, Codex still frequently emits wrapped PowerShell command forms like:

[
    "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
    "-Command",
    "& 'C:\\dev\\flutter\\bin\\dart.bat' format lib\\foo.dart"
]

Those wrapped forms do not appear to match the broad manually-authored rules consistently, even though the equivalent normalized command would.

So at this point, the issue appears to be inconsistent command normalization/canonicalization before rule matching and persistence:

  • some command paths are normalized correctly
  • other command paths are still evaluated and persisted as raw wrapped PowerShell invocations

This seems closely related to PR #20336, but there are still Windows Desktop command paths that do not appear to be using the normalized inner-command representation consistently.