# Block secrets in Claude Code

URL: https://tailrace.dev/docs/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 [#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 [#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 [#step-1-scaffold-config]

```bash
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 [#step-2-install-hooks]

```bash
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 [#step-3-verify-with-a-fake-key]

```bash
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) [#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 [#troubleshooting]

| Symptom                         | Fix                                                                                                      |
| ------------------------------- | -------------------------------------------------------------------------------------------------------- |
| Hook does nothing               | Confirm `tailrace` is on `PATH` inside Claude Code; re-run `install-hooks`; open `/hooks` in Claude Code |
| Missing config error            | Run `init` or `install-hooks` so `.tailrace/config.json` exists under `$CLAUDE_PROJECT_DIR`              |
| Tokens differ across tool calls | Set a stable `vaultKey` or `TAILRACE_VAULT_KEY`; workflow id is Claude Code `session_id`                 |
| Exit 1 on stderr                | Process error (bad JSON / missing config), not a policy deny - deny always exits 0 with JSON             |

## Related [#related]

* [Claude Code integration](/docs/integrations/claude-code)
* [CLI reference](/docs/reference/cli)
* Spec: [`docs/integrations.md`](https://github.com/tailrace/tailrace/blob/main/docs/integrations.md) §4
* Example: [`examples/claude-code`](https://github.com/tailrace/tailrace/tree/main/examples/claude-code)
