[Bug] No guardrail prevents an agent from committing a plaintext credential; PreToolUse Bash hooks must fail open

Status Open
Maintainer reply None cached
Activity 0 comments · opened Aug 24, 2026

Summary

An agent running in auto/bypass mode staged 66 files in one shot and committed a plaintext credential, then pushed it. Nothing in Claude Code stood in the way: git commit is just another Bash call. The value sat in a remote repository for ~4 hours before a review bot caught it — after the fact, in a code review, not before the write.

There is no built-in guardrail for this, and the two workarounds available to users both have gaps worth reporting.

What happened

  1. To satisfy an earlier review finding ("index references files missing from the commit"), the agent bulk-copied 66 files into the staging area without reading their contents.
  2. One file contained SECRET = '<value>' in plaintext.
  3. git add + git commit + git push all executed with no prompt, no warning, no scan.
  4. The leak was found only when an external review bot flagged the committed line.
  5. Remediation required redacting the value and rewriting branch history — which cleans the branch but does not undo the exposure; the orphaned commit stays reachable by SHA.

The agent was at fault for not reading what it staged. But bulk-staging is exactly what agents do, and this failure mode is available in every installation by default.

Why the existing mechanisms don't cover it

PostToolUse runs after the command. For Bash, that means the commit already happened. It can observe, not prevent. This isn't documented clearly enough — it's easy to wire up a "protection" that only witnesses the damage.

PreToolUse with a Bash matcher works, but the failure policy inverts. I wrote one (it now blocks commits and pushes containing high-confidence secret patterns, verified live). The catch: with a narrow matcher you can afford to deny when the hook can't parse its input — "if it fired, there was something to judge". With matcher: "Bash" you cannot: denying on internal error would block every command on the machine. So the hook must fail open, which means a broken hook silently equals no protection. Related, already reported: #88738 and #85430.

The live settings.json isn't versioned. Whether a guardrail is active depends on a file that no PR touches. Merging or reverting a commit that "adds a hook" changes nothing about what is actually enforced — a real gap when configuration is expected to be reviewable.

Suggestion

A built-in secret scan on git commit/git push — even as a warning rather than a block — would close the most common path. Agents stage in bulk and rarely read what they staged; the current design leaves the last line of defense to a post-hoc code review, which is one push too late.

Environment

  • Claude Code desktop, auto mode, multiple concurrent sessions
  • macOS
  • Agent operating autonomously on git repositories

Not reported here

The same session produced several errors that were the agent's own performance, not product defects — wrong first diagnosis, badly constructed measurements, files committed unread. Those were fixed with written rules and the hook above. I'm listing only what looks structural.

View original on GitHub ↗