CVE-2024-29023 (PHP, published 2024-04-12T21:15Z)
Description: value: Xibo is an Open Source Digital Signage platform with a web content management system and Windows display player software. Session tokens are exposed in the return of session search API call on the sessions page. Subsequently they can be exfiltrated and used to hijack a session. Users must be granted access to the session page, or be a super admin. Users should upgrade to version 3.3.10 or 4.0.9 which fix this issue. Customers who host their CMS with the Xibo Signage service have already received an upgrade or patch to resolve this issue regardless of the CMS version that they are running. Patches are available for earlier versions of Xibo CMS that are out of security support: 2.3 patch ebeccd000b51f00b9a25f56a2f252d6812ebf850.diff. 1.8 patch a81044e6ccdd92cc967e34c125bd8162432e51bc.diff. There are no known workarounds for this vulnerability.
Severity: nan (CVSS v3 base score: )
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/xibosignage/xibo-cms
Files changed:
lib/Controller/Sessions.php
lib/Factory/SessionFactory.php
lib/Helper/Environment.php
lib/Helper/Session.php
lib/Xmds/Soap.php
views/sessions-form-confirm-logout.twig
Commit message: Improvements to filtering IP and sessions (#2433)

* Sessions: Add sanitization in getIp() and disable output of session ID in session grid. xibosignage/xibo#3375
* Bump to 4.0.9

Vulnerable code:
                        ['id' => $row->sessionId]
     * @param $id
    function confirmLogoutForm(Request $request, Response $response, $id)
            'sessionId' => $id,
    function logout(Request $request, Response $response, $id)
        $session = $this->sessionFactory->getById($id);

        if ($session->userId != 0) {
            $this->store->update(
                'UPDATE `session` SET IsExpired = 1 WHERE userID = :userId ',
                ['userId' => $session->userId]
            );
        } else {
            $this->store->update(
                'UPDATE `session` SET IsExpired = 1 WHERE session_id = :session_id ',
                ['session_id' => $id]
            );
        }
 * Copyright (c) 2022 Xibo Signage Ltd
 * Xibo - Digital Signage - http://www.xibo.org.uk
use Xibo\Support\Exception\NotFoundException;
     * @param $sessionId
     * @return Session
     * @throws NotFoundException
    public function getById($sessionId)
        $session = $this->query(null, ['sessionId' => $sessionId]);

        if (count($session) <= 0)
            throw new NotFoundException();

        return $session[0];
            $entries[] = $this->createEmpty()->hydrate($row, ['stringProperties' => ['sessionId']]);
    public static $WEBSITE_VERSION_NAME = '4.0.8';
 * Copyright (C) 2023 Xibo Signage Ltd
        $userAgent = substr($_SERVER['HTTP_USER_AGENT'], 0, 253);
            'useragent' => substr($_SERVER['HTTP_USER_AGENT'], 0, 253),
            if (isset($_SERVER[$key])) {
            if (isset($_SERVER[$key])) {
            <form id="sessionsConfirmLogoutForm" class="XiboForm form-horizontal" method="delete" action="{{ url_for("sessions.confirm.logout", {id: sessionId}) }}">

Fixed code:
                // No buttons on expired sessions
                if ($row->isExpired == 1) {
                    continue;
                }

                        ['id' => $row->userId]
     * @param int $id The UserID
    public function confirmLogoutForm(Request $request, Response $response, $id)
            'userId' => $id,
    public function logout(Request $request, Response $response, $id)
        // We log out all of this user's sessions.
        $this->sessionFactory->expireByUserId($id);
 * Copyright (C) 2024 Xibo Signage Ltd
 * Xibo - Digital Signage - https://xibosignage.com
     * @param int $userId
    public function expireByUserId(int $userId): void
        $this->getStore()->update(
            'UPDATE `session` SET IsExpired = 1 WHERE userID = :userId ',
            ['userId' => $userId]
        );
            $session = $this->createEmpty()->hydrate($row, [
                'stringProperties' => ['sessionId'],
                'intProperties' => ['isExpired'],
            ]);
            $session->userAgent = htmlspecialchars($session->userAgent);
            $session->remoteAddress = filter_var($session->remoteAddress, FILTER_VALIDATE_IP);
            $session->excludeProperty('sessionId');
            $entries[] = $session;
    public static $WEBSITE_VERSION_NAME = '4.0.9';
 * Copyright (C) 2024 Xibo Signage Ltd
        $userAgent = substr(htmlspecialchars($_SERVER['HTTP_USER_AGENT']), 0, 253);
            'useragent' => substr(htmlspecialchars($_SERVER['HTTP_USER_AGENT']), 0, 253),
            if (isset($_SERVER[$key]) && filter_var($_SERVER[$key], FILTER_VALIDATE_IP) !== false) {
            if (isset($_SERVER[$key]) && filter_var($_SERVER[$key], FILTER_VALIDATE_IP) !== false) {
            <form id="sessionsConfirmLogoutForm" class="XiboForm form-horizontal" method="delete" action="{{ url_for("sessions.confirm.logout", {id: userId}) }}">