Introduction
During a security audit of a web application, I discovered an uncommon flaw in the password reset mechanism. Due to insufficient server-side validation, the application failed to properly verify the presence and validity of a reset token, which is a core element of any secure password recovery flow. This oversight made it possible for an attacker to bypass the verification process entirely and reset the password of any user, ultimately leading to full account takeover.
The vulnerability was the result of the backend logic incorrectly handling the token parameter in the password reset request. Instead of enforcing a strict requirement for a valid token associated with a specific user, the server accepted a crafted request containing a maliciously formed token field. This bypassed the intended authorization check and allowed the attacker to set a new password for an account that had recently initiated a reset process, all without ever accessing the reset link or token sent via email.
In the following sections, I will describe how the reset functionality was designed to work, explain how the flaw was discovered, and walk through an example attack. I will also provide practical recommendations for properly securing password reset endpoints.
Understanding the password reset process In a correctly implemented password reset flow, the user initiates the process by entering their email address on a dedicated page. The application responds by generating a unique token and sending it to the provided email address. This token is typically embedded within a URL that points to the password reset page, allowing the user to set a new password. Once the token is received and the user submits a new password, the backend is responsible for verifying the token’s validity, ensuring that it matches a valid entry in the database and has not expired.
The tested application followed this general structure, at least on the surface. When the password reset process was initiated by submitting a user’s email address to the appropriate endpoint, the server responded with a generic success message, indicating that a reset link would be sent if the address existed in the system. This behavior is considered good practice, as it avoids leaking the existence of specific email addresses.
The reset link received via email included a token, which appeared to be a bcrypt hash embedded in the URL. This token would normally be submitted during the final step of the reset process, when the user sets a new password. However, the actual verification logic behind the reset endpoint was flawed.
Step-by-step exploitation The attacker begins by visiting the login page and selecting the "Forgot Password" option. This triggers the password reset flow, which starts with a POST request to the endpoint responsible for initiating the process. The attacker submits the victim’s email address as shown below:
The server responds with a success message indicating that, if the email exists in the system, a reset link has been sent:
In a standard implementation, the user would now receive an email with a reset link containing a token. That link might look something like this:
When the user clicks the link, they are redirected to a form where they can enter a new password. At this point, the frontend sends another POST request to the reset password endpoint, including both the new password and the reset token.
However, the attacker does not follow this process. Instead of using a valid token, they intercept the final request and modify its contents. They prepare a malicious payload like the following:
Rather than including a valid string token, the attacker injects a JSON object using a NoSQL operator. This payload is interpreted by the backend in a way that completely bypasses token validation.
The server accepts this request and responds with a success status:

As a result, the password for the victim’s account is changed without the attacker ever needing access to the actual reset link or token. This method only worked if a valid password reset request had already been initiated for the victim’s email address. Otherwise, there was no token context for the server to misuse.
Root cause and remediation The vulnerability was caused by the application failing to verify the integrity and presence of the token parameter during the final password reset request. In this case, the backend logic allowed the token field to be treated as a dynamic object, which introduced the possibility of using payloads commonly associated with NoSQL injections. The specific use of a structure such as {"$exists": false} strongly suggests that the application was interfacing with a NoSQL database like MongoDB, where such operators are interpreted at query time unless explicitly blocked or sanitized.
To remediate this issue, the server must enforce strict validation rules for the token used during password reset. The token should be mandatory and must be verified against a secure, server-side store to ensure that it was generated for the correct user and has not expired. It must never be possible to submit a password reset request without including a properly formatted and valid token. Furthermore, if a NoSQL database is in use, input data should be validated against a strict schema before it is passed into any query logic. This can be achieved using whitelisting approaches or object sanitization libraries that prevent the injection of special query operators.
It is also recommended to hash the token using a secure algorithm before storing it in the database, similar to how passwords are handled. This prevents token leakage even in the event of a data breach and ensures that the token cannot be trivially reused or forged.
For a comprehensive list of recommendations, the OWASP Forgot Password Cheat Sheet provides a solid foundation for designing a secure reset flow. The resource is available at: https://cheatsheetseries.owasp.org/cheatsheets/Forgot_Password_Cheat_Sheet.html
Conclusion The vulnerability discovered in this case reveals a fundamental failure in the application's authentication flow. By neglecting to enforce proper validation of password reset tokens, the system allowed any user to reset the password of another account, provided a reset process had been recently initiated. This type of flaw poses a serious security risk and can lead to widespread account takeovers if left unaddressed.
The fix requires more than just patching the specific payload used in the attack. It involves rethinking how the server handles and validates sensitive actions like password resets. Ensuring that all requests include a valid, user-specific token, and that tokens are never interpreted as arbitrary objects, is essential to building a secure authentication mechanism.
This case is a strong reminder that even seemingly minor oversights in how inputs are handled can lead to critical vulnerabilities. Security testing should always include verification of edge cases and unexpected input behavior, particularly in flows related to authentication and credential recovery. By taking a defensive approach to input validation and treating all user-controlled data as untrusted, developers can significantly reduce the likelihood of such high-impact security issues.