Summary

During testing of a food delivery application, I found an Insecure Direct Object Reference (IDOR) in the login API that leaked user details. Combined with a flaw in the OTP-based password reset flow, this led to full account takeover of any user.

The IDOR

The login endpoint returned more data than necessary in its response. A POST to /api/v1/login with valid credentials returned:

{
  "status": "success",
  "user": {
    "id": 14832,
    "email": "[email protected]",
    "phone": "+1-555-0142",
    "name": "John Doe",
    "address": "123 Main St",
    "role": "customer"
  }
}

The problem: the same response structure was returned when querying other user IDs via /api/v1/users/<id>. No authorization check. Incrementing the id parameter returned full profile data for any user in the system.

This alone is a significant data leak. But it gets worse.

The OTP Flaw

The application used OTP (one-time password) sent via SMS for password resets. The flow:

  1. User enters phone number on the forgot-password page
  2. Server sends a 4-digit OTP via SMS
  3. User enters the OTP
  4. Server validates and allows password reset

Two problems:

  1. No rate limiting on OTP verification. The endpoint accepted unlimited attempts.
  2. 4-digit OTP space is only 10,000 combinations. Brute-forceable in seconds.

The Chain

  1. Use the IDOR to get the target user’s phone number from /api/v1/users/<id>
  2. Trigger a password reset for that phone number
  3. Brute-force the 4-digit OTP (10,000 requests, no rate limiting)
  4. Reset the password
  5. Full account access

Total time from IDOR to account takeover: under 2 minutes with a simple script.

Impact

  • Any user account could be taken over by any authenticated user
  • Personal data (email, phone, address) of all users exposed via IDOR
  • No user interaction required

Takeaways

  • API responses should return only the data the requesting user is authorized to see.
  • OTP brute-force protection is mandatory: rate limiting, account lockout after N failed attempts, and OTP length should be at least 6 digits.
  • Authorization checks on every endpoint, not just the ones that “look sensitive.”

Timeline

Date Event
2018-08-10 Vulnerability discovered
2018-08-10 Reported to vendor
2018-08-14 Vendor acknowledged
2018-08-20 Fix deployed (rate limiting + authorization check)