July 4, 2026
Fail-Open Authentication Bypass to Account Takeover
During a security assessment of a web app, I discovered a critical authentication bypass that allowed account takeover of arbitrary users.
By debang5hu
2 min read
๐ Heyo Internet!
I am debang5hu and over here I'll be sharing my finding and methodology from a recent security assessment on a VDP.
Let's dive in!
Introduction
While testing the authentication flow of a web application, I discovered a critical authentication bypass that ultimately led to full Account Takeover (ATO). What made this vulnerability particularly interesting was its simplicity providing an incorrect password resulted in an "Invalid Credentials" error, as intended. However, removing the password parameter entirely caused the application to authenticate the user successfully.
Understanding the Authentication Flow
During testing, I observed that the application supported two different authentication mechanisms:
- Email and password authentication via
/api/pwa/authenticateV3 - Google OAuth authentication via
/api/pwa/authenticateV2
My initial approach was to analyze whether the two authentication flows handled user input differently. Since both endpoints ultimately authenticated users, I wanted to see whether parameters from one authentication method could be accepted by the other.
I first attempted to send the complete OAuth authentication payload directly to the email based authentication endpoint, effectively swapping the request body between the two flows. The application correctly rejected this, indicating that the endpoint expected its own distinct payload structure.
Next, I took a more targeted approach instead of swapping the entire payload, I modified only the email based request by replacing the password parameter with the oauth_code parameter from the OAuth flow, while keeping the rest of the payload structure intact. Surprisingly, the server returned a successful authentication response. This raised an immediate question "how could a parameter meant for an entirely different authentication mechanism produce a valid login?" To investigate further, I removed the oauth_code parameter as well, leaving only the email address in the request body. To my surprise, the server continued to authenticate the user successfully and returned a valid login token โ revealing that the endpoint could authenticate users based solely on a supplied email address, with no password validation at all.
Root Cause Analysis
The issue appeared to stem from a fail-open authentication implementation.
Conceptually, secure authentication should follow logic similar to:
user = find_user(email)
if not user:
reject()
if not verify_password(user, password):
reject()
login(user)user = find_user(email)
if not user:
reject()
if not verify_password(user, password):
reject()
login(user)The vulnerable implementation likely behaved more like:
user = find_user(email)
if not user:
reject()
if password:
if not verify_password(user, password):
return "invalid credentials"
return login(user)user = find_user(email)
if not user:
reject()
if password:
if not verify_password(user, password):
return "invalid credentials"
return login(user)As a result:
- Incorrect password โ authentication failed.
- Correct password โ authentication succeeded.
- Missing password โ password validation was skipped entirely.
The application authenticated users based solely on email existence when the password parameter was omitted.
Disclosure Timeline
- Reported through Bugcrowd on 2 Jul 2026 09:04:17 GMT+0
- Triaged and accepted on 02 Jul 2026 09:54:48 GMT+0
- Resolved on 02 Jul 2026 13:49:08 GMT+0
๐ This finding reinforces the importance of testing how applications handle missing, null, and unexpected parameters. It is always worth exploring edge cases and unconventional input scenarios, as seemingly minor validation oversights can sometimes lead to critical vulnerabilities.
Sayonara!!!