CVE-2026-42318
Description
GLPI versions 9.5.0 through 11.0.6 allow low-privilege users to delete any object via the planning feature.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
GLPI versions 9.5.0 through 11.0.6 allow low-privilege users to delete any object via the planning feature.
Vulnerability
GLPI versions 9.5.0 and prior to 10.0.25 and 11.0.7 contain a vulnerability that allows low-privilege users with access to the planning feature to delete any object within the application. This issue affects the planning module of the software.
Exploitation
An attacker with low-privilege user access and permissions to the planning feature can exploit this vulnerability. The attacker needs to interact with the planning interface to initiate the deletion of any object within GLPI.
Impact
Successful exploitation allows an attacker to delete any object in GLPI, leading to data loss and potential disruption of IT management functions. The scope of the compromise is limited to the data within the GLPI instance that the attacker can access via the planning feature.
Mitigation
Upgrade to GLPI version 11.0.7 or 10.0.25 to receive a patch. As a workaround, disable delete rights for User's planning. The fixed versions were released on 2024-05-23 [1].
AI Insight generated on Jun 3, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
2>=9.5.0,<11.0.7+ 1 more
- (no CPE)range: >=9.5.0,<11.0.7
- (no CPE)range: >=9.5.0, <10.0.25, <11.0.7
Patches
3ac57d2f17727Encrypt API session tokens (#23809)
3 files changed · +12 −2
src/Api/API.php+4 −1 modified@@ -336,9 +336,12 @@ protected function initSession($params = []) $this->returnError($error_msg, 401, $error_code, false); } + $session_token = \base64_encode((new GLPIKey())->encrypt($_SESSION['valid_id'])); + unset($_SESSION['valid_id']); // this is not needed for the API, unsetting it prevents any unexpected exposure + // stop session and return session key session_write_close(); - $data = ['session_token' => $_SESSION['valid_id']]; + $data = ['session_token' => $session_token]; // Insert session data if requested $get_full_session = $params['get_full_session'] ?? false;
src/Api/APIRest.php+2 −1 modified@@ -40,6 +40,7 @@ namespace Glpi\Api; use AllAssets; +use GLPIKey; use GLPIUploadHandler; use stdClass; use Toolbox; @@ -601,7 +602,7 @@ public function parseIncomingParams($is_inline_doc = false) // try to retrieve session_token in header if (isset($headers['Session-Token'])) { - $parameters['session_token'] = $headers['Session-Token']; + $parameters['session_token'] = (new GLPIKey())->decrypt(\base64_decode(trim($headers['Session-Token']))); } // try to retrieve app_token in header
src/Api/APIXmlrpc.php+6 −0 modified@@ -35,6 +35,7 @@ namespace Glpi\Api; +use GLPIKey; use Toolbox; class APIXmlrpc extends API @@ -269,6 +270,11 @@ public function parseIncomingParams() ? $parameters[0] : []); + // decrypt session token + if (\array_key_exists('session_token', $this->parameters)) { + $this->parameters['session_token'] = (new GLPIKey())->decrypt(\base64_decode($this->parameters['session_token'])); + } + // transform input from array to object if ( isset($this->parameters['input'])
e035590cb691Prevent conflicts between legacy API auth methods (#23811)
3 files changed · +137 −54
apirest.md+4 −0 modified@@ -1748,6 +1748,10 @@ One of theses parameter(s) is missing: The GLPI setup forbid the login with credentials, you must login with your user_token instead. See your personal preferences page or setup API access in GLPI main interface. +### ERROR_LOGIN_WITH_TOKEN_DISABLED + +The GLPI setup forbid the login with user token, you must login with your login/password instead. + ### ERROR_GLPI_LOGIN_USER_TOKEN The provided user_token seems invalid.
phpunit/APIBaseClass.php+74 −14 modified@@ -52,13 +52,6 @@ public function setUp(): void global $GLPI_CACHE; $GLPI_CACHE->clear(); - $this->initSessionCredentials(); - } - - abstract public function initSessionCredentials(); - - public static function setUpBeforeClass(): void - { // To bypass various right checks // This is mandatory to create/update/delete some items during tests. $_SESSION['glpishowallentities'] = 1; @@ -70,15 +63,20 @@ public static function setUpBeforeClass(): void $_SESSION['glpicronuserrunning'] = "cron_phpunit"; // enable api config - $config = new Config(); - $config->update([ - 'id' => 1, - 'enable_api' => true, - 'enable_api_login_credentials' => true, - 'enable_api_login_external_token' => true, - ]); + Config::setConfigurationValues( + 'core', + [ + 'enable_api' => true, + 'enable_api_login_credentials' => true, + 'enable_api_login_external_token' => true, + ] + ); + + $this->initSessionCredentials(); } + abstract public function initSessionCredentials(); + /** * @tags api * @covers API::initSession @@ -99,6 +97,68 @@ public function testInitSessionUserToken() $this->assertArrayHasKey('session_token', $data); } + /** + * @tags api + * @covers API::initSession + */ + public function testInitSessionUserTokenFailIfNotEnabled() + { + Config::setConfigurationValues( + 'core', + [ + 'enable_api_login_external_token' => false, + ] + ); + + $user = new User(); + $uid = getItemByTypeName('User', TU_USER, true); + $this->assertTrue($user->getFromDB($uid)); + $token = $user->getAuthToken('api_token'); + + $this->query( + 'initSession', + ['query' => ['user_token' => $token]], + 400, + 'ERROR_LOGIN_WITH_TOKEN_DISABLED' + ); + } + + /** + * @tags api + * @covers API::initSession + */ + public function testInitSessionCredentialsFailIfNotEnabled() + { + Config::setConfigurationValues( + 'core', + [ + 'enable_api_login_credentials' => false, + ] + ); + + $this->query( + 'initSession', + ['query' => ['login' => TU_USER, 'password' => TU_PASS]], + 400, + 'ERROR_LOGIN_WITH_CREDENTIALS_DISABLED' + ); + } + + /** + * @tags api + * @covers API::initSession + */ + public function testInitSessionFallbackToCredentials() + { + $data = $this->query( + 'initSession', + ['query' => ['user_token' => 'notvalid', 'login' => TU_USER, 'password' => TU_PASS]], + ); + + $this->assertNotFalse($data); + $this->assertArrayHasKey('session_token', $data); + } + /** * @tags api * @covers API::initSession
src/Api/API.php+59 −40 modified@@ -263,58 +263,77 @@ protected function initSession($params = []) $this->checkAppToken(); $this->logEndpointUsage(__FUNCTION__); - if ( - (!isset($params['login']) - || empty($params['login']) - || !isset($params['password']) - || empty($params['password'])) - && (!isset($params['user_token']) - || empty($params['user_token'])) - ) { + $login = $params['login'] ?? ''; + $password = $params['password'] ?? ''; + $token = $params['user_token'] ?? ''; + + if (($login !== '' || $password !== '') && !$CFG_GLPI['enable_api_login_credentials']) { $this->returnError( - __("parameter(s) login, password or user_token are missing"), + __("usage of initSession resource with credentials is disabled"), 400, - "ERROR_LOGIN_PARAMETERS_MISSING" + "ERROR_LOGIN_WITH_CREDENTIALS_DISABLED", + false ); } - - $auth = new Auth(); - - // fill missing params (in case of user_token) - if (!isset($params['login'])) { - $params['login'] = ''; - } - if (!isset($params['password'])) { - $params['password'] = ''; - } - - $noAuto = true; - if (isset($params['user_token']) && !empty($params['user_token'])) { - $_REQUEST['user_token'] = Sanitizer::dbEscape($params['user_token']); - $noAuto = false; - } elseif (!$CFG_GLPI['enable_api_login_credentials']) { + if ($token !== '' && !$CFG_GLPI['enable_api_login_external_token']) { $this->returnError( - __("usage of initSession resource with credentials is disabled"), + __("usage of initSession resource with user token is disabled"), 400, - "ERROR_LOGIN_WITH_CREDENTIALS_DISABLED", + "ERROR_LOGIN_WITH_TOKEN_DISABLED", false ); } - if (!isset($params['auth'])) { - $params['auth'] = ''; + if ( + (!$CFG_GLPI['enable_api_login_credentials'] || $login === '' || $password === '') + && (!$CFG_GLPI['enable_api_login_external_token'] || $token === '') + ) { + if ($CFG_GLPI['enable_api_login_credentials'] && $CFG_GLPI['enable_api_login_external_token']) { + $this->returnError( + __("parameter(s) login, password or user_token are missing"), + 400, + "ERROR_LOGIN_PARAMETERS_MISSING" + ); + } elseif ($CFG_GLPI['enable_api_login_credentials']) { + $this->returnError( + __("parameter(s) login, password are missing"), + 400, + "ERROR_LOGIN_PARAMETERS_MISSING" + ); + } else { + $this->returnError( + __("parameter user_token is missing"), + 400, + "ERROR_LOGIN_PARAMETERS_MISSING" + ); + } } - // login on glpi - if (!$auth->login($params['login'], $params['password'], $noAuto, false, $params['auth'])) { - $err = implode(' ', $auth->getErrors()); - if ( - isset($params['user_token']) - && !empty($params['user_token']) - ) { - $this->returnError(__("parameter user_token seems invalid"), 401, "ERROR_GLPI_LOGIN_USER_TOKEN", false); - } - $this->returnError($err, 401, "ERROR_GLPI_LOGIN", false); + $authenticated = false; + $error_msg = ''; + $error_code = ''; + $use_token_auth = $CFG_GLPI['enable_api_login_external_token'] && $token !== ''; + $use_login_auth = $CFG_GLPI['enable_api_login_credentials'] && $login !== '' && $password !== ''; + + if ($use_token_auth) { + $_REQUEST['user_token'] = $token; + + $auth = new Auth(); + $authenticated = $auth->login('', '', false, false, $params['auth'] ?? ''); + $error_code = 'ERROR_GLPI_LOGIN_USER_TOKEN'; + $error_msg = __("parameter user_token seems invalid"); + } + if (!$authenticated && $use_login_auth) { + unset($_REQUEST['user_token']); + + $auth = new Auth(); + $authenticated = $auth->login($login, $password, true, false, $params['auth'] ?? ''); + $error_code = 'ERROR_GLPI_LOGIN'; + $error_msg = implode(' ', $auth->getErrors()); + } + + if (!$authenticated) { + $this->returnError($error_msg, 401, $error_code, false); } // stop session and return session key
0ea900cb51a3Bump version
1 file changed · +1 −1
src/autoload/constants.php+1 −1 modified@@ -40,7 +40,7 @@ define('GLPI_ROOT', dirname(__DIR__, 2)); // Current version of GLPI -define('GLPI_VERSION', '11.0.7-dev'); +define('GLPI_VERSION', '11.0.7'); $schema_file = sprintf('%s/install/mysql/glpi-empty.sql', GLPI_ROOT); define(
Vulnerability mechanics
Root cause
"The API session token handling did not properly validate or decrypt session tokens, allowing unauthorized actions."
Attack vector
A low-privilege user with access to the planning module can exploit this vulnerability. By manipulating API requests, they can bypass intended authorization checks. This allows them to perform actions, such as deleting any object within GLPI, that they should not have permission to execute. The vulnerability is present in versions prior to 10.0.25 and 11.0.7 [patch_id=4683553].
Affected code
The vulnerability lies within the API handling code, specifically in `src/Api/APIXmlrpc.php` and `src/Api/APIRest.php`, where session tokens are processed. The changes in `src/Api/API.php` also address the authentication flow for API requests [patch_id=4683553, patch_id=4683554].
What the fix does
The patch introduces encryption and decryption for API session tokens using a GLPI key [patch_id=4683553]. This ensures that only valid and properly authenticated session tokens can be used to interact with the API. Additionally, the patch refactors API authentication logic to prevent conflicts and enforce configuration settings for login credentials and user tokens [patch_id=4683554].
Preconditions
- authThe attacker must be a low-privilege user with access to the planning module.
Generated on Jun 3, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
1News mentions
0No linked articles in our index yet.