# URL helper reserved param passthrough

URL builders honoring unfiltered reserved params (domain, script_name, location) that rewrite links or redirects

_Area: Web injection and code execution. Seen in 3 disclosed reports; 3 confirmed bounties, median $1,000, range $500-$4,000; latest 2021-01-08. Updated 2026-10-31._

## How it works
A URL helper or redirect sink builds a link from request parameters, but the filter in front of it only blocks a few obvious keys (host, port, protocol) or checks a URL prefix. The framework underneath honors a wider set of reserved options — `domain`, `script_name`, `anchor`, `location` — that silently rewrite the generated URL. Any key the filter misses stays attacker-controlled and reaches the sink. The broken assumption: "we filtered the dangerous params" when the filter list is narrower than the framework's actual reserved-key list.

## Where it shows up
- A helper that allowlists/denylists params before calling `url_for` or building a `Location` header.
- Params reflected into a link `href` or a redirect target, especially `from`, `location`, `domain`, `script_name`.
- Prefix-based URL validation ("must start with /path") that control chars like `%0A`/`%09` can defeat.
- Client-side nav handlers that read a JSON `location` field from a response and redirect to it.
- Middleware endpoints (e.g. `/rails/actions`) taking `location` straight from request params.

## How to review
Diff the helper's filtered key set against the framework's full reserved-options list; every unfiltered reserved key is a candidate. For each sink, confirm the final URL is constrained to a relative/safe path after all rewriting, not just at input. The invariant: no request-controlled value may set scheme, host, or path prefix of the emitted URL or `Location` header. For client nav, the redirect target must be validated server-side, not trusted from a fetched JSON field.

## Variants seen
- Helper stripped host/port/protocol but left `domain`/`script_name`, enabling open redirect and reflected XSS via `url_for` [E1](https://bugbountylibrary.com/r/h1%3A946728.md).
- LF (`%0A`) in `from` bypassed prefix check, injected external host into Back link, whose JSON `location` became a `javascript:` redirect (DOM XSS) [E2](https://bugbountylibrary.com/r/h1%3A874198.md).
- `location` param passed unvalidated into `Location` header in Rails middleware [E3](https://bugbountylibrary.com/r/h1%3A904059.md).

## Why fixes fail
E3 shows a CVE patch narrowing one condition while an adjacent unvalidated `location` param in the same middleware stayed exposed — reviewers must diff sibling params after a fix lands.

## Impact and severity
Open redirect, reflected and DOM XSS; median bounty 1000 (range 500-4000). Worse when the sink feeds a client-side redirect or when the helper is used across many routes [E1](https://bugbountylibrary.com/r/h1%3A946728.md).

## Evidence
- E1: https://bugbountylibrary.com/r/h1%3A946728.md
- E2: https://bugbountylibrary.com/r/h1%3A874198.md
- E3: https://bugbountylibrary.com/r/h1%3A904059.md
