# SSRF via encoded URL parser mismatch

Sanitizer and fetcher disagree on URL meaning: escapes, fragments, duplicate tokens, authority tricks

_Area: Web infrastructure and server-side requests. Seen in 3 disclosed reports; one confirmed bounty: $500; latest 2026-07-31. Updated 2026-10-24._

## How it works
A security check reads a URL as text, but the component that actually fetches it decodes or parses it differently. The check approves one destination; the client contacts another. The broken assumption is that "the string I validated" and "the string that gets fetched" are the same. Any decoding step between them (escape expansion, fragment handling, global string replacement) can decouple the two.

## Where it shows up
- URL allowlist/denylist checks done with regex or substring matching, then the raw string handed to curl, requests, or a proxy.
- Signature or token embedded in the path and removed with `str.replace()` without a count [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-mw3h-qjxj-6xg9.md).
- `#` or `@` inside the authority, where the validator and the HTTP client may split host differently [E2](https://bugbountylibrary.com/r/h1%3A180434.md).
- Sanitizers that rewrite `url(...)` or links but do not normalize CSS escapes or percent-encoding first [E3](https://bugbountylibrary.com/r/h1%3A745953.md).
- Any place validation and fetching use different libraries or different parse stages.

## How to review
Find the exact string that reaches the network call and confirm it is the same value the check approved. The invariant: validate the parsed, fully-decoded URL (scheme, host, port, path) and fetch from that same parsed object, never re-parse the original text. Check that token stripping removes exactly one occurrence at a known position [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-mw3h-qjxj-6xg9.md), that the parser matches RFC authority/fragment rules [E2](https://bugbountylibrary.com/r/h1%3A180434.md), and that the sanitizer decodes escapes before matching [E3](https://bugbountylibrary.com/r/h1%3A745953.md). Prefer resolving the host once and pinning the connection to that resolved address.

## Variants seen
- Global substring removal of an embedded signature lets a duplicated token change the validated string [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-mw3h-qjxj-6xg9.md).
- Parser differential on `#` in the authority: validator sees one host, curl connects to another [E2](https://bugbountylibrary.com/r/h1%3A180434.md).
- CSS hex escape (`u\72l`) evades a url() rewriter, forcing arbitrary requests through visitors [E3](https://bugbountylibrary.com/r/h1%3A745953.md).

## Impact and severity
Led to SSRF and proxy-bypass: requests to attacker-chosen hosts, internal reachability, and forced client-side requests. Severity rises when the fetcher has internal network access or credentials, and when the bypass is silent (no error) so it is not noticed. Median bounty in evidence was modest, but impact depends on what the fetcher can reach.

## Evidence
- E1: https://bugbountylibrary.com/r/ghsa%3AGHSA-mw3h-qjxj-6xg9.md
- E2: https://bugbountylibrary.com/r/h1%3A180434.md
- E3: https://bugbountylibrary.com/r/h1%3A745953.md
