# nginx ignition has Unauthenticated Admin Account Creation via Onboarding Race Condition

Unauthenticated POST /api/users/onboarding/finish in nginx-ignition has a TOCTOU race letting attackers create full ReadWrite admin accounts and receive admin JWTs.

- Payout: Research
- Severity: high
- Program: nginx-ignition
- Found by: tikket1
- Disclosed: 2026-09-21
- CVE: CVE-2026-61628
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-pxcx-fv34-x9p5
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-pxcx-fv34-x9p5
- Tags: area:web domain:api domain:web impact:ato impact:privesc kind:research platform:ghsa sev:high tech:go technique:race-window technique:source-review vuln:access-control vuln:auth-bypass vuln:race-condition

**Target:** Go web API endpoint POST /api/users/onboarding/finish
**Root cause:** The onboarding-finish handler performs a check-then-act between OnboardingCompleted() and Save() with no lock, transaction, or unique constraint, so concurrent requests all pass the 'not finished' check and each create an admin user.
**Steps:**
1. Reach an instance in pre-onboarding state (fresh deployment or reset).
2. Fire concurrent requests: `for i in $(seq 1 20); do curl -s -X POST http://TARGET/api/users/onboarding/finish -H 'Content-Type: application/json' -d '{"username":"attacker'"$i"'","password":"P@ssw0rd123!"}' -o /dev/null -w "%{http_code}\n" & done; wait`
3. Observe multiple 200 responses instead of one 200 plus N×403.
4. Each 200 body returns a userLoginResponseDTO with a JWT granting full ReadWrite admin permissions.
**How found:** Code review of route registration found the endpoint explicitly AllowAnonymous, then reading the handler revealed the check-then-act gap between OnboardingCompleted() and Save() with no atomic guard.
**Exploitation:** Attacker sends a burst of concurrent onboarding-finish requests during the pre-onboarding window; each racing request passes the alreadyFinished check before any commit, creates an admin user with all permissions ReadWrite, and returns a valid admin JWT. Attacker then controls hosts, streams, certificates, settings, users, nginx server config and access lists.
**Escalation:** Admin access to the config surface is itself injectable (related nginx-configuration-injection issues), giving a path to SSRF/arbitrary nginx directives; multiple minted admins aid persistence and stealth alongside the legitimate operator.
**Insight:** Grep route registration for AllowAnonymous/whitelisted endpoints and check whether their handlers do check-then-act on global state (setup/onboarding/first-run flags) without a DB unique constraint — a single-row guard or setup token is the usual missing piece.

