# Absence of Token expiry leads to Unauthorized login Access

Affirm's phone-login token never expired, letting an attacker brute-force the 4-digit SMS OTP and take over any account.

- Payout: hidden
- Severity: critical
- Program: Affirm
- Found by: yogesh_ojha
- Disclosed: 2020-12-01
- Write-up quality: 6/10
- Original: https://hackerone.com/reports/766578
- Library page: https://bugbountylibrary.com/r/h1%3A766578
- Tags: area:mobile domain:mobile impact:ato kind:bounty platform:hackerone sev:critical technique:recon vuln:account-takeover vuln:auth-bypass vuln:business-logic vuln:mfa-bypass

**Target:** Mobile app login API (/api/v3/login/phone/)
**Root cause:** The login token returned by /api/v3/login/phone/ never expires and has no attempt limit, so the 4-digit OTP can be brute-forced indefinitely against the same token.
**Steps:**
1. POST `/api/v3/login/phone/` with `{"channel":"sms","address":"<victim phone>"}` to get `response_url` containing SOMETOKEN
2. POST `/api/v3/login/phone/SOMETOKEN` with `{"response":"0000"}` repeatedly via Intruder over the 0000-9999 space
3. Detect success by 200 status and response length/`"status":"authenticated"`
4. Extract `Affirm-Client` session token and `user_id` from the success response
5. GET `/api/v2/users/<user_id>` with the `Affirm-Client` header to confirm account access
**How found:** While testing the mobile app, the researcher noticed the login token in response_url persisted across many OTP attempts, hypothesizing it could be brute-forced with Intruder.
**Exploitation:** Attacker requests a login token for the victim's phone number, then brute-forces the 4-digit OTP against the non-expiring token until authenticated, obtaining an Affirm-Client session token that grants full account access.
**Insight:** When a login flow issues a per-session token before OTP entry, test whether that token expires or rate-limits after failed attempts; a static token plus a short numeric OTP is a brute-forceable ATO.

