Banked: 2026-06-11 (Web2 lane, Securva HeaderGuard API self-audit) Class: Web2 / SSRF / server-side fetcher endpoints Type: Positive case study + reusable test matrix
GET /api/scan?domain= style endpoints (header scanners, screenshot services, link
previewers, webhook validators, "fetch my site" tools) take a user-supplied host and
connect to it server-side. This is the highest-yield SSRF surface in Web2 because the
SSRF is the intended function - the only question is whether the allow/deny logic is
implemented at the right layer.
A validator can block private IPs at TWO different layers:
1. Literal-string layer (weak): regex/blocklist on the raw input. Bypassable by
decimal (2130706433), octal (0177.0.0.1), IPv6-mapped ([::ffff:127.0.0.1]),
and ANY public hostname that DNS-resolves to a private IP (localtest.me,
127.0.0.1.nip.io, <ip>.nip.io).
2. Resolved-IP layer (correct): resolve DNS first, then check the resolved
address against private/reserved ranges. This is the only layer that catches the
DNS-to-private bypass class.
A validator that blocks literal 127.0.0.1 but ALLOWS 127.0.0.1.nip.io is the
classic, common, submittable SSRF. A validator that blocks BOTH is doing
resolved-IP-layer validation and is (this vector) clean.
| # | Input | What it probes |
|---|---|---|
| 1 | localhost, 127.0.0.1 |
literal loopback |
| 2 | 169.254.169.254 |
cloud metadata literal |
| 3 | 10.0.0.1 / 192.168.0.1 |
RFC1918 literal |
| 4 | 2130706433 |
decimal-encoded 127.0.0.1 |
| 5 | 0177.0.0.1 |
octal-encoded |
| 6 | localtest.me, 127.0.0.1.nip.io |
DNS->loopback (deciding test) |
| 7 | 169.254.169.254.nip.io |
DNS->metadata (deciding test) |
| 8 | [::1], [::ffff:127.0.0.1], [fd00:ec2::254] |
IPv6 loopback/mapped/ULA |
| 9 | example.com%0d%0aHost:... |
CRLF/header injection |
| 10 | open-redirect -> private (needs attacker-controlled host) | post-resolution redirect SSRF (residual) |
Even a resolved-IP-layer validator can be bypassed if it validates the initial host
but then follows HTTP redirects without re-validating each hop. Attacker hosts
https://attacker.com (public, passes check) returning 302 -> http://169.254.169.254/.
Testing this requires an attacker-controlled redirector, so it is NOT closable with the
passive matrix above. ALWAYS flag it as the residual untested vector when the literal/
DNS matrix comes back clean. Mitigation to look for: "validate on every redirect hop"
or "disable redirect-following / max-redirects 0".
Invalid domain format validation layer.This matrix is the standard opener for ANY bug-bounty target exposing a fetch-a-URL/ scan-a-domain feature (Web3 dApp metadata fetchers, NFT image proxies, webhook test buttons, SSO metadata-URL importers, RSS/OG-preview services). Lead with row 6/7; if those pass, immediately pivot to row 10 (redirect SSRF) since that's where the real yield hides when the literal/DNS layers are correctly implemented.