Project 18: “The Security Firewall Hook” — Security Governance
| Attribute | Value |
|---|---|
| File | KIRO_CLI_LEARNING_PROJECTS.md |
| Main Programming Language | Python or Rust |
| Coolness Level | Level 4: Hardcore Tech Flex |
| Business Potential | 3. Service & Support (Enterprise Security) |
| Difficulty | Level 3: Advanced |
| Knowledge Area | Security Governance |
What you’ll build: A PreToolUse hook that blocks dangerous commands.
Why it teaches Governance: You enforce guardrails against hallucinated risk.
Success criteria:
- A destructive command is blocked with a clear message.
Real World Outcome
You’ll have a security firewall that intercepts every Kiro tool call and blocks dangerous operations before execution. When Kiro attempts risky commands, your hook prevents disaster:
Blocked destructive command:
$ kiro "clean up the database by dropping all tables"
[PreToolUse Hook] Analyzing command...
🚫 BLOCKED: Dangerous Bash command detected
Command: DROP DATABASE production;
Reason: Database destructive operation (DROP, TRUNCATE)
Risk Level: CRITICAL
Suggested Alternative: Create a backup first with pg_dump
Hook Exit Code: 1 (Execution prevented)
Allowed safe command:
$ kiro "show me the database schema"
[PreToolUse Hook] Analyzing command...
✅ ALLOWED: Read-only database query
Command: \d+ users
Risk Level: LOW
Reason: SELECT queries are permitted
Security policy report:
$ python analyze-blocks.py
Security Firewall Report (Last 7 Days)
──────────────────────────────────────
Total Tool Calls: 1,247
Blocked: 23 (1.8%)
Allowed: 1,224 (98.2%)
Top Blocked Patterns:
1. rm -rf / (8 attempts)
2. DROP DATABASE (5 attempts)
3. chmod 777 (4 attempts)
4. curl | bash (3 attempts)
5. git push --force main (3 attempts)
Risk Prevented:
- Data loss: 13 incidents
- Security vulnerabilities: 7 incidents
- Production impact: 3 incidents
The hook runs pattern matching, AST analysis, and allow-list checking to catch both obvious and subtle threats before they execute.
The Core Question You’re Answering
“How do I prevent an AI agent from executing catastrophic commands while still allowing productive work?”
Before you start coding, consider: LLMs hallucinate. They suggest rm -rf / to “clean up space.” They recommend chmod 777 for “permission issues.” They propose DROP TABLE users to “fix schema conflicts.” A security firewall is your last line of defense against well-intentioned but devastating suggestions. This project teaches you to build guardrails that catch mistakes before they become disasters.
Concepts You Must Understand First
Stop and research these before coding:
- PreToolUse Hook Lifecycle
- When does PreToolUse execute relative to tool invocation?
- How does a non-zero exit code block tool execution?
- Can you modify tool arguments in a PreToolUse hook?
- What happens if the hook times out (5-second limit)?
- Book Reference: Kiro CLI documentation - Hook System Architecture
- Command Pattern Matching
- How do you distinguish
rm -rf /tmp/safefromrm -rf /? - Should you use regex, AST parsing, or both?
- How do you handle command aliases (ll, la, etc.)?
- What about commands wrapped in functions or subshells?
- Book Reference: “Compilers: Principles, Techniques, and Tools” by Aho et al. - Ch. 3 (Lexical Analysis)
- How do you distinguish
- Bash AST Parsing
- What is the structure of a Bash abstract syntax tree?
- How do you extract the command name from complex pipelines?
- How do you detect destructive flags (
-f,--force,--no-preserve-root)? - Libraries: Python (bashlex), Rust (shell-words)
- Book Reference: “The Linux Command Line” by William Shotts - Ch. 28 (Script Debugging)
- Security Policy Design
- Deny-list (block known bad) vs allow-list (permit known good)?
- How do you balance security with usability?
- Should you allow overrides with explicit flags (–i-know-what-im-doing)?
- How do you handle context-dependent risk (safe in dev, fatal in prod)?
- Book Reference: “Building Secure and Reliable Systems” by Google - Ch. 6 (Design for Least Privilege)
Questions to Guide Your Design
Before implementing, think through these:
- Threat Model
- What are the most dangerous commands to block (file deletion, permission changes, database drops)?
- How do you detect SQL injection in commands?
- Should you block network commands (curl, wget) if they download and execute?
- What about indirect threats (cron jobs, systemd services)?
- Detection Strategy
- Do you use regex patterns (fast but fragile) or AST parsing (slow but accurate)?
- How do you handle obfuscated commands (
$(echo cm)$(echo 64)→echo cm64)? - Should you sandbox and execute the command in dry-run mode first?
- Do you need a scoring system (low/medium/high risk) or binary allow/deny?
- User Experience
- How do you communicate why a command was blocked?
- Should you suggest safer alternatives?
- Do you allow interactive approval (“This is risky, proceed? [y/N]”)?
- How do you prevent alert fatigue from too many false positives?
- Policy Configuration
- Should policies be global or per-project?
- Do you support environment-specific rules (block in prod, allow in dev)?
- How do you update patterns without modifying the hook code?
- Should you support policy inheritance (base + overrides)?
Thinking Exercise
Manual Threat Detection Walkthrough
Before writing code, manually trace how your hook would analyze these commands:
Test Case 1: Obvious Threat
Command: rm -rf /
Analysis:
- Command:
rm(file deletion) - Flags:
-rf(recursive, force) - Target:
/(root directory) - Decision: BLOCK - Catastrophic data loss risk
- Reason: Recursive deletion of root filesystem
Test Case 2: Subtle Threat
Command: find / -name "*.log" -exec rm {} \;
Analysis:
- Command:
find(search, seems harmless) - Execution:
-exec rm(delete each match) - Target:
/(all logs system-wide) - Decision: BLOCK - Hidden destructive operation in -exec
- Reason: Mass file deletion disguised as search
Test Case 3: Context-Dependent
Command: chmod 777 /tmp/test.sh
Analysis:
- Command:
chmod(permission change) - Mode:
777(world-writable) - Target:
/tmp/test.sh(temp file) - Decision: WARN - Bad practice but low immediate risk
- Reason: Insecure permissions on non-critical file
Test Case 4: SQL Injection
Command: psql -c "DROP TABLE users WHERE id = 1; DROP DATABASE production; --"
Analysis:
- Command:
psql(database client) - SQL: Multiple statements detected
- Keywords:
DROP TABLE,DROP DATABASE - Decision: BLOCK - SQL injection attempt
- Reason: Destructive SQL operations
Questions while analyzing:
- Which patterns can you detect with regex alone?
- Which require parsing the command structure?
- How would you handle base64-encoded commands?
- What if the command is split across multiple tool calls?
The Interview Questions They’ll Ask
Prepare to answer these:
- “How would you detect a destructive command hidden in a base64-encoded string that’s later decoded and executed?”
- “Explain the difference between deny-list and allow-list security models. Which is appropriate for AI agent governance?”
- “How do you prevent time-of-check to time-of-use (TOCTOU) attacks where the command changes after your hook approves it?”
- “What strategies would you use to minimize false positives while maintaining strong security boundaries?”
- “How would you design a policy system that’s secure by default but allows power users to override when necessary?”
- “Explain how you would parse a complex Bash command with pipes, redirects, and subshells to extract all executable components.”
Hints in Layers
Hint 1: Start with Pattern Matching Begin with a deny-list of obvious threats using regex:
rm -rf /DROP DATABASEchmod 777curl .* | bashBuild incrementally from simple patterns to complex AST analysis.
Hint 2: Parse the Bash Command Structure
Use a library like bashlex (Python) to parse commands into an AST. Walk the tree to extract:
- Primary command name
- All flags and arguments
- Nested commands in subshells or backticks This catches threats hidden in complex syntax.
Hint 3: Risk Scoring System Assign risk scores to each pattern:
- Critical (100):
rm -rf /,DROP DATABASE - High (75):
chmod 777,git push --force main - Medium (50): Unverified curl downloads
- Low (25): Warnings only Block anything ≥75, warn for 25-74.
Hint 4: Configuration-Driven Policies Load patterns from a YAML config file:
critical_patterns:
- pattern: 'rm\s+-rf\s+/'
reason: "Root filesystem deletion"
- pattern: 'DROP\s+DATABASE'
reason: "Database destruction"
This allows updates without code changes.
Books That Will Help
| Topic | Book | Chapter |
|---|---|---|
| Security Policy Design | “Building Secure and Reliable Systems” by Google | Ch. 6 (Design for Least Privilege), Ch. 12 (Crisis Management) |
| Command Parsing | “Compilers: Principles, Techniques, and Tools” by Aho et al. | Ch. 3 (Lexical Analysis), Ch. 4 (Syntax Analysis) |
| Bash Scripting Security | “The Linux Command Line” by William Shotts | Ch. 28 (Script Debugging), Ch. 29 (Flow Control) |
| Pattern Matching | “Regular Expressions Cookbook” by Goyvaerts & Levithan | Ch. 4 (Validation), Ch. 7 (Security) |
| Hook System | Kiro CLI docs | Hooks System, Security Best Practices |
Common Pitfalls & Debugging
Problem 1: “Hook blocks legitimate commands (false positives)”
- Why: Overly broad regex patterns match harmless variations
- Fix: Test patterns against a suite of safe commands:
# Safe: rm -rf ./temp # Unsafe: rm -rf / # Pattern should distinguish based on target path - Quick test: Create a test suite with 100 safe and 20 unsafe commands
Problem 2: “Obfuscated commands bypass detection”
- Why: Regex can’t detect
$(echo rm) -rf / - Fix: Execute the command in a sandbox with dry-run mode:
bash -n -c "$command" 2>&1 # Check syntax without executing - Quick test: Try variations like
r''m -rf,${CMD}, base64 encoding
Problem 3: “Hook is too slow, Kiro times out”
- Why: AST parsing is expensive for every command
- Fix: Implement a fast-path for common safe commands:
if command.startswith(('ls', 'cat', 'grep', 'echo')): return ALLOW # Skip expensive parsing - Quick test: Time hook execution—should be <100ms for 95% of commands
Problem 4: “Policy updates require redeploying the hook”
- Why: Patterns are hardcoded in the script
- Fix: Load patterns from
~/.kiro/security-policy.yaml:with open(os.path.expanduser('~/.kiro/security-policy.yaml')) as f: policy = yaml.safe_load(f) - Quick test: Modify YAML file, verify new patterns apply without restart
Problem 5: “Can’t block SQL injection in psql commands”
- Why: SQL is embedded as a string argument
- Fix: Parse SQL with a library like
sqlparse(Python):import sqlparse statements = sqlparse.split(sql_query) for stmt in statements: if 'DROP' in stmt.upper() or 'DELETE' in stmt.upper(): return BLOCK - Quick test: Test with various SQL injection payloads
Definition of Done
- Hook intercepts all PreToolUse events for Bash and Edit tools
- Critical patterns (rm -rf /, DROP DATABASE, chmod 777) are blocked
- Blocked commands log to ~/.kiro/security-log.jsonl with reason
- AST parsing catches threats hidden in complex command structures
- Policy is loaded from YAML config file, updatable without code changes
- False positive rate is <2% on a benchmark of 500 real commands
- Hook completes analysis in <100ms for 95th percentile
- Blocked commands show helpful error messages with alternatives
- Allow-list overrides are supported via –security-override flag
- Environment-specific policies (dev vs prod) are configurable
- Documentation explains how to add custom patterns and policies