# OAuth state and callback CSRF binding

Callback trusts state that is unbound, forgeable, leaked, or truncated, binding attacker tokens to victim sessions

_Area: Web authentication and account takeover. Seen in 7 disclosed reports; 5 confirmed bounties, median $1,600, range $500-$5,000; latest 2023-06-19. Updated 2026-10-23._

## How it works
OAuth/OIDC ties an authorization response to the browser that started the flow using `state` (sometimes with PKCE). The assumption: only the initiating session knows `state`, so a callback carrying it belongs to that session. This breaks when the callback never compares `state` to the session, accepts a `state` the attacker can read or forge (unsigned base64 JSON, echoed in an error, or truncated at a null byte), or redirects based on request-controlled data. Then an attacker's code or token binds to the victim's session, or the victim's code/token goes to the attacker.

## Where it shows up
- Callback handlers that consume `code`/`token` without comparing `state` to the session.
- `state` that is base64 JSON with URL/host fields the server later redirects to, unsigned.
- Error or debug responses that echo the expected `state`, `nonce`, or PKCE verifier.
- Post-callback redirects driven by the `Referer` header or other request input.
- Initiation endpoints reachable by GET, so the flow can be started on a victim's behalf (login CSRF).
- Callbacks that write data using the caller's token (e.g. saving to a linked Drive).
- Consent screens that don't name the destination project/tenant (a chained factor, not state binding itself).

## How to review
Trace one flow end to end. The invariant: the `state` at the callback must equal the value stored server-side for that user's session, single-use and unguessable. Check that `state` is opaque or integrity-protected, never echoed in any response (inspect error/debug JSON explicitly [E6](https://bugbountylibrary.com/r/h1%3A1878381.md)), and that no redirect target (including `Referer`) comes from the request [E1](https://bugbountylibrary.com/r/blog%3Aarneswinnen-net-2017-06-authentication-bypass-on-airbnb-via-oauth-tokens-theft.md). Confirm initiation can't be forged cross-site, and that the consent screen discloses the destination resource [E7](https://bugbountylibrary.com/r/h1%3A226199.md). For data-writing callbacks, confirm the token is bound to the session before use [E5](https://bugbountylibrary.com/r/blog%3Ablog-shashank-co-2017-11-stealing-bitcoin-wallet-backups-from-html.md).

## Variants seen
- Login CSRF plus Referer-based open redirect in the callback, stealing OAuth codes/tokens [E1](https://bugbountylibrary.com/r/blog%3Aarneswinnen-net-2017-06-authentication-bypass-on-airbnb-via-oauth-tokens-theft.md).
- Unsigned base64-JSON `state` with attacker-controllable `AppURL` redirecting code/token to an attacker host [E2](https://bugbountylibrary.com/r/blog%3Aobmiblog-blogspot-com-2019-12-gcp-5k-oauth-token-hijack-html.md).
- Missing CSRF/state on a Drive callback, binding the attacker's token to the victim and exfiltrating backups [E5](https://bugbountylibrary.com/r/blog%3Ablog-shashank-co-2017-11-stealing-bitcoin-wallet-backups-from-html.md).
- Integration link flow with no CSRF plus a consent screen hiding the target project [E7](https://bugbountylibrary.com/r/h1%3A226199.md).
- CSRF token not validated against the session, reusable to bind a victim's third-party account to the attacker [E3](https://bugbountylibrary.com/r/h1%3A1727221.md).
- Null byte appended to `state` bypassing a prior CSRF fix via string truncation [E4](https://bugbountylibrary.com/r/h1%3A1046630.md).

## Why fixes fail
Locking down `redirect_uri` alone is insufficient: the post-callback `Referer` redirect still leaks codes [E1](https://bugbountylibrary.com/r/blog%3Aarneswinnen-net-2017-06-authentication-bypass-on-airbnb-via-oauth-tokens-theft.md). Adding `state` doesn't help if it's forgeable [E2](https://bugbountylibrary.com/r/blog%3Aobmiblog-blogspot-com-2019-12-gcp-5k-oauth-token-hijack-html.md), leaked in errors [E6](https://bugbountylibrary.com/r/h1%3A1878381.md), or compared with truncation-prone logic [E4](https://bugbountylibrary.com/r/h1%3A1046630.md).

## Impact and severity
Led to full account takeover and authentication bypass [E1](https://bugbountylibrary.com/r/blog%3Aarneswinnen-net-2017-06-authentication-bypass-on-airbnb-via-oauth-tokens-theft.md), session/token hijack [E2](https://bugbountylibrary.com/r/blog%3Aobmiblog-blogspot-com-2019-12-gcp-5k-oauth-token-hijack-html.md), data exfiltration [E5](https://bugbountylibrary.com/r/blog%3Ablog-shashank-co-2017-11-stealing-bitcoin-wallet-backups-from-html.md), and integration relinking that cloned reports [E7](https://bugbountylibrary.com/r/h1%3A226199.md). Severity is high when the callback yields a session or token; worse combined with open redirects, forgeable initiation, or leaked state.

## Evidence
- E1: https://bugbountylibrary.com/r/blog%3Aarneswinnen-net-2017-06-authentication-bypass-on-airbnb-via-oauth-tokens-theft.md
- E2: https://bugbountylibrary.com/r/blog%3Aobmiblog-blogspot-com-2019-12-gcp-5k-oauth-token-hijack-html.md
- E3: https://bugbountylibrary.com/r/h1%3A1727221.md
- E4: https://bugbountylibrary.com/r/h1%3A1046630.md
- E5: https://bugbountylibrary.com/r/blog%3Ablog-shashank-co-2017-11-stealing-bitcoin-wallet-backups-from-html.md
- E6: https://bugbountylibrary.com/r/h1%3A1878381.md
- E7: https://bugbountylibrary.com/r/h1%3A226199.md
