July 29, 2026
When Password Reset Becomes Login: A Real-World Session Puzzling Vulnerability
A few months ago, I was conducting a penetration test on an enterprise system belonging to a municipality. The goal was to assess different…

By Hossein Zarei
4 min read
A few months ago, I was conducting a penetration test on an enterprise system belonging to a municipality. The goal was to assess different parts of the application based on the vulnerabilities and testing methodologies defined in the OWASP Web Security Testing Guide (WSTG).
One of the areas I was testing was the employee and staff login functionality.
Initially, my plan was to focus on authentication-related vulnerabilities. However, while reviewing the login functionality, I noticed an unusual error behavior in Burp Suite, so I decided to investigate this issue first.
The application had a password recovery functionality. When entering an email address (even an arbitrary one), the application displayed a message indicating that password recovery information had been sent.
However, when I modified the same request using Burp Suite, the server started behaving unexpectedly in certain situations.
For example, the email field validation was only performed on the client side. By sending manipulated requests, I was able to trigger different server-side errors.
Some examples included sending an empty email value or changing the parameter structure into an array:
email[]=email[]=Initial Investigation
The application returned different error responses and exceptions.
This behavior indicated that the server-side logic for this functionality was not properly implemented. Therefore, I decided to investigate how the application's Session was being handled.
The Interesting Part
Assume the user login page was available at:
target.com/logintarget.com/loginand the password reset functionality was available at:
target.com/forgot-passwordtarget.com/forgot-passwordThe application also had a separate management panel for administrators and site operators:
target.com/managetarget.com/manageThe interesting behavior was that after sending the Forgot Password request (even using the manipulated requests), if I immediately accessed:
target.com/managetarget.com/managethe administration panel was displayed without entering any username or password.
As shown in the screenshot above, the admin panel contained login information and passwords belonging to website users (municipality employees).
Impact Verification
To verify the impact, I decided to use one of the username and password combinations exposed in the panel and perform a normal login.
After logging in successfully, sensitive employee information such as salary slips, personnel records, and other internal data became accessible.
Identifying the Vulnerability
After analyzing the application's behavior and comparing it with the OWASP Web Security Testing Guide, I determined that this issue matched the Session Puzzling (also known as Session Variable Overloading) vulnerability pattern.
The root cause was that the same Session Variable was being used in multiple contexts, allowing the password recovery process to affect the authentication state.
To make sure this behavior was not just a random application error, I repeated the same workflow multiple times.
Each time, I followed this sequence:
1. Send Forgot Password request
2. Without performing Login
3. Access the management panel1. Send Forgot Password request
2. Without performing Login
3. Access the management panelThe result was always the same.
The management panel was only accessible when the requests were performed in this specific order.
This indicated that the Forgot Password functionality was modifying the Session state, and later the management panel incorrectly interpreted this Session data as a valid authenticated session.
This testing approach is also consistent with the black-box methodology recommended by OWASP for identifying Session Puzzling vulnerabilities.
What Is the Root Cause?
Based on the observed behavior, the application's logic was most likely similar to the simplified example below.
Note: The following code is only a simplified example to demonstrate the vulnerability. It is not the actual source code of the tested application.
The problem was that a single Session Variable:
$_SESSION["user"]$_SESSION["user"]was used in two different contexts.
Context 1:
Password ResetPassword ResetContext 2:
AuthenticationAuthenticationThis is exactly the type of issue OWASP describes as Session Variable Overloading or Session Puzzling.
The application incorrectly trusted the existence of a Session value that was originally created for another purpose.
A Secure Implementation Approach
In a secure design, every Session Variable should have a single and clearly defined purpose.
Session variables should not be shared between different workflows such as password reset and authentication. OWASP recommends separating Session usage based on responsibility to prevent Session Puzzling vulnerabilities.
For example:
Instead of:
$_SESSION["user"] = $email;$_SESSION["user"] = $email;The password recovery process should use a dedicated Session variable:
$_SESSION["password_reset_email"] = $email;$_SESSION["password_reset_email"] = $email;Authentication should have its own Session structure:
$_SESSION["authenticated"] = true;
$_SESSION["user_id"] = $user["id"];
$_SESSION["role"] = $user["role"];$_SESSION["authenticated"] = true;
$_SESSION["user_id"] = $user["id"];
$_SESSION["role"] = $user["role"];And the admin area should verify authentication explicitly:
if(
isset($_SESSION["authenticated"]) &&
$_SESSION["authenticated"] === true &&
$_SESSION["role"] === "admin"
){
// Allow access
}if(
isset($_SESSION["authenticated"]) &&
$_SESSION["authenticated"] === true &&
$_SESSION["role"] === "admin"
){
// Allow access
}Why Is It Called "Puzzling"?
Because the attacker combines different parts of the application like pieces of a puzzle, creating a flow that developers did not expect.
In my scenario:
/forgot-password
↓
Session is modified
↓
/manage
↓
Admin panel becomes accessible/forgot-password
↓
Session is modified
↓
/manage
↓
Admin panel becomes accessibleThe developer expected the only valid path to reach the admin area to be:
Login
↓
Valid password
↓
Authenticated Session is created
↓
Admin accessLogin
↓
Valid password
↓
Authenticated Session is created
↓
Admin accessHowever, the attacker found another path:
Forgot Password
↓
The same Session Variable is populated
↓
Admin accessForgot Password
↓
The same Session Variable is populated
↓
Admin accessThis is why OWASP classifies this type of weakness as Session Puzzling / Session Variable Overloading.