Files
2026-07-13 12:35:03 +08:00

6.7 KiB

Security Hooks Guide

Guide Origin: Official | ArcKit Version: [VERSION]

ArcKit includes three security hooks that provide layered protection against accidental secret exposure during Claude Code sessions. These hooks run automatically and require no manual configuration.

Three-Layer Protection Model

The security hooks implement defence in depth with three complementary layers:

Layer Hook Hook Type Trigger Purpose
1 secret-detection.py UserPromptSubmit Every user message Catches secrets pasted into prompts
2 file-protection.py PreToolUse (Edit|Write) File edit/write operations Blocks writes to sensitive file paths
3 secret-file-scanner.py PreToolUse (Edit|Write) File edit/write operations Scans content being written for embedded secrets

How the layers work together

  1. Layer 1 — Prompt scanning: Before your message reaches the model, secret-detection.py scans the prompt text for known secret patterns (API keys, tokens, passwords, connection strings). If a secret is detected, the message is blocked before it is sent.

  2. Layer 2 — Path protection: When Claude attempts to edit or write a file, file-protection.py checks whether the target file path is sensitive (environment files, credential stores, private keys, lock files). Protected files are blocked regardless of content.

  3. Layer 3 — Content scanning: For files that pass the path check, secret-file-scanner.py examines the actual content being written for secret patterns. This catches cases where a secret is embedded in an otherwise safe file path.

What Each Hook Detects

secret-detection.py (Prompt Scanner)

Scans user prompts for:

  • Key-value secrets: pwd=, api_key=, auth_token=, api_secret=
  • Provider-specific tokens: OpenAI (sk-), Anthropic (sk-ant-), GitHub (ghp_, gho_, ghs_), AWS (AKIA), Notion (ntn_), Atlassian (ATATT), Slack (xox), Google (AIza)
  • Bearer tokens: bearer <value>
  • Connection strings: mongodb://, postgres://, mysql://, redis:// with credentials
  • PEM private keys: -----BEGIN ... KEY----- headers
  • High-entropy credentials: Long base64-like strings assigned to key/secret variables

Example block:

$ echo '{"userPrompt": "Use this key sk-ant-abc123def456ghi789"}' \
    | python3 arckit-claude/hooks/secret-detection.py
# Output: {"decision": "block", "reason": "Warning: Potential secrets detected: ..."}

file-protection.py (Path Guard)

Blocks writes to:

  • Environment files: .env, .env.local, .env.production, .env.development
  • Lock files: package-lock.json, yarn.lock, pnpm-lock.yaml, Gemfile.lock, poetry.lock, Cargo.lock
  • Version control: .git/
  • Credential directories: .aws/, .ssh/, .gnupg/
  • Secret files: credentials, credentials.json, secrets.json, secrets.yaml, secrets.yml, .secrets
  • Private keys: *.pem, *.key, *.p12, *.pfx, id_rsa, id_ed25519, id_ecdsa
  • Auth config files: .npmrc, .pypirc, .netrc
  • Files with sensitive keywords: filenames containing terms like "credential", "api-key", etc.

Example block:

$ echo '{"tool_name": "Write", "tool_input": {"file_path": ".env", "content": "DB_HOST=localhost"}}' \
    | python3 arckit-claude/hooks/file-protection.py
# Output: {"decision": "block", "reason": "Protected: Protected file: .env\nFile: .env\n..."}

secret-file-scanner.py (Content Scanner)

Scans the content of files being written or edited using the same pattern library as secret-detection.py. This catches secrets that might be embedded in source code, configuration files, or documentation.

Example block:

$ echo '{"tool_name": "Write", "tool_input": {"file_path": "config.py", "content": "db_host=localhost"}}' \
    | python3 arckit-claude/hooks/secret-file-scanner.py
# Output: no output (safe content passes through)

Adding Exceptions

File protection exceptions

To allow edits to files that would normally be blocked by file-protection.py, you have three options:

1. Add to ALLOWED_EXCEPTIONS — for specific filenames that are legitimate security tools:

ALLOWED_EXCEPTIONS = [
    ".secrets.baseline",
    ".pre-commit-config.yaml",
    "secret-detection.py",
    "secret-file-scanner.py",
    "your-new-exception.py",  # Add here
]

2. Add to ALLOWED_DIRECTORIES — for directories containing documentation or tool files that discuss secrets:

ALLOWED_DIRECTORIES = [
    "arckit-claude/commands/",
    "arckit-claude/templates/",
    "arckit-claude/agents/",
    "arckit-claude/hooks/",
    "docs/",
    ".arckit/templates/",
    "your-project/docs/",  # Add here
]

Content scanner skip patterns

To prevent secret-file-scanner.py from scanning certain files (e.g., documentation that legitimately discusses secret formats), add a regex to SKIP_PATTERNS:

SKIP_PATTERNS = [
    r"\.pre-commit-config\.yaml$",
    r"secret-detection\.py$",
    r"secret-file-scanner\.py$",
    r"file-protection\.py$",
    r"\.secrets\.baseline$",
    r"arckit-claude/commands/.*\.md$",
    r"arckit-claude/templates/.*\.md$",
    r"docs/.*\.md$",
    r"CHANGELOG\.md$",
    r"README\.md$",
    r"your-custom-pattern\.md$",  # Add here
]

Testing

You can test each hook by piping JSON to stdin. All hooks handle empty input gracefully.

Test file protection blocks .env writes

echo '{"tool_name": "Write", "tool_input": {"file_path": ".env", "content": "VALUE=abc"}}' \
    | python3 arckit-claude/hooks/file-protection.py

Expected: {"decision": "block", ...}

Test secret detection blocks API keys in prompts

echo '{"userPrompt": "Use this key sk-ant-abc123def456ghi789"}' \
    | python3 arckit-claude/hooks/secret-detection.py

Expected: {"decision": "block", ...}

Test secret file scanner blocks secrets in content

echo '{"tool_name": "Write", "tool_input": {"file_path": "test.md", "content": "pwd=hunter2"}}' \
    | python3 arckit-claude/hooks/secret-file-scanner.py

Expected: {"decision": "block", ...}

Test that allowed files pass through

echo '{"tool_name": "Write", "tool_input": {"file_path": "arckit-claude/commands/research.md", "content": "Use API key format: sk-xxx"}}' \
    | python3 arckit-claude/hooks/secret-file-scanner.py

Expected: no output (exit code 0, file is in a skip pattern)

Test that empty input does not crash

echo '' | python3 arckit-claude/hooks/file-protection.py
echo '' | python3 arckit-claude/hooks/secret-detection.py
echo '' | python3 arckit-claude/hooks/secret-file-scanner.py

Expected: no output or {} (exit code 0 for all)