Skip to content
Module 3Lesson 12 of 15·3:08

Implementing a Security Hook

Step-by-step walkthrough of building a PreToolUse hook that prevents Claude Code from reading sensitive .env files. Covers configuration, script implementation, and security best practices.

Let us build a real hook from scratch: a security guard that prevents Claude Code from reading your .env files. This is a practical, production-worthy example that protects environment variables, API keys, and other secrets from being exposed during AI-assisted development sessions.

Step 1: Configure the Hook

Open your .claude/settings.local.json file and add a PreToolUse hook configuration. We want to catch both Read and Grep operations, since either could expose the contents of a .env file:

.claude/settings.local.json
1{
2 "hooks": {
3 "PreToolUse": [
4 {
5 "matcher": "Read|Grep",
6 "hooks": [
7 {
8 "type": "command",
9 "command": "node ./hooks/read_hook.js"
10 }
11 ]
12 }
13 ]
14 }
15}

The pipe syntax "Read|Grep" acts as an OR — the hook triggers on either tool type.

Step 2: Write the Hook Script

Create a hooks directory in your project and add the read_hook.js script. The script reads JSON from standard input, checks whether Claude is trying to access a .env file, and blocks the operation if so:

hooks/read_hook.js
1async function main() {
2 const chunks = [];
3 for await (const chunk of process.stdin) {
4 chunks.push(chunk);
5 }
6
7 const toolArgs = JSON.parse(Buffer.concat(chunks).toString());
8
9 // Extract the file path from the tool input
10 const readPath =
11 toolArgs.tool_input?.file_path ||
12 toolArgs.tool_input?.path ||
13 "";
14
15 // Block access to .env files
16 if (readPath.includes('.env')) {
17 console.error("Access denied: .env files are protected by a security hook.");
18 process.exit(2);
19 }
20}
21
22main();

Step 3: Test the Hook

Restart Claude Code for the hook configuration to take effect. Then test by asking Claude to read your .env file. Claude will attempt the Read tool, your hook will intercept it and return exit code 2, and Claude will receive your error message explaining that the operation was blocked.

The same protection applies to Grep operations — if Claude tries to search within .env files, the hook catches that too.

Security Best Practice: Use Absolute Paths

The official Claude Code documentation recommends using absolute paths for hook scripts rather than relative paths. This mitigates path interception and binary planting attacks where a malicious actor could place a script with the same name earlier in the PATH.

Absolute paths and team sharing

Absolute paths make sharing settings.json files challenging because paths differ between machines. A common solution is to use a settings.example.json with $PWD placeholders and a setup script that replaces them with the actual project path on each developer's machine.

Beyond .env: Extending the Pattern

The same pattern protects any sensitive files or directories. You can extend the logic to block access to:

  • Private key files (.pem, .key)
  • Credential configuration files
  • Internal documentation directories
  • Production database configuration
  • Any path matching a pattern you define

Key Takeaways

  • 01A PreToolUse hook on "Read|Grep" can prevent Claude from accessing sensitive files.
  • 02The hook script reads JSON from stdin, checks the file path, and exits with code 2 to block.
  • 03Always write clear stderr messages when blocking — Claude uses this feedback.
  • 04Use absolute paths for hook scripts in production to prevent path interception attacks.
  • 05The pattern extends to any file type or directory you need to protect.