What
Implement SSRF (Server-Side Request Forgery) protections on the webhook delivery system for alert rules.
Why
BMAD CLO finding (🔴 CRITICAL): TrapFall sends HTTP POSTs to user-configured webhook URLs for alert notifications. Without restrictions:
- Attacker registers webhook pointing to
http://169.254.169.254/latest/meta-data/ → cloud metadata exfiltration (AWS/GCP/Azure credentials leaked)
- Internal network scanning via TrapFall as proxy
- Access to internal services (databases, admin panels, etc.)
Changes
- IP blocklist: Reject URLs resolving to private/internal IP ranges:
- RFC 1918:
10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
- Link-local:
169.254.0.0/16 (includes cloud metadata 169.254.169.254)
- Loopback:
127.0.0.0/8, ::1
- Other:
0.0.0.0/8, 100.64.0.0/10 (CGNAT)
- URL scheme restriction: Only allow
https:// (and optionally http:// via config flag)
- DNS rebinding mitigation: Resolve hostname → validate IP is not blocked → connect to validated IP (not re-resolve)
- Redirect following: Disable or validate redirect targets against blocklist
- Config flag:
TRAPFALL_WEBHOOK_ALLOW_PRIVATE_IP=false (default: false, can override for self-hosted LAN)
- Add tests: webhook to
127.0.0.1, 169.254.169.254, 10.x.x.x → all rejected
Testing
- Unit test: webhook URL with private IP → rejected with error
- Unit test: webhook URL with public IP → accepted
- Unit test: DNS resolution to private IP → rejected
- Unit test: localhost bypass via config flag → accepted when allowed
What
Implement SSRF (Server-Side Request Forgery) protections on the webhook delivery system for alert rules.
Why
BMAD CLO finding (🔴 CRITICAL): TrapFall sends HTTP POSTs to user-configured webhook URLs for alert notifications. Without restrictions:
http://169.254.169.254/latest/meta-data/→ cloud metadata exfiltration (AWS/GCP/Azure credentials leaked)Changes
10.0.0.0/8,172.16.0.0/12,192.168.0.0/16169.254.0.0/16(includes cloud metadata169.254.169.254)127.0.0.0/8,::10.0.0.0/8,100.64.0.0/10(CGNAT)https://(and optionallyhttp://via config flag)TRAPFALL_WEBHOOK_ALLOW_PRIVATE_IP=false(default: false, can override for self-hosted LAN)127.0.0.1,169.254.169.254,10.x.x.x→ all rejectedTesting