rm-on-variable-path confirmation dialog fires under bypassPermissions with no way to disable/detect it, freezing unattended background agents for hours
Summary
The "Dangerous rm operation on possibly-empty variable path" confirmation dialog fires even under bypassPermissions mode, and cannot be suppressed by any permissions.allow rule or PreToolUse hook returning allow. In an unattended multi-agent setup (background teammate sessions spawned via the Agent/Task tool, running with no one watching the terminal), this silently freezes the teammate's pane until a human happens to notice and click through it.
Impact
Running Claude Code with background/teammate agents (the documented Agent-team pattern), a teammate that emits any rm -r/rm -rf command touching a shell-variable path stalls indefinitely — not for seconds, but until a human physically clicks "yes" in that pane's terminal. Measured on our end: one teammate sat frozen for ~13 hours, another for ~8 hours more shortly after, both fully idle, silently waiting on a dialog nobody knew existed until we happened to check the pane directly.
This is a severe usability regression for any workflow that relies on bypassPermissions specifically because it promises unattended execution. If a check is going to override bypassPermissions, it needs a way to be silenced (e.g., an explicit opt-out flag/env var), or at minimum it needs to be observable from outside the frozen pane (surfaced to the spawning session, or logged somewhere pollable) so an orchestrating process can detect and handle it instead of a human being the only possible unblock path.
Reproduction
Any of the following patterns raise the confirmation, even in bypassPermissions mode:
rm -rf "$T"(quoted variable path)rm -rf "$TMP/x"trap 'rm -rf "$TMP"' EXIT- Confirmed to also fire on non-rm content that merely contains the literal text
rm -rnear a$var-shaped path — e.g. agreppattern string like'rm -rf\|rm -r 'followed by a"$D/$s.jsonl"-style path in the same Bash call raised the same dialog, with normactually being executed.
What we've verified
- Per Claude Code's own docs (
https://code.claude.com/docs/en/permission-modes.md, sections "Skip all checks with bypassPermissions mode" and "Critical paths"):rm/rmdirremovals targeting a "critical path" still prompt inbypassPermissions, and nopermissions.allowrule orPreToolUsehook returningallowcan approve it. - No environment variable, CLI flag, settings key, or hook we could find disables this specific check.
- The check appears to be a textual/pattern scan on the submitted command text, not a semantic check of what the command actually does — see the grep-pattern false-positive above.
Ask
Either:
- An explicit, documented opt-out (env var or settings flag) for this specific check, scoped narrowly enough that it doesn't reopen the broader "critical path" protections
bypassPermissionsalready carves out exceptions for, or - A way for an orchestrating/parent session to be notified when a spawned teammate is blocked on this dialog, so it can be handled programmatically instead of requiring a human to physically be at the keyboard.
Happy to provide more reproduction detail if useful.
Showing cached comments. Read the full discussion on GitHub ↗
3 Comments
Update: confirmed a second, broader trigger — NOT just
rm -rA teammate session just diagnosed a ~35.5-hour freeze (submitted, sat blocked, only ran after a human physically clicked through) on a Bash call that contained no
rm -r/rm -rfat all — it had been deliberately avoiding that exact pattern the whole run per our own internal mitigation doc.The blocked call was a
cat > file <<'HEREDOC'writing a ~241-line script followed bybash -non it. Diffing the shell content against three earlier, structurally similar calls from the same session that ran unblocked, the only shapes unique to the blocked one were:cp -R "$SOME_VAR" "$OTHER_VAR"— a recursive copy with two shell-variable operandsmkdir -p "$HOME/.some/path"— a write under$HOMENon-recursive
rm -f "$VAR"/*lines were present in both the blocked call and the earlier ones that ran clean, ruling outrm -fas the discriminator. The most likely trigger, by elimination, is the recursivecp -Rwith two variable paths — the same "critical path" textual-scan class as the documentedrm -rbehavior, just not limited torm.This matters for the ask above: if the check's scope is "any recursive filesystem verb with a variable operand," not just
rm, then avoidingrm -rf(the only documented trigger) is not sufficient to keep an unattended agent from freezing —cp -R, and plausiblymv,cp -r,rsync, etc. with variable paths may trip the identical unbypassable, unobservable dialog. We were not able to confirm this from inside the session (the tool call returns as an ordinary success after the click, with no denial/prompt payload visible to the calling process), so this is inference from a diff of what passed vs. what didn't rather than a captured error.If it's useful, happy to try to construct a minimal, isolated repro (a small script with a bare
cp -R "$A" "$B"underbypassPermissions) rather than relying on this after-the-fact diff.+1
Same issue on 2.1.296, Linux,
bypassPermissions. The prompts come fromgeneral-purposesubagents writing throwaway test scaffolding. Three prompts in one session:The check is right each time.
${c:?}doesn't help becausecis never empty, onlyTcan be. That makes the main problem the feedback loop, not detection:Suggestion: in
bypassPermissions(at least for subagents), return the check as a tool error to the model with the same explanation, instead of blocking on a human. The agent can rewrite the command (rm -rf "${T:?}/${name:?}", absolute path) and keep going unattended. Nobody's pane freezes, and the safety property still holds.Our workaround for now: a CLAUDE.md rule that subagents load ("guard every variable at the
rmsite; nocd; rm ../..; never rm a$(...)/catresult directly").