# CSRF via missing header and referrer leak

State-changing endpoints trusting SameSite, Sec-Fetch-Site, Referer or custom headers that can be absent or forged

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

## How it works
CSRF defenses here rest on a signal the browser is supposed to attach to a request: a custom header, a `Sec-Fetch-Site` value, or a `Referer`. The broken assumption is that the signal is always present and trustworthy. When a navigation path or client omits the signal, the server treats the request as legitimate rather than rejecting it. The defense fails open on absence.

## Where it shows up
- State-changing endpoints whose only guard is `X-Requested-With` or another custom header [E1](https://bugbountylibrary.com/r/h1%3A44146.md).
- Cookie policy relying on `SameSite=Strict` with no server-side token check [E2](https://bugbountylibrary.com/r/h1%3A3253725.md).
- Referer checks that test presence or host match but not the absent case [E3](https://bugbountylibrary.com/r/h1%3A52635.md).
- Browser UI that opens links (split view, side panels, previews) and may skip navigation metadata [E2](https://bugbountylibrary.com/r/h1%3A3253725.md).
- Legacy plugin surfaces (Flash, Silverlight) able to set arbitrary headers, combined with redirects from allowed domains [E1](https://bugbountylibrary.com/r/h1%3A44146.md).

## How to review
For each state-changing endpoint, ask: what happens when the guard signal is missing? The invariant is that a request lacking the expected token, header, or origin metadata must be rejected, not accepted. Check that:
- A per-session anti-CSRF token is validated server-side, independent of headers the client controls.
- `SameSite` is treated as defense-in-depth, never the sole control [E2](https://bugbountylibrary.com/r/h1%3A3253725.md).
- Referer/Origin logic fails closed on null or absent values [E3](https://bugbountylibrary.com/r/h1%3A52635.md).
- Custom-header checks are not assumed to block non-AJAX or plugin clients [E1](https://bugbountylibrary.com/r/h1%3A44146.md).

## Variants seen
- Custom-header-only defense bypassed via plugin-set headers and a 307 redirect [E1](https://bugbountylibrary.com/r/h1%3A44146.md).
- Browser navigation path omitting `Sec-Fetch-Site`, causing Strict cookies to be sent cross-site [E2](https://bugbountylibrary.com/r/h1%3A3253725.md).
- Referer check failing open when the header is stripped via iframe [E3](https://bugbountylibrary.com/r/h1%3A52635.md).

## Impact and severity
In the evidence this led to acting as another user via API calls [E1](https://bugbountylibrary.com/r/h1%3A44146.md) and admin password change [E3](https://bugbountylibrary.com/r/h1%3A52635.md), i.e. account takeover. Severity is high where the endpoint is privileged or the action is irreversible. It worsens when the guard is the only control and the action needs no re-authentication.

## Why fixes fail
Header- and referrer-based checks are brittle: each new client or navigation surface can omit the signal, so patches that add one more header check leave the fail-open behavior intact [E1](https://bugbountylibrary.com/r/h1%3A44146.md)[E2](https://bugbountylibrary.com/r/h1%3A3253725.md)[E3](https://bugbountylibrary.com/r/h1%3A52635.md).

## Evidence
- E1: https://bugbountylibrary.com/r/h1%3A44146.md
- E2: https://bugbountylibrary.com/r/h1%3A3253725.md
- E3: https://bugbountylibrary.com/r/h1%3A52635.md
