Back to the index

LAB PASS

OTP Bruteforce Protection - Authentication - Password Reset (Per-Session Lockout)

OTP Bruteforce Protection — Authentication — Password Reset (Per-Session Lockout)

CWE-307: Improper Restriction of Excessive Authentication Attempts (per-session control PRESENT) · OWASP API2:2023 - Broken Authentication (negative test - per-session path)

Vulnerability

[PASS] OTP Bruteforce Protection - Authentication - Password Reset (Per-Session Lockout)

Description

Tested OTP brute force within a single OTP session without requesting a new OTP.

Impact

No impact on this path: lockout triggers after 9 attempts (HTTP 503), so per-session brute force fails.

CWE

CWE-307: Improper Restriction of Excessive Authentication Attempts (per-session control PRESENT)

OWASP

API2:2023 - Broken Authentication (negative test - per-session path)

Scenario

Normal: one OTP attempt -> Invalid. Exploitation: brute force -> lockout 503 after 9 attempts. PASS (per-session control holds). The bypass is covered in [FAIL].

Endpoint

POST http://127.0.0.1:8888/identity/api/auth/v3/check-otp

Affected feature

Password Reset via OTP (crapi-identity)

Remediation

Make the lockout PERSISTENT per account so it cannot be reset by a new OTP request (see the related [FAIL] finding).

Proof of concept

  1. (Screenshot 1) NORMAL: POST v3/check-otp with one wrong attempt -> Invalid OTP.
  2. (Screenshot 2) EXPLOITATION: repeat attempts; on the 10th attempt the lockout triggers -> 503 "You've exceeded the number of attempts" (per-session control holds).

The complete record

LAB All targets are lab systems. Nothing here is a client engagement. Evidence is shown as recorded; secrets are blacked out.

Normal: one OTP attempt

Normal flow: one incorrect OTP attempt returns Invalid OTP.

HTTP request
POST /identity/api/auth/v3/check-otp HTTP/1.1
Host: 127.0.0.1:8888
Content-Type: application/json

{"email":"[REDACTED-EMAIL]","otp":"9001","password":"[REDACTED-LAB-VALUE]"}
HTTP response
HTTP/1.1 500
Server: openresty/1.27.1.2
Content-Type: application/json
Content-Length: 58

{
  "message": "Invalid OTP! Please try again..",
  "status": 500
}
Normal: one OTP attempt

Result: lockout after 9 OTP attempts (PASS)

Result (PASS): brute-forcing the OTP within one session triggers a lockout after 9 attempts (503 exceeded attempts). The lockout held in this test, but forget-password can bypass it; see [FAIL].

HTTP request
POST /identity/api/auth/v3/check-otp HTTP/1.1
Host: 127.0.0.1:8888
Content-Type: application/json

{"email":"[REDACTED-EMAIL]","otp":"<diulang>","password":"[REDACTED-LAB-VALUE]"}
HTTP response
HTTP/1.1 503
Server: openresty/1.27.1.2
Content-Type: application/json
Content-Length: 66

{
  "message": "You've exceeded the number of attempts.",
  "status": 503
}
Result: lockout after 9 OTP attempts (PASS)

← Previous case: NoSQL Injection - Community - Coupon Validation (Normal Input) Next case: OTP Bruteforce Protection Bypass - Authentication - Password Reset →