VYPR
High severityNVD Advisory· Published Jun 3, 2026

CVE-2026-42321

CVE-2026-42321

Description

GLPI versions 10.0.4 to 10.0.24 are vulnerable to stored XSS in the asset locked tab, allowing technicians to inject malicious scripts.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

GLPI versions 10.0.4 to 10.0.24 are vulnerable to stored XSS in the asset locked tab, allowing technicians to inject malicious scripts.

Vulnerability

Starting in version 10.0.4 and prior to version 10.0.25, GLPI is vulnerable to a stored Cross-Site Scripting (XSS) attack. A technician can store an XSS payload in the asset locked tab. This vulnerability affects GLPI versions 10.0.4 through 10.0.24 [1].

Exploitation

An attacker with technician privileges can exploit this vulnerability by storing an XSS payload within the asset locked tab. No other specific prerequisites or complex steps are detailed in the available references [1].

Impact

Successful exploitation allows an attacker to execute arbitrary JavaScript in the context of another user's browser. This could lead to session hijacking, data theft, or further malicious actions within the GLPI application, depending on the payload used [1].

Mitigation

GLPI versions 10.0.25 and 11.0.7 contain a patch for this vulnerability. Users are advised to upgrade to these versions or later. No workarounds are mentioned in the available references [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
  • Glpi Project/Glpiinferred2 versions
    >=10.0.4,<10.0.25+ 1 more
    • (no CPE)range: >=10.0.4,<10.0.25
    • (no CPE)range: >=10.0.4,<10.0.25

Patches

2
ac57d2f17727

Encrypt API session tokens (#23809)

https://github.com/glpi-project/glpiCédric AnneApr 9, 2026Fixed in 10.0.25via llm-release-walk
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'])
    
e035590cb691

Prevent conflicts between legacy API auth methods (#23811)

https://github.com/glpi-project/glpiCédric AnneApr 9, 2026Fixed in 10.0.25via llm-release-walk
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
    

Vulnerability mechanics

Root cause

"The API session token was not properly encrypted, allowing for manipulation."

Attack vector

A technician with access to GLPI can store an XSS payload within the asset locked tab. This payload can then be triggered when the asset is accessed via the API. The vulnerability is present in versions prior to 10.0.25 and 11.0.7.

Affected code

The vulnerability is related to the handling of API session tokens in `src/Api/APIXmlrpc.php`, `src/Api/API.php`, and `src/Api/APIRest.php`.

What the fix does

The patch encrypts API session tokens using a GLPI key before they are transmitted and decrypts them upon receipt. This prevents unauthorized modification or injection of malicious data into the session token. The changes are applied to `src/Api/APIXmlrpc.php`, `src/Api/API.php`, and `src/Api/APIRest.php` [patch_id=4683548].

Preconditions

  • authThe attacker must be a technician with access to GLPI.
  • inputThe attacker must be able to store an XSS payload in the asset locked tab.

Generated on Jun 3, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

1

News mentions

0

No linked articles in our index yet.