Desoul Review Tiếng Việt

← Guides

Hooks that stop Claude Code reading your secrets

The job is keeping Claude Code away from .env files, SSH keys and cloud credentials. A PreToolUse hook sees every tool call before it runs, and exit code 2 blocks it. On 5 and 6 November 2026 I tested two public guards against my own two (one for secret reads, one for dangerous git commands) by feeding all of them the same fake tool calls.

How I tested

No real secrets, no real home folder. Each hook ran on a scratch copy with a fake HOME, one JSON event per line on stdin, the way Claude Code calls it. I recorded the exit code.

printf '{"tool_name":"Read","tool_input":{"file_path":"/work/app/.env"}}' \
  | HOME=FAKE_HOME bash COPY_OF_HOOK.sh

24 fake calls went to the guard in disler/claude-code-hooks-mastery and to mine. 33 went to emaarco/agento-patronum, once against its old plugin hook and once against the current one. The author has since folded the repo into emaarco/hogwarts, so the old URL no longer works. Both hooks gave identical results.

hooks-mastery's guard against mine

Neither guard covers everything. Theirs is stronger on deletes, mine on reading credentials through the shell.

agento-patronum: strong on files, thin on the shell

It ships 12 rules: .env, .env.*, *.pem, *.key, ~/.ssh/*, ~/.aws/credentials, ~/.aws/config, ~/.docker/config.json, ~/.kube/config, ~/.npmrc, ~/.pypirc and the command printenv. An update on 10 November added five more: ~/.config/gh/hosts.yml, ~/.config/glab-cli/config.yml, ~/.git-credentials, ~/.netrc and ~/.claude/.credentials.json.

On 14 November 2026 I re-ran fake calls against that updated hook, inside a macOS sandbox with no network, writes allowed only in two scratch folders, a throwaway HOME, an empty environment and a 10-second CPU limit. I read all 163 lines of the hook first. My original list of 33 calls was not kept, so I rebuilt it from my notes (32 calls plus 3 I had noted separately, which is not the identical set). Every result below held, except where it says otherwise.

What works for the shell, and what it costs

Match the whole command text, not its first word. My git guard runs a regex over the full command, so it catches cd x && git push, which a prefix rule misses. The cost is false alarms. During these tests my own guards blocked a command that only had the words "git push" inside a quoted string, and another that named .env in a label. hooks-mastery's guard has the same kind of false alarm.

If you write one

  1. Put Grep and Glob in the matcher, not only Read, Edit and Bash.
  2. For Bash, match the whole command text, and accept a few false alarms.
  3. Fail closed when the rules file is missing or broken, and when the input is not valid JSON.
  4. Give every block a reason a person can read, and log each one on a single line.
  5. Test it with fake calls like the ones above, and check the exit code.

A hook doesn't replace deny rules in your settings. patronum's own newer README notes that Read deny rules also feed Claude Code's sandbox. Use both.

Tools in this test