# Auth gate bypass via path or host rewrite

Auth allowlists matched on full URL, path swaps in multi-step flows, and localhost checks trusting Host header

_Area: Web authentication and account takeover. Seen in 3 disclosed reports; latest 2026-10-08. Updated 2026-10-24._

## How it works
An authentication gate decides "is this request allowed?" from a value the client can influence, rather than from a server-owned fact. Three shapes appear: a public-path allowlist tested against the whole URL including the query string; a step gate keyed on the current path, which a sibling path skips; and a "localhost-only" check read from the request's Host header. In each case the gate's input is attacker-controlled, so the gate answers a different question than the one the code assumes.

## Where it shows up
- Route allowlists compiled as unanchored regexes or substring checks against the full URL (path + query) [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-8783-3wgf-jggf.md)
- Multi-step flows (account merge, SSO linking, password set) where the master-password step is just a URL-gated page [E2](https://bugbountylibrary.com/r/h1%3A796956.md)
- "Is this local / trusted?" decided from `request.url.hostname`, `Host`, `X-Forwarded-For`, or `Origin` [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-2gpf-2492-q9jh.md)
- Auth opt-out flags (`AUTH=disabled`) whose safety depends on a request-derived check [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-2gpf-2492-q9jh.md)
- Any middleware that sets `publicEndpoint=true` and thereby skips a global auth check [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-8783-3wgf-jggf.md)

## How to review
Trace every gate to its input. The invariant: the allow/deny decision must depend only on server-owned state (the parsed path component, the socket bind address, a session record), never on the raw URL string or client headers.
- For allowlists: confirm matching is anchored and applied to the path only, not the query string [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-8783-3wgf-jggf.md).
- For multi-step flows: confirm the master-password check is enforced server-side on the action, not implied by which page the request came from [E2](https://bugbountylibrary.com/r/h1%3A796956.md).
- For localhost/trust guards: confirm the check reads the actual bind address or socket, not `Host` [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-2gpf-2492-q9jh.md).
- For patches: re-read the fix and ask what value the new guard reads.

## Variants seen
- Unanchored regex over full URL lets a public path ride in as a query param [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-8783-3wgf-jggf.md)
- Path swap to a sibling endpoint (`new-password`) while keeping the query string, skipping the master-password gate [E2](https://bugbountylibrary.com/r/h1%3A796956.md)
- Spoofed `Host: 127.0.0.1` satisfies a localhost-only guard [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-2gpf-2492-q9jh.md)

## Why fixes fail
E3 is a patch for a prior unconditional disabled-auth bypass; the new guard still trusted a client-controlled value, so the bypass survived in a new form.

## Impact and severity
Unauthenticated access to protected endpoints [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-8783-3wgf-jggf.md), full merchant account takeover despite SSO [E2](https://bugbountylibrary.com/r/h1%3A796956.md), and remote invocation of localhost-only agent APIs [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-2gpf-2492-q9jh.md). Severity is high: the gate is the only boundary, and bypass needs no credentials. Multi-step and SSO flows widen impact because the bypass yields a password reset or takeover, not just read access.

## Evidence
- E1: https://bugbountylibrary.com/r/ghsa%3AGHSA-8783-3wgf-jggf.md
- E2: https://bugbountylibrary.com/r/h1%3A796956.md
- E3: https://bugbountylibrary.com/r/ghsa%3AGHSA-2gpf-2492-q9jh.md
