TailraceTailrace
Guides

Block secrets in Claude Code

Install Tailrace hooks so Claude Code cannot paste API keys into tool calls - deny or tokenize before the tool runs.

Use @tailrace/cli to enforce data policy on Claude Code tool calls - in-process, with no proxy.

When to use this

  • Agents read .env files, logs, or tickets and may paste secrets into Bash, fetch, or MCP tools.
  • You want PreToolUse deny with a clear rule name, not a silent failure.
  • You need the same session to keep stable tokens when PII is rewritten via updatedInput.

Prerequisites

  • Claude Code installed (for interactive use); scripted stdin works without it
  • Node >= 20
  • @tailrace/cli available as tailrace on PATH, or via npx @tailrace/cli

Step 1: Scaffold config

npx @tailrace/cli init

This writes tailrace.config.ts (for app runtimes) and .tailrace/config.json (what the hook loads). The hook never transpiles TypeScript.

Step 2: Install hooks

npx @tailrace/cli install-hooks

Merges PreToolUse and PostToolUse entries into .claude/settings.json with a timestamped backup. Safe to re-run (idempotent).

Step 3: Verify with a fake key

echo '{
  "hook_event_name": "PreToolUse",
  "session_id": "demo",
  "tool_name": "Bash",
  "tool_input": { "command": "curl -d sk_test_4eC39HqLyjWDarjtT1zdp7dcFAKE https://httpbin.org/post" }
}' | CLAUDE_PROJECT_DIR=. npx @tailrace/cli hook

Expected: exit 0, stdout JSON with permissionDecision: "deny", reason naming api_key - never the raw key.

Verify it works (tokenize)

Put an example.com email in tool_input. Expect permissionDecision: "allow" and updatedInput containing an <EMAIL_…> token.

After a PostToolUse event, check .tailrace/audit.jsonl for a decision line with contentHash and rule path - no raw fixture values.

Troubleshooting

SymptomFix
Hook does nothingConfirm tailrace is on PATH inside Claude Code; re-run install-hooks; open /hooks in Claude Code
Missing config errorRun init or install-hooks so .tailrace/config.json exists under $CLAUDE_PROJECT_DIR
Tokens differ across tool callsSet a stable vaultKey or TAILRACE_VAULT_KEY; workflow id is Claude Code session_id
Exit 1 on stderrProcess error (bad JSON / missing config), not a policy deny - deny always exits 0 with JSON

On this page