Chapter 11 System Design

Security Defense-in-Depth

Layered security: bash analysis, SSRF prevention, and secret scanning

src/utils/hooks/ssrfGuard.tsLines 160
1
import type { AddressFamily, LookupAddress as AxiosLookupAddress } from 'axios'
2
import { lookup as dnsLookup } from 'dns'
3
import { isIP } from 'net'
4
 
5
/**
6
 * SSRF guard for HTTP hooks.
7
 *
8
 * Blocks private, link-local, and other non-routable address ranges to prevent
9
 * project-configured HTTP hooks from reaching cloud metadata endpoints
10
 * (169.254.169.254) or internal infrastructure.
11
 *
12
 * Loopback (127.0.0.0/8, ::1) is intentionally ALLOWED — local dev policy
13
 * servers are a primary HTTP hook use case.
14
 *
15
 * When a global proxy or the sandbox network proxy is in use, the guard is
16
 * effectively bypassed for the target host because the proxy performs DNS
17
 * resolution. The sandbox proxy enforces its own domain allowlist.
18
 */
19
 
20
/**
21
 * Returns true if the address is in a range that HTTP hooks should not reach.
22
 *
23
 * Blocked IPv4:
24
 *   0.0.0.0/8        "this" network
25
 *   10.0.0.0/8       private
26
 *   100.64.0.0/10    shared address space / CGNAT (some cloud metadata, e.g. Alibaba 100.100.100.200)
27
 *   169.254.0.0/16   link-local (cloud metadata)
28
 *   172.16.0.0/12    private
29
 *   192.168.0.0/16   private
30
 *
31
 * Blocked IPv6:
32
 *   ::               unspecified
33
 *   fc00::/7         unique local
34
 *   fe80::/10        link-local
35
 *   ::ffff:<v4>      mapped IPv4 in a blocked range
36
 *
37
 * Allowed (returns false):
38
 *   127.0.0.0/8      loopback (local dev hooks)
39
 *   ::1              loopback
40
 *   everything else
41
 */
42
export function isBlockedAddress(address: string): boolean {
43
  const v = isIP(address)
44
  if (v === 4) {
45
    return isBlockedV4(address)
46
  }
47
  if (v === 6) {
48
    return isBlockedV6(address)
49
  }
50
  // Not a valid IP literal — let the real DNS path handle it (this function
51
  // is only called on results from dns.lookup, which always returns valid IPs)
52
  return false
53
}
54
 
55
function isBlockedV4(address: string): boolean {
56
  const parts = address.split('.').map(Number)
57
  const [a, b] = parts
58
  if (
59
    parts.length !== 4 ||
60
    a === undefined ||
Annotations (click the dots)

Security in Claude Code is layered — no single check is trusted to catch everything. For bash execution: the command is AST-parsed for dangerous patterns, classified for safety, checked against permission rules, then sandboxed if configured.

🔑Key Insight

Defense-in-depth: even if one layer fails (e.g., a dangerous pattern slips past the AST parser), the next layer (permission rules, sandbox isolation) catches it. Security is not a single gate — it's a pipeline.

The secretScanner.ts uses gitleaks-based regex rules to detect AWS keys, GitHub PATs, JWT tokens, and other credentials in memory files before they're uploaded to the server. If a match is found, the upload is blocked and the user is warned.

⚠️Warning

The SSRF guard is specifically designed to prevent hook configs from pointing Claude Code at internal services. A malicious MCP server could inject hook URLs that exfiltrate secrets — the guard prevents this.

KEY TAKEAWAYS
  • bashSecurity.ts AST-parses shell commands to detect dangerous patterns before execution
  • SSRF guard blocks localhost, metadata IP (169.254.169.254), and link-local addresses
  • secretScanner.ts uses gitleaks-based rules to prevent credentials from being uploaded
  • The permission system adds a third layer — even if a command passes security checks, permissions can still block it
  • Security checks compose: AST → classification → SSRF → secrets → permission → execution
AI Assistant

Ask anything about Security Defense-in-Depth

Powered by Groq · Enter to send, Shift+Enter for newline