False Positive: Security Hook Blocking Write Tool on Non-Code Files
Resolved 💬 9 comments Opened Nov 1, 2025 by jagan-nuvai Closed Jan 30, 2026
False Positive: Security Hook Blocking Write Tool on Non-Code Files
Summary
The PreToolUse:Callback security hook is incorrectly blocking the Write tool when creating markdown documentation files, triggering a command injection warning despite no shell execution occurring.
Environment
- Platform: macOS (Darwin 24.3.0)
- Model: claude-sonnet-4-5-20250929
- Claude Code: 2.0.31
Issue Description
When attempting to write a markdown file using the Write tool, a security hook is incorrectly blocking the operation with this error:
Write(00-introduction.md)
⎿ PreToolUse:Callback hook returned blocking error
⎿ Error: ⚠️ Security Warning: Using child_process.exec() can lead to command injection vulnerabilities.
This codebase provides a safer alternative: src/utils/execFileNoThrow.ts
Instead of:
exec(`command ${userInput}`)
Use:
import { execFileNoThrow } from '../utils/execFileNoThrow.js'
await execFileNoThrow('command', [userInput])
Problem
- False Positive Detection: The
Writetool does not usechild_process.exec()- it's a file system operation - Incorrect Context: The security warning references source code patterns (
src/utils/execFileNoThrow.ts) but is triggered on markdown file creation - Blocks Legitimate Operations: Prevents writing documentation and non-executable files
- Confusing Error Message: Suggests code-level fixes for a file operation that doesn't involve shell execution
Expected Behavior
The security hook should:
- Only trigger on actual shell command execution (Bash tool, exec calls, etc.)
- Allow
Writetool operations on non-executable files (.md, .txt, .json, .yaml) - Distinguish between file content and shell commands
- Not block documentation file creation
Actual Behavior
The hook incorrectly:
- Treats markdown file writes as potential command injection vectors
- Blocks the
Writetool based on filename or content patterns - Provides irrelevant remediation advice for file operations
Reproduction Steps
- Use the
Writetool to create a markdown file:
````
Write("/path/to/00-introduction.md", <markdown_content>)
- Observe the
PreToolUse:Callback hook returned blocking error - Note the command injection warning despite no shell execution
Proposed Solutions
Option 1: Scope Hook to Bash Tool Only
// Only apply command injection checks to Bash tool
if (tool.name === 'Bash' && containsUnsafePattern(tool.command)) {
return blockingError;
}
Option 2: Whitelist Safe File Extensions
// Allow Write operations on documentation files
const safeExtensions = ['.md', '.txt', '.json', '.yaml', '.yml', '.toml'];
if (tool.name === 'Write' && isSafeExtension(tool.file_path)) {
return allowOperation;
}
Option 3: Content-Based Analysis
// Only check for command injection in shell contexts
if (tool.name === 'Bash' || isShellExecution(tool)) {
return analyzeCommandInjection(tool);
}
Impact
- Severity: Medium-High
- Affected Users: Anyone using Claude Code to create documentation or configuration files
- Workaround: None available - hook blocks the operation entirely
- Frequency: Occurs on every
Writetool invocation for certain file patterns
Additional Context
This appears to be a hook configuration issue where:
- The pattern matching is too broad (possibly regex matching on content vs. context)
- The hook doesn't differentiate between tool types (Write vs. Bash)
- Security checks intended for shell execution are applied to file I/O
Related Issues
- This may affect other file operation tools (Edit, NotebookEdit)
- Could block legitimate workflows involving file generation
- May impact automated documentation generation
Requested Fix
Please update the security hook to:
- Only apply command injection checks to shell execution contexts (Bash tool)
- Exclude file operation tools (Write, Edit) from shell security checks
- Add tool-specific validation logic
- Improve error messages to indicate which tool/operation triggered the block
This issue has 9 comments on GitHub. Read the full discussion on GitHub ↗