Permission system bypassed by command chaining AND command options (new attack vector)

Resolved 💬 10 comments Opened Dec 8, 2025 by Aujourduy Closed May 1, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

The permission system in settings.json can be completely bypassed through two methods:

  1. Command Chaining (known - related to #4956, #612): Shell operators like &&, ;, || bypass detection
  2. Command Options (NEW): Options inserted between command and subcommand bypass detection

Users configure protections that don't actually protect them.

What Should Happen?

When a user blocks "git commit" via "ask": ["Bash(git commit:*)"], ALL variations should be caught:

  • cd /tmp && git commit → should be blocked
  • git -C /path commit → should be blocked
  • git --no-pager commit → should be blocked

The permission system should parse shell structure and normalize commands before matching.

Error Messages/Logs

No error - commands execute silently when they should be blocked.

Steps to Reproduce

  1. Configure settings.json with: "ask": ["Bash(git commit:*)"]
  1. Test bypass method 1 - Command chaining:
  • Ask Claude to run: cd /tmp && git commit -m 'test'
  • Observe: Command executes WITHOUT asking for permission
  1. Test bypass method 2 - Command options:
  • Ask Claude to run: git -C /path commit -m 'test'
  • Observe: Command executes WITHOUT asking for permission
  1. Additional bypass examples that all execute without permission:
  • echo test ; git rm file.txt
  • git --no-pager push origin main
  • git -c user.name='Bot' commit
  • rm --force --recursive /home (if "rm -rf" is blocked)
  • docker --host tcp://x rm container (if "docker rm" is blocked)

Claude Model

Sonnet (default)

Is this a regression?

No, this never worked

Last Working Version

_No response_

Claude Code Version

2.0.34 (Claude Code)

Platform

Other

Operating System

Ubuntu/Debian Linux

Terminal/Shell

Windows Terminal

Additional Information

Root Cause

Permission system uses simple startsWith() matching. It cannot:

  • Parse shell structure (&&, ;, ||, pipes)
  • Handle options before subcommands
  • Normalize command variations

Impact

  • False sense of security: Users believe they are protected when they are not
  • Affects ALL commands: Not just Git - any command with options can be bypassed

Suggested Solution

A PreToolUse hook that:

  1. Always denies dangerous commands to Claude
  2. Launches external script with GUI popup for user confirmation
  3. Executes command outside Claude's control if user approves

I have a working implementation (100% bypass prevention, 0% false positives) - happy to share if useful.

View original on GitHub ↗

This issue has 10 comments on GitHub. Read the full discussion on GitHub ↗