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:
- Command Chaining (known - related to #4956, #612): Shell operators like
&&,;,||bypass detection - 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 blockedgit -C /path commit→ should be blockedgit --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
- Configure
settings.jsonwith:"ask": ["Bash(git commit:*)"]
- Test bypass method 1 - Command chaining:
- Ask Claude to run:
cd /tmp && git commit -m 'test' - Observe: Command executes WITHOUT asking for permission
- Test bypass method 2 - Command options:
- Ask Claude to run:
git -C /path commit -m 'test' - Observe: Command executes WITHOUT asking for permission
- Additional bypass examples that all execute without permission:
echo test ; git rm file.txtgit --no-pager push origin maingit -c user.name='Bot' commitrm --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:
- Always denies dangerous commands to Claude
- Launches external script with GUI popup for user confirmation
- 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.
This issue has 10 comments on GitHub. Read the full discussion on GitHub ↗