CVE-2023-2848 (PHP, published 2023-09-14T12:15Z)
Description: value: Movim prior to version 0.22 is affected by a Cross-Site WebSocket Hijacking vulnerability. This was the result of a missing header validation.
Severity: nan (CVSS v3 base score: 8.8)
Weakness: CWE-346 \u2014 Origin Validation Error
The product does not properly verify that the source of data or communication is valid.
Repository: https://github.com/movim/movim
Files changed:
CHANGELOG.md
src/Movim/Daemon/Core.php
Commit message: Add a same-origin check for non-internal connected Websockets


Vulnerable code:
            echo colorize("Generate and store the Push Notification VAPID keys", 'green')."\n";
            "\n".
            "--- ".colorize("Server Configuration - Apache", 'purple')." ---".
        echo colorize("Enable the Secure WebSocket to WebSocket tunneling", 'yellow')."\n# a2enmod proxy_wstunnel \n";
        echo colorize("Add this in your configuration file (default-ssl.conf)", 'yellow')."\nProxyPass /ws/ ws://127.0.0.1:{$port}/\n";
            "\n".
            "--- ".colorize("Server Configuration - nginx", 'purple')." ---".
        echo colorize("Add this in your configuration file", 'yellow')."\n";
            "\n".
            "--- ".colorize("Server Configuration - Caddy", 'purple')." ---".
            echo colorize("Add this in your configuration file", 'yellow')."\nhandle /ws/* {
                if (array_key_exists($sid, $this->singlelocks)
                && array_key_exists($path, $this->singlelocks[$sid])) {
                if (array_key_exists($sid, $this->singlelocks)
                && array_key_exists($path, $this->singlelocks[$sid])) {
                if ($session->countClients() == 0
                && $session->registered == null) {
            ->where('created_at', '<', date(MOVIM_SQL_DATE, time()-60))
        PushSubscription::where('activity_at', '<', date(MOVIM_SQL_DATE, time()-(60*60*24*30)))
        EncryptedPassword::where('updated_at', '<', date(MOVIM_SQL_DATE, time()-(60*60*24*7)))
        return (isset($arr['offset'])) ? invertSign(((int)$arr['offset'])*60) : 0;
        return ($conn->httpRequest->hasHeader('MOVIM_SESSION_ID')
            && $conn->httpRequest->getHeader('MOVIM_DAEMON_KEY')[0] === $this->key)

Fixed code:
 * Add a same-origin check for non-internal connected Websockets
            echo colorize("Generate and store the Push Notification VAPID keys", 'green') . "\n";
        "\n" .
            "--- " . colorize("Server Configuration - Apache", 'purple') . " ---" .
        echo colorize("Enable the Secure WebSocket to WebSocket tunneling", 'yellow') . "\n# a2enmod proxy_wstunnel \n";
        echo colorize("Add this in your configuration file (default-ssl.conf)", 'yellow') . "\nProxyPass /ws/ ws://127.0.0.1:{$port}/\n";
        "\n" .
            "--- " . colorize("Server Configuration - nginx", 'purple') . " ---" .
        echo colorize("Add this in your configuration file", 'yellow') . "\n";
        "\n" .
            "--- " . colorize("Server Configuration - Caddy", 'purple') . " ---" .
        echo colorize("Add this in your configuration file", 'yellow') . "\nhandle /ws/* {
        if (!$this->isTrustedConnection($conn)) $conn->close();


                if (
                    array_key_exists($sid, $this->singlelocks)
                    && array_key_exists($path, $this->singlelocks[$sid])
                ) {
                if (
                    array_key_exists($sid, $this->singlelocks)
                    && array_key_exists($path, $this->singlelocks[$sid])
                ) {
                if (
                    $session->countClients() == 0
                    && $session->registered == null
                ) {
            ->where('created_at', '<', date(MOVIM_SQL_DATE, time() - 60))
        PushSubscription::where('activity_at', '<', date(MOVIM_SQL_DATE, time() - (60 * 60 * 24 * 30)))
        EncryptedPassword::where('updated_at', '<', date(MOVIM_SQL_DATE, time() - (60 * 60 * 24 * 7)))
        return (isset($arr['offset'])) ? invertSign(((int)$arr['offset']) * 60) : 0;
        return ($conn->httpRequest->hasHeader('MOVIM_SESSION_ID'))

    private function isTrustedConnection(ConnectionInterface $conn): bool
    {
        $daemonKeyHeader = $conn->httpRequest->getHeader('MOVIM_DAEMON_KEY');
        $secFetchSiteHeader = $conn->httpRequest->getHeader('Sec-Fetch-Site');

        return (is_array($daemonKeyHeader) && !empty($daemonKeyHeader) && $daemonKeyHeader[0] === $this->key)
            || (is_array($secFetchSiteHeader) && !empty($secFetchSiteHeader) && $secFetchSiteHeader[0] == 'same-origin');
    }