PreToolUse Hooks: Prevent Dangerous Command String Replacements

Resolved 💬 2 comments Opened Jul 1, 2025 by smartpuppy Closed Jul 28, 2025

Bug Description
⏺ String Replacement Risks in Hook Command Modification

Summary

When PreToolUse hooks gain the ability to modify commands (per issue #2814), naive string replacement could cause catastrophic unintended modifications.
Documentation should warn users and provide guidance on safe command parsing.

Context

Once hooks can modify tool_input (currently broken), users will likely implement command corrections like python→python3. However, simple string replacement is
dangerous.

The Problem

A naive implementation like this:
command = input_data.get('tool_input', {}).get('command', '')
if 'python' in command:
command = command.replace('python', 'python3')

Would cause these disasters:

  1. Search Command Corruption

grep "python" requirements.txt → grep "python3" requirements.txt ❌
rg "import python" → rg "import python3" ❌
Result: Searches for wrong strings, missing actual matches

  1. File Operation Failures

mv python-utils.py backup/ → mv python3-utils.py backup/ ❌
rm old-python-scripts/ → rm old-python3-scripts/
cat python_config.json → cat python3_config.json ❌
Result: Operations on non-existent files, data loss

  1. String Content Corruption

echo "Use python3 not python" → echo "Use python33 not python3" ❌
sed 's/python/python3/g' file → sed 's/python3/python33/g' file ❌
Result: Corrupted documentation and code

  1. Path Corruption

cd /usr/local/python-3.12/ → cd /usr/local/python3-3.12/ ❌
./scripts/python-installer.sh → ./scripts/python3-installer.sh ❌
Result: Navigation to wrong directories, script execution failures

Safe Implementation Requirements

Proper command modification requires:

  1. Command Parsing - Identify the actual executable vs arguments
  2. Context Awareness - Only modify when string is the command itself
  3. Boundary Detection - Use word boundaries to avoid partial matches
  4. Argument Preservation - Never modify command arguments

Example safer approach:
import shlex

parts = shlex.split(command)
if parts and parts[0] == 'python':
parts[0] = 'python3'
command = shlex.join(parts)

Recommendations

  1. Documentation Updates
  • Add prominent warnings about string replacement dangers
  • Provide safe command parsing examples
  • List common pitfalls with examples
  1. Built-in Safeguards
  • Consider providing utility functions for safe command modification
  • Add hook validation that warns about naive string operations
  1. Example Templates
  • Provide tested examples for common use cases (python→python3, etc.)
  • Show proper command parsing techniques

Impact

Without proper guidance, users will create hooks that:

  • Break their workflows in subtle ways
  • Cause data loss through wrong file operations
  • Create hard-to-debug issues
  • Generate user frustration and distrust

Related Issues

  • #2814 (Hooks cannot modify commands - the underlying issue)

Priority

High - This guidance should be available when #2814 is fixed to prevent widespread user issues.

Environment Info

  • Platform: darwin
  • Terminal: Apple_Terminal
  • Version: 1.0.38
  • Feedback ID: 38cf8cc4-2acc-4f1c-a7a2-5cd1b29d9fa2

Errors

[{"error":"Error: Command failed: security find-generic-password -a $USER -w -s \"Claude Code\"\nsecurity: SecKeychainSearchCopyNext: The specified item could not be found in the keychain.\n\n    at genericNodeError (node:internal/errors:983:15)\n    at wrappedFn (node:internal/errors:537:14)\n    at checkExecSyncError (node:child_process:892:11)\n    at execSync (node:child_process:964:15)\n    at WI (file:///opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/cli.js:701:3921)\n    at file:///opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/cli.js:623:9038\n    at Q (file:///opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/cli.js:526:13327)\n    at SX (file:///opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/cli.js:623:8184)\n    at K_ (file:///opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/cli.js:623:7265)\n    at O9 (file:///opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/cli.js:623:11432)","timestamp":"2025-07-01T17:50:58.218Z"}]

View original on GitHub ↗

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