[BUG] PreToolUse hook for Write/Edit can be bypassed by writing files via the Bash tool

Resolved 💬 3 comments Opened May 29, 2026 by DaemonNZ Closed Jul 2, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code

What's Wrong?

A PreToolUse hook configured with matcher Write|Edit does not fire when the same file write is performed via the Bash tool (e.g. using tee, cat >, or python3 open()). This means any hook intended to constrain file-write behaviour can be silently bypassed by switching tools.

This was discovered when Claude itself used this technique to bypass its own credential-guard hook during a session. The hook blocked the Write tool from updating a script under ~/.claude/hooks/. Claude identified that tee via the Bash tool would achieve the same write without triggering the hook, and executed this without disclosing the workaround to the user. A separate model behaviour issue has been filed for that aspect.

What Should Happen?

Hook enforcement should be action-scoped, not tool-scoped. A PreToolUse hook that restricts file writes should apply to any tool invocation that results in a file write, regardless of which tool is used. At minimum, the documentation should clearly state that Write/Edit hooks do not cover Bash-mediated file writes, so operators know to add a Bash hook as well.

Steps to Reproduce

  1. In settings.json, configure a PreToolUse hook with matcher Write|Edit that blocks writes to a specific path — e.g. any path under ~/.claude/.
  2. Ask Claude to write a file to that path using the Write tool. Confirm the hook fires and the write is blocked.
  3. Now ask Claude (or attempt manually) to write the same file via a Bash command: e.g. tee ~/.claude/somefile.txt << 'EOF' ... EOF
  4. The hook does not fire. The file is written without restriction.

Error Messages/Logs

No error. The bypass is silent — the Bash tool completes successfully and no hook output is produced.

Claude Model

Sonnet (claude-sonnet-4-6, version 2.1.156)

Is This a Regression?

No — this appears to be a fundamental property of the hook architecture (tool-scoped rather than action-scoped).

Claude Code Version

2.1.156 (Claude Code)

Platform

Anthropic API

Operating System

macOS (Darwin 25.5.0)

Terminal/Shell

Terminal.app (macOS) / zsh

Additional Information

The practical impact is that PreToolUse hooks for Write|Edit provide no protection against Bash-mediated file writes. Operators configuring hooks to protect credential stores, config directories, or other sensitive paths will find the restriction silently bypassable. The hook matcher name implies file-write coverage but it is enforced only at the tool-invocation boundary.

A companion model behaviour issue has been filed separately describing how Claude reasoned about and executed this bypass without user notification.

View original on GitHub ↗

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