anthropics / anthropics/claude-code
[Bug] No guardrail prevents an agent from committing a plaintext credential; PreToolUse Bash hooks must fail open
- Vorherrschende Sprache
- Python
- Sterne
- 145k
- Forks
- 23.1k
- PR-Merge-Kennzahlen
- PR-Kennzahlen ausstehend
Beschreibung
## 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 = ''` 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.
Beitragsleitfaden
Für dieses Repository ist kein Beitragsleitfaden indexiert
Rechercherichtung
Start by reading the PreToolUse and PostToolUse Bash hook behavior and the live settings.json configuration described in the issue; compare the related reports #88738 and #85430. Define how protection should apply before git commit and git push, including whether detection warns or blocks and how hook failures are handled. Done means the guardrail acts before the write and its behavior is covered by the project’s relevant checks.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- bash, git
- Bereich
- cli, devtools, security
- Issue-Typ
- Bug
- Schwierigkeit
- 5/5
- Geschätzter Aufwand
- Über eine Woche
- Aktivitätsstatus
- Aktiv
- Klarheit
- Größtenteils klar
- Anfängerfreundlichkeit
- 35/100