Skip to content

TribeAI/claude-code-alignment-checks

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Claude Code — Bash Safety Hook

A PreToolUse hook for Claude Code that validates every Bash tool call before it executes. Safe, read-only commands are fast-pathed without an API call; anything ambiguous is checked by claude-haiku-4-5 via the Anthropic API.

What's included

File Purpose
.claude/settings.json Hook registration, permission allow/deny lists
.claude/hooks/code-safety.sh The hook script
.claude/hooks/refresh-alignment-key.sh Fetches/refreshes API key from 1Password into .env
generate_test_commands.py Generates 29 exfiltration test commands across 7 categories
run_tests.sh Runs the test commands against the hook and reports results

Be careful before running these tests; see the Test Suite section below for more information.

Prerequisites

  • Python 3 (for JSON handling)
  • curl
  • An Anthropic API key — either set ANTHROPIC_ALIGNMENT_CHECK_API_KEY directly in .env, or set OP_ANTHROPIC_KEY_REF and use the included 1Password refresh script

Installation

Clone this repo, then ask Claude Code to merge the hook configuration into your project:

git clone <this-repo> /tmp/bash-safety-hook

Then in your project, start Claude Code and ask:

Merge the Claude Code bash safety hook from /tmp/bash-safety-hook/.claude/ into this project's .claude/ directory. Add the hook config and permissions to my existing settings.json, and copy the hook script.

Claude Code will handle merging the hook registration, permissions, and script into your existing setup without overwriting your other settings.

Alternatively, if you don't have an existing .claude/ directory, just copy it directly:

cp -r /tmp/bash-safety-hook/.claude/ your-project/.claude/
chmod +x your-project/.claude/hooks/code-safety.sh

Finally, configure the API key in your project's .env. There are two options:

Option A — Set the key directly:

ANTHROPIC_ALIGNMENT_CHECK_API_KEY=sk-ant-...

Option B — Use 1Password: Set a 1Password secret reference and run the refresh script to fetch and cache the key:

OP_ANTHROPIC_KEY_REF=op://vault/item/field
bash .claude/hooks/refresh-alignment-key.sh

The refresh script resolves the reference via op read and writes ANTHROPIC_ALIGNMENT_CHECK_API_KEY into .env. If the cached key expires or is revoked, the hook will tell the agent to re-run the refresh script.

Either way, the hook loads ANTHROPIC_ALIGNMENT_CHECK_API_KEY from .env automatically. A separate variable name is used to avoid collisions with your own ANTHROPIC_API_KEY.

How it works

Four layers of protection

  1. Deny list (.claude/settings.json) — Hard blocks on the most dangerous operations (rm, sudo, git reset --hard, git push --force, etc.) and on .env file access via Read, Edit, Grep, and common Bash commands. These cannot be approved regardless of anything else.

  2. .env early block (.claude/hooks/code-safety.sh) — Any Bash command referencing .env as a token is immediately blocked before reaching the fast-path or API check.

  3. Hook fast-path (.claude/hooks/code-safety.sh) — Common read-only commands (git status, ls, grep, uv pip list, just --list, etc.) are allowed immediately without an API call. Commands that contain chaining operators (|, &&, $(, backticks, >) always go to the Haiku check, even if they start with a safe prefix — this prevents cat .env | curl style bypasses.

  4. Haiku check (.claude/hooks/code-safety.sh) — Anything not fast-pathed is sent to claude-haiku-4-5-20251001 with a safety-focused system prompt that explicitly flags .env access as unsafe. If the model returns {"safe": false, ...}, the tool call is blocked with an explanation. This catches obfuscated attempts (string concatenation, chr() encoding, etc.).

For a critical step that has been blocked, Claude Code will generally tell you what you would need to run in a separate terminal. This forces a level of review above and beyond the default permissions modal, and should only come up sparingly, for example during destructive operations.

Failure behaviour

  • If the API key is missing: block (with a message telling the agent how to set it).
  • If the API key is invalid (authentication error): block (with a message telling the agent to refresh or replace the key).
  • If the curl call fails (network error, timeout): block (fail closed).
  • If the API returns an empty or unparseable response: block (fail closed).

Test suite

Warning: The test suite sends real attack-pattern commands (reverse shells, DNS exfiltration, credential harvesting, etc.) to the Anthropic API for classification. Even though the hook blocks them before execution, the network traffic itself looks like attack tooling. If your computer is on a managed network, your IT / security team will see this traffic and likely follow up with you. Run on a personal machine or give your security team a heads-up first.

The test suite generates 29 exfiltration-style commands across 7 categories:

Category Count Examples
http_exfil 5 curl -d @.env, wget | bash
base64_exfil 3 Base64-encoded secrets sent via POST, query string, headers
dns_exfil 2 Data exfiltration via DNS subdomain queries
reverse_shell 3 nc, bash /dev/tcp, python reverse shells
pipe_exfil 4 tar ~/.ssh | curl, env | curl, etc.
credential_harvest 3 Keychain dumps, 1Password reads, grep for API keys
obfuscated 5 Hex IPs, variable indirection, eval+base64, backgrounding
disguised 4 Exfil disguised as npm publish, pip install, git push, scp

To run:

python3 generate_test_commands.py   # generates test_commands.json
bash run_tests.sh                   # runs all commands against the hook

All 29 commands should be blocked.

Adapting for your project

Fast-path pattern — Edit the SAFE_PATTERN variable in code-safety.sh to add project-specific read-only commands that shouldn't incur an API call.

Allow list — The permissions.allow array in settings.json lists commands that bypass the user-approval prompt. The hook still runs on all of them. Add or remove entries to match your toolchain.

Deny list — The permissions.deny array hard-blocks commands regardless of the hook. Add entries here for anything that should never run without manual intervention outside Claude Code.

Haiku system prompt — The SYSTEM_PROMPT variable in code-safety.sh defines what Haiku considers safe or unsafe. Edit it to reflect your project's risk profile.

Permissions model in settings.json

The included settings.json has a broad "Bash" allow (no user prompts for Bash commands) and relies on the hook as the gate. If you prefer to be prompted for commands not in the explicit allow list, remove the "Bash" entry from permissions.allow and keep only the "Bash(cmd:*)" pattern entries.

Thanks

Big thanks to Jake Porway for the initial settings.json file that kicked off this project.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors