pwneglyph logo
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 hostname is external, the fetch is safe" without reconstructing the URL from parsed components are bypassable.

Vulnerable Pattern

  • Python code using urlparse() (or similar) to check scheme/hostname, then passing the original string to requests, a browser bot, or another fetch layer.
  • Validation that never rebuilds the URL from the parsed pieces it just inspected.

Exploit Flow

  1. Test basic localhost forms, dotted-decimal variants, IPv6 literals, and path traversal after the authority.
  2. If direct localhost is blocked, move to parser-differential payloads: backslashes before @, fake userinfo, or a visible public host masking an internal one.
  3. 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/../flag
  • http://attacker\@localhost:4000/done
  • http://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 urlparse then fetches the raw string.
  • Direct 127.0.0.1 / localhost is filtered but you control authority syntax.
  • The fetch follows redirects across more than one component.

Sources

  • 0xFUN2026/web/webhook_service
  • LACTF2026/web/append-note
  • LACTF2026/web/extend-note