`--permission-mode dontAsk` bypasses `autoAllowBashIfSandboxed` for Bash commands containing shell variable expansion

Status Fixed / completed
Reported on v2.1.114
Maintainer reply ✓ Yes — claude[bot]
Activity 5 comments · opened Apr 20, 2026 · closed May 11, 2026
💡 Likely answer: A maintainer (claude[bot], contributor) responded on this thread — see the highlighted reply below.

Summary

When Claude Code is invoked with --permission-mode dontAsk and sandbox.autoAllowBashIfSandboxed: true, Bash commands that contain shell variable expansion (e.g. $VAR) are denied with "Permission to use Bash has been denied because Claude Code is running in don't ask mode" instead of being auto-approved through the sandbox.

Non-expansion Bash commands run correctly in the same session — so the sandbox is functional and auto-allow fires for those. The issue is specific to commands containing shell expansion.

The sandboxing documentation states:

Auto-allow mode works independently of your permission mode setting. Even if you're not in "accept edits" mode, sandboxed bash commands will run automatically when auto-allow is enabled.

This does not hold for expansion-bearing commands under dontAsk.

Environment

  • Claude Code: 2.1.114
  • OS: Linux (Ubuntu 24.04 on WSL2)
  • bubblewrap: 0.9.0
  • socat installed

Minimal Reproduction

settings.json:

{
  "permissions": { "allow": ["Read", "Glob", "Grep"] },
  "sandbox": {
    "enabled": true,
    "autoAllowBashIfSandboxed": true,
    "filesystem": {
      "denyRead": ["/"],
      "denyWrite": ["/"],
      "allowRead": [".", "/usr", "/etc"],
      "allowWrite": []
    }
  }
}

(Run from any git working tree with at least one commit.)

Failing case — command WITH expansion:

export TB=HEAD~1
claude -p "Run the bash command: git log --oneline -1 \$TB" \
  --permission-mode dontAsk --settings ./settings.json \
  --max-turns 3 --output-format stream-json --verbose < /dev/null

Tool result:

is_error=true: Permission to use Bash has been denied because Claude Code is running in don't ask mode.

Passing case — same session, same settings, same permission mode, but NO expansion:

claude -p "Run the bash command: git log --oneline -1" \
  --permission-mode dontAsk --settings ./settings.json \
  --max-turns 3 --output-format stream-json --verbose < /dev/null

Tool result:

is_error=false: <commit sha> <commit subject>

The only variable is the presence of $TB in the command string. The sandbox configuration, permission mode, and autoAllowBashIfSandboxed: true are identical.

Expected

Both commands auto-approved by the sandbox per the documented guarantee. Both return git log output.

Actual

  • Expansion command: permission-layer deny before the sandbox wrap is attempted.
  • Non-expansion command: executed inside the sandbox, output returned.

Impact

Any non-interactive workflow that relies on --permission-mode dontAsk (CI pipelines, scripted headless runs, agents invoked from external automation) cannot execute Bash commands containing shell expansion, even when the sandbox is fully capable of wrapping them safely. Models frequently generate commands with expansion when environment variables are semantically relevant (e.g. git diff \$TARGET_BRANCH...HEAD from a prompt that passes TARGET_BRANCH via env). Workarounds require rewriting commands to read env values separately and inline them, which is not always feasible for generated tool calls.

Likely 2.1.113 provenance

2.1.113 added a family of security hardenings around Bash matching/approval, including:

  • \"Security: Bash deny rules now match commands wrapped in \env\/\sudo\/\watch\/\ionice\/\setsid\ and similar exec wrappers\"
  • \"Security: \Bash(find:*)\ allow rules no longer auto-approve \find -exec\/\-delete\\"

These sibling changes suggest a set of heuristic checks were added that require approval for commands exhibiting certain patterns. If an expansion-heuristic was added at the same time and is evaluated before the sandbox auto-allow path, that would explain the observed behaviour.

Suggested fix

Either (a) evaluate \autoAllowBashIfSandboxed\ for expansion-bearing commands before rejecting under \dontAsk\, or (b) document the expansion-command exception in the sandboxing docs so users know the mode-independence guarantee has a scope.

View original on GitHub ↗

6 Comments

github-actions[bot] · 4 months ago

Found 2 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/43713
  2. https://github.com/anthropics/claude-code/issues/49874

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

0xbrainkid · 4 months ago

This is a good report because it isolates the bug to a very specific mismatch between documented permission semantics and actual command classification.

The documentation promise is clear: sandbox auto-allow should operate independently of permission mode. If that holds for ordinary Bash commands but fails only when shell expansion is present, then the runtime is treating expansion-bearing commands as a different permission class in a way the docs do not describe.

That matters because from the user/operator perspective, $VAR expansion is a normal shell feature, not a meaningful change in safety model. If the same sandbox and same session auto-allow one command but deny the same command shape with variable expansion, the control plane becomes surprising and hard to reason about.

So the core issue is not just a denial. It is inconsistency in the policy boundary. The system is exposing one rule in docs and another in practice depending on syntactic details that users would not expect to matter this much.

Permission systems have to be exact and legible. If shell expansion changes approval behavior, that needs to be either fixed or surfaced explicitly.

yurukusa · 4 months ago

Good analysis of the evaluation order issue. The root cause seems clear: expansion detection runs before autoAllowBashIfSandboxed gets a chance to allow the command.

As a workaround until this is fixed upstream, you can use a PreToolUse hook to manually approve expansion-bearing commands when you know they're safe:

#!/bin/bash
# allow-sandbox-expansion.sh — Approve variable expansion in sandboxed commands
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
[ -z "$COMMAND" ] && exit 0

# Only intervene for commands with shell variable expansion
if echo "$COMMAND" | grep -qE '\$[A-Za-z_]'; then
    # Log for audit but allow (exit 0 = approve)
    echo "INFO: Allowing command with variable expansion in sandbox: ${COMMAND:0:80}" >&2
    exit 0
fi

exit 0

This won't fix the underlying permission-layer ordering, but it gives you a way to unblock CI/CD pipelines that depend on dontAsk + sandbox.

olejorgenb · 4 months ago
claude[bot] contributor · 3 months ago

This issue was fixed as of version 2.1.139.

github-actions[bot] · 2 months ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.