# Auth check-then-act race conditions

First-user/admin or session state decided by a check before an insert, with no atomic guard

_Area: Web authentication and account takeover. Seen in 3 disclosed reports; latest 2026-09-21. Updated 2026-11-01._

## How it works
An auth decision reads shared state ("is onboarding done?", "are there zero users?", "is there an auth context for this subscriber?") and then acts on it (create admin, store context). Between the read and the write, another request can do the same read and reach the same conclusion. The assumption that breaks is that the check and the act are one step. Without a lock, transaction, or unique constraint, concurrent requests all pass the check and all perform the privileged action [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-pxcx-fv34-x9p5.md)[E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-h3ww-q6xx-w7x3.md), or overwrite each other's in-progress state [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-334q-h5g3-fpxv.md).

## Where it shows up
- Endpoints registered as anonymous/whitelisted (onboarding, first-run, setup) whose handlers call a global flag check then Save() [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-pxcx-fv34-x9p5.md)
- First-user or owner role assigned from a `has_users()`/`count()==0` check before the user insert [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-h3ww-q6xx-w7x3.md)
- Parallel registration paths (LDAP, OAuth, SSO, invite) that each re-implement the same pre-insert count check [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-h3ww-q6xx-w7x3.md)
- A `sync.Map` keyed only by subscriber/user identity with unconditional `Store()`, no `LoadOrStore` [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-334q-h5g3-fpxv.md)
- Session or auth-context URLs that embed only a stable identity (SUPI/SUCI) rather than a per-session ID [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-334q-h5g3-fpxv.md)

## How to review
For every privileged auth decision, find the exact invariant and confirm it is enforced atomically. The property: the check and the write must be a single atomic operation — a DB unique constraint or conditional insert (insert-then-check), a transaction with row lock, or `LoadOrStore` — not a read followed by a separate write. For first-user/admin: confirm a unique constraint makes only one insert succeed. For session state: confirm each auth procedure gets its own keyed context and concurrent requests cannot clobber it. Grep route registration for anonymous endpoints and read each handler for check-then-act on global flags [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-pxcx-fv34-x9p5.md).

## Variants seen
- Unauthenticated onboarding-finish race creating multiple ReadWrite admins with admin JWTs [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-pxcx-fv34-x9p5.md)
- First-login race across LDAP/OAuth paths assigning admin to every concurrent first user [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-h3ww-q6xx-w7x3.md)
- Concurrent auth requests overwriting a SUPI-keyed context, breaking AT_MAC verification and denying a targeted subscriber [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-334q-h5g3-fpxv.md)

## Why fixes fail
A TOCTOU fix landed in signup_handler (insert-then-check) but the LDAP and OAuth paths kept the pre-insert count check, leaving the race open [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-h3ww-q6xx-w7x3.md). Fixing one registration path does not fix the others.

## Impact and severity
Unauthenticated admin account creation and admin JWT issuance [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-pxcx-fv34-x9p5.md), multiple admin accounts from concurrent first logins [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-h3ww-q6xx-w7x3.md), and targeted authentication denial [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-334q-h5g3-fpxv.md). Severity is highest when the endpoint is anonymous and the created role is full admin; incomplete fixes across parallel paths make it worse.

## Evidence
- E1: https://bugbountylibrary.com/r/ghsa%3AGHSA-pxcx-fv34-x9p5.md
- E2: https://bugbountylibrary.com/r/ghsa%3AGHSA-334q-h5g3-fpxv.md
- E3: https://bugbountylibrary.com/r/ghsa%3AGHSA-h3ww-q6xx-w7x3.md
