Note
web
python
ssrf
url-parsing
parser-differential
requests
redirects
Abuse the gap between the validator's URL parse tree and the HTTP client's normalization to reach internal hosts.
SSRF via URL Parser / HTTP Client Disagreement
Validation and execution are often done by different components. The validator reasons over one parse
tree (urllib.parse.urlparse() checking scheme/hostname), while the actual HTTP client, browser
bot, or fetch layer normalizes the string differently and connects somewhere else.
Why It Works
- Userinfo, backslashes, mixed authority syntax, and path normalization create ambiguity about where the true host boundary is.
- Allowlists that trust "if
hostnameis external, the fetch is safe" without reconstructing the URL from parsed components are bypassable.
Vulnerable Pattern
- Python code using
urlparse()(or similar) to checkscheme/hostname, then passing the original string torequests, a browser bot, or another fetch layer. - Validation that never rebuilds the URL from the parsed pieces it just inspected.
Exploit Flow
- Test basic localhost forms, dotted-decimal variants, IPv6 literals, and path traversal after the authority.
- If direct localhost is blocked, move to parser-differential payloads: backslashes before
@, fake userinfo, or a visible public host masking an internal one. - Confirm not only reachability but where redirects are processed — the first and final hop may be validated by different layers.
Variations
http://127.0.0.1:5001\:.:@public.example:80/../flaghttp://attacker\@localhost:4000/donehttp://public@example.com@127.0.0.1/- Mixed IPv6 / zone forms, or scheme-relative redirects.
- If the sink is a browser bot rather than
requests, switch to browser URL-handling payload families.
Common Blockers
- Some clients canonicalize and then reject malformed strings before connecting.
- Internal DNS or proxy layers may rewrite the target again, so reason about input string → socket destination end to end.
PoC Sketch
url=http://127.0.0.1:5001\:.:@public.example:80/../flag
url=http://attacker\@localhost:4000/done
Good Situations To Use It
- An app validates a user-supplied URL with
urlparsethen fetches the raw string. - Direct
127.0.0.1/localhostis filtered but you control authority syntax. - The fetch follows redirects across more than one component.
Sources
0xFUN2026/web/webhook_serviceLACTF2026/web/append-noteLACTF2026/web/extend-note