Skip to content

Add block-secret-files hook - #1

Merged
jackyraimond merged 5 commits into
mainfrom
add-block-secret-files
Aug 13, 2026
Merged

Add block-secret-files hook#1
jackyraimond merged 5 commits into
mainfrom
add-block-secret-files

Conversation

@jackyraimond

Copy link
Copy Markdown
Collaborator

Adds the first hook to the repo: a PreToolUse guardrail that stops Claude from reading or writing files that look like secrets.

Why

Claude reads whatever a task seems to need, and "seems to need" regularly includes .env. Nothing in Claude Code stops that by default. Permission rules can, but they are per-project and easy to forget on the project where it matters. A hook applies everywhere, once.

The point is not that a leaked .env is catastrophic on its own — it is that the contents end up in a transcript, and transcripts get shared, summarised and stored.

What it does

Denies Read, Edit, Write and NotebookEdit when the target path matches a secret pattern: .env and its variants, *.pem, *.key, *.p12, *.pfx, keystores, id_rsa and friends, *.kdbx, credentials, service-account*.json, .npmrc, .pypirc, .netrc, .htpasswd, plus anything inside .ssh/, .gnupg/, .aws/ and the .docker/config.json / .kube/config files.

*.example, *.sample, *.template, *.dist and the .env.example family are allowed on purpose. Those are the files Claude should be reading.

It returns a permissionDecision of deny with a reason, so Claude gets told why and can ask for the single value it needs instead of giving up or retrying.

What it deliberately does not do

  • It does not match Bash. cat .env still works. Blocking that reliably needs command parsing, not path matching, and the false-positive rate is not worth it. Stated plainly in the hook's README rather than left for someone to discover.
  • It does not scan contents. A secret pasted into config.php goes through.
  • It fails open. An unreadable payload or a tool without a path is allowed. A guardrail that crashes should not take the session down with it.

Seatbelt, not vault.

Testing

./scripts/validate.sh passes.

The script was exercised directly with ten payloads:

Payload Expected Result
.env deny
.env.local deny
.env.example allow
env.example allow
~/.ssh/id_ed25519 deny
~/.kube/config deny
notebook_path = .env deny
src/app.ts allow
malformed JSON on stdin allow
empty payload {} allow

Reproduce with the two commands in the hook's README.

Review notes

This is shell that runs automatically on every matching file operation, so it is worth reading the script rather than trusting the description. It is 129 lines of dependency-free Python: three pattern lists at the top, one fnmatch check, no network, no writes, no reads beyond stdin.

🤖 Generated with Claude Code

PreToolUse hook that denies Read, Edit, Write and NotebookEdit calls
targeting files that look like secrets: .env and variants, private keys,
keystores, credential stores, and anything inside .ssh/, .gnupg/ or
.aws/. Example and template files are allowed on purpose, since those
are what Claude should be reading anyway.

It returns a permissionDecision of "deny" with a reason, so Claude can
act on it by asking for the one value it needs instead of reading the
whole file. It fails open: an unreadable payload or a tool without a
path is allowed through, because a broken guardrail should not break the
session.

Known limits, documented in the hook's README: it does not match Bash,
so `cat .env` still works, and it does not scan file contents.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adds the metadata the plugin schema supports: $schema for editor
autocomplete, keywords, license, homepage and repository.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@KainDitmer KainDitmer left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This branch has conflicts that must be resolved
Use the web editor or the command line to resolve conflicts before continuing.

.claude-plugin/marketplace.json
README.md

jackyraimond and others added 2 commits August 13, 2026 09:50
main now carries git-guardrails and project-checks; both sides appended to
marketplace.json and the README hooks table, so all three entries are kept in
alphabetical order. Switched the hook to the exec form CONTRIBUTING requires.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
PR #4 landed on main while this branch was being updated, adding one more
marketplace entry and README row in the same two spots. All four hooks kept,
alphabetical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@jackyraimond
jackyraimond merged commit ee0d493 into main Aug 13, 2026
5 checks passed
@jackyraimond
jackyraimond deleted the add-block-secret-files branch August 13, 2026 08:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants