# SSRF via unparsed URL encoding

Sanitizer or extension check that inspects raw URL text instead of the parsed, decoded request target

_Area: Web infrastructure and server-side requests. Seen in 2 disclosed reports; one confirmed bounty: $1,000; latest 2021-12-06. Updated 2026-10-23._

## How it works
A server-side fetcher decides whether a URL is allowed by inspecting the URL *string* rather than the request it will actually make. Any encoding layer between the string and the real target — a query suffix, a base64 segment, a CSS escape — lets the check see one thing while the fetch does another. The broken assumption is that the string the validator reads is the same as the resource the HTTP client retrieves.

## Where it shows up
- Extension checks that look at text after the last dot, or at the raw query string [E1](https://bugbountylibrary.com/r/blog%3Abuer-haus-2016-04-18-esea-server-side-request-forgery-and-querying-aws-meta-data.md)
- Endpoints that base64-decode a path segment and then fetch it, with no scheme or host allowlist [E2](https://bugbountylibrary.com/r/h1%3A1189367.md)
- HTML/CSS sanitizers that rewrite `url(...)` by regex without normalizing CSS escapes [E3](https://bugbountylibrary.com/r/h1%3A745953.md)
- Any server-side fetch of a user-supplied URL where validation and fetching use different parsers
- Fetchers that follow redirects or accept `file://` and internal `http://` schemes

## How to review
Find every place a user-influenced URL reaches an HTTP client. The invariant: validation must run on the *parsed, decoded, normalized* URL — scheme, host, port, path — and the same parsed object must be what the client fetches. Check that:
- The extension/scheme check operates on the parsed path, not the raw string or query [E1](https://bugbountylibrary.com/r/blog%3Abuer-haus-2016-04-18-esea-server-side-request-forgery-and-querying-aws-meta-data.md)
- Decoded segments (base64, percent, CSS escapes) are re-validated after decoding [E2](https://bugbountylibrary.com/r/h1%3A1189367.md)[E3](https://bugbountylibrary.com/r/h1%3A745953.md)
- Scheme is restricted to http/https and host is allowlisted or resolved-and-blocked for link-local/metadata ranges
- Redirects are not followed, or are re-validated per hop

## Variants seen
- Query-suffix bypass: `?.png` satisfies an extension check while the path stays arbitrary [E1](https://bugbountylibrary.com/r/blog%3Abuer-haus-2016-04-18-esea-server-side-request-forgery-and-querying-aws-meta-data.md)
- Base64 path segment decoded to a full URL or `file://` URI, fetched without scheme/host restriction [E2](https://bugbountylibrary.com/r/h1%3A1189367.md)
- CSS hex escape (`u\72l`) evades a `url()` rewriter, so the browser fetches directly, skipping the proxy [E3](https://bugbountylibrary.com/r/h1%3A745953.md)

## Impact and severity
Led to AWS metadata access (credentials) and local file read [E1](https://bugbountylibrary.com/r/blog%3Abuer-haus-2016-04-18-esea-server-side-request-forgery-and-querying-aws-meta-data.md)[E2](https://bugbountylibrary.com/r/h1%3A1189367.md), plus stored XSS and forced client-side requests [E1](https://bugbountylibrary.com/r/blog%3Abuer-haus-2016-04-18-esea-server-side-request-forgery-and-querying-aws-meta-data.md)[E3](https://bugbountylibrary.com/r/h1%3A745953.md). Severity rises when the fetcher returns the response body to the attacker and when metadata credentials are reachable; blind SSRF is lower. Naive string checks and unrestricted schemes made it worse.

## Evidence
- E1: https://bugbountylibrary.com/r/blog%3Abuer-haus-2016-04-18-esea-server-side-request-forgery-and-querying-aws-meta-data.md
- E2: https://bugbountylibrary.com/r/h1%3A1189367.md
- E3: https://bugbountylibrary.com/r/h1%3A745953.md
