anomalyco / anomalyco/opencode

bash permission rules non-deterministic for `rm *`, `mv *`, `cp *` patterns

Open
#39,001 2 comments 0 reactions 1 assignee View on GitHub

@kitlangton is already working on this.

Since Jul 26, 2026.

Dominant language
TypeScript
Stars
209k
Forks
27.5k
PR merge metrics
PR metrics pending

Description

Description

Bash permission rules with anchored patterns (rm *, mv *, cp *) are non-deterministic: the same command, run multiple times in identical conditions, sometimes triggers the ask prompt and sometimes executes silently. 50% bypass rate for rm, 90% bypass rate for mv in my testing.

When the rule fires:

! permission requested: bash (rm /tmp/test.txt); auto-rejecting
✗ rm /tmp/test.txt failed

When it doesn't fire, the rm is executed and the file is removed — no prompt, no log entry.

Static config is correct: opencode debug config shows rm *: ask, and a Python reproducer of Wildcard.match confirms rm /tmp/test.txt matches rm * (returns True). The bug is at the bash tool invocation layer, not the pattern matcher.

Plugins

None

OpenCode version

1.18.3

Steps to reproduce
  1. Configure bash rules:
    {
      "permission": {
        "bash": {
          "*": "allow",
          "rm *": "ask",
          "mv *": "ask",
          "cp *": "ask"
        }
      }
    }
    
  2. From any cwd, run:
    for i in $(seq 1 20); do
      echo "X" > /tmp/test_$i.txt
      out=$(timeout 15 opencode run --model <model> "Run: bash -c 'rm /tmp/test_$i.txt'" 2>&1)
      has_prompt=$(echo "$out" | grep -c "permission requested")
      file_exists=$(ls /tmp/test_$i.txt 2>/dev/null | wc -l)
      echo "Run $i: prompt=$has_prompt file_exists=$file_exists"
    done
    
  3. Observe that rm /tmp/test_$i.txt is sometimes blocked and sometimes executed silently.
Reproduction data

Test 1 — rm (20 runs): 10/20 prompts fired, 10/20 bypassed. Several sample runs:

  • Run 1: prompt=0 file_exists=0 (NO PROMPT, file deleted ⚠)
  • Run 2: prompt=1 file_exists=1 (correct)
  • Run 3: prompt=0 file_exists=0 (NO PROMPT, file deleted ⚠)
  • Run 4: prompt=1 file_exists=1 (correct)

Test 2 — mv /tmp/a /tmp/b (10 runs): 1/10 prompts fired, 9/10 bypassed. ⚠

Test 3 — full output capture (5 runs):

  • Run 1: bash -c 'rm /tmp/full_test_1.txt' → PROMPT, file intact ✓
  • Run 2: bash -c 'rm /tmp/full_test_2.txt' → NO PROMPT, file DELETED ⚠
  • Run 3: agent did not invoke bash → file intact
  • Run 4: → PROMPT, file intact ✓
  • Run 5: → PROMPT, file intact ✓
Screenshot and/or share link

Not applicable — deterministic rule on paper, non-deterministic in practice. Numerical evidence above is reproducible.

Operating System

Ubuntu 24.04

Terminal

gnome-terminal (Wayland)

Additional context
  • Other tools (read, edit, glob, grep) enforce rules consistently. The bug is specific to the bash tool.
  • external_directory (path-level) works correctly.
  • Most likely cause: the bash tool's allStructured parser (packages/opencode/src/permission/wildcard.ts) doesn't match the head/tail split correctly for all bash -c "..." invocations, or there's a race condition in the permission check.
  • Related but distinct issue: #35882 (plugin-rewritten commands). My repro uses no plugins.
  • Impact: users relying on bash rules for destructive command protection in unattended sessions have a false sense of security. Running opencode with --yolo or --auto in unattended mode is unsafe — bash rules cannot be relied upon to block destructive operations.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.