Manual permission mode: file edits via Bash (python/sed) bypass per-edit diff review

Status Open
Maintainer reply None cached
Activity 1 comment · opened Aug 10, 2026

Summary

In manual permission mode, file modifications made through the Bash tool (e.g. a python3 heredoc or sed -i performing string replacements) bypass the per-edit diff review that the Edit/Write tools provide. The user is shown — at most — a single "run this command" prompt containing an opaque script, instead of one reviewable diff per changed file. If a broad Bash allowlist rule matches (e.g. Bash(python3 *), often added just to reduce prompt noise), there is no prompt at all.

What happened (real session)

  • User runs Claude Code in manual permission mode, specifically because they want to review every file change before it lands.
  • Earlier in the session, the user had rejected two Edit-tool calls, so per-edit review was demonstrably active and being used.
  • The model was asked to reword code comments across many files. It chose a python3 - <<'EOF' ... EOF heredoc via the Bash tool to do exact string replacements in 12 files in one shot.
  • The command executed and all 12 files were modified. Later the user asked: "did I actually confirm those edits?" — they had no memory of approving them, despite manual mode being on. In effect they hadn't: they (or an allowlist rule) approved "run this Python script", with no diff preview, no per-file granularity, and no trace in the edit-review UX.

No malice involved — the model picked a script because it was the efficient tool for many mechanical replacements. That is exactly what makes this a footgun: it happens naturally, in benign workflows.

Why this is a problem

  1. Manual mode reads as a review boundary, but it is only advisory for Bash. Users reasonably believe "manual mode = I see every change as a diff". Any write-capable shell command silently breaks that contract.
  2. Prompt asymmetry defeats review. A multi-line heredoc with embedded old/new strings is far harder to review in a permission prompt than a rendered diff. Users effectively rubber-stamp it.
  3. Allowlists amplify the gap. Innocent-looking rules like Bash(python3 *) or Bash(sed *) — typically added for read-only convenience — silently grant unbounded workspace writes with zero prompts.
  4. Nothing steers the model away from this. The harness does not discourage routing edits through Bash. Worse, if a user rejects an Edit call, the model can learn that Bash "works" where Edit gets scrutinized — inverting the intended control.

Suggested mitigations (any subset would help)

  • Guidance-level (cheap, immediate): strengthen the system-prompt/tool-choice guidance so the model never modifies workspace files via Bash when Edit/Write are available, or asks for explicit user consent before doing a scripted bulk edit.
  • Detection-level: Claude Code already tracks file state (it detects external modifications and file checkpointing exists for /rewind). After a Bash call, if tracked files changed, surface it: "This command modified N files" with an expandable diff — ideally before the result is consumed, or at least as a visible post-hoc notice with one-keystroke revert.
  • Policy-level (opt-in): a permissions option that treats write-capable Bash invocations as edits for prompting purposes, or lets users exclude the workspace from Bash writes (the sandbox filesystem controls exist but are off by default and not connected to the edit-review UX).

Repro

  1. Start claude with default/manual permissions in a git repo.
  2. Prompt: "Replace all occurrences of FOO with BAR in these ten files" (or any mechanical multi-file change).
  3. The model is likely to reach for python3/sed via Bash. Approve the single command prompt (or have Bash(python3 *) allowlisted → no prompt).
  4. Observe: all files modified; no per-file diff review occurred. Compare with a single-file change, where the Edit tool prompts with a rendered diff.

Environment

  • Claude Code CLI on Linux (Debian), manual permission mode
  • Model: claude-fable-5
  • Observed 2026-08-10

<sub>The above issue description was generated using Claude Code</sub>

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗