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
- (Screenshot 1) NORMAL: POST v3/check-otp with one wrong attempt -> Invalid OTP.
- (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
}
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
}
← Previous case: NoSQL Injection - Community - Coupon Validation (Normal Input) Next case: OTP Bruteforce Protection Bypass - Authentication - Password Reset →