CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-4HV6-XC92-J86G

GHSA-4HV6-XC92-J86G: Insufficient Session Expiration in Vikunja WebSocket Authentication Pipeline

Alon Barad
Alon Barad
Software Engineer

Oct 10, 2026·5 min read·3 visits

Executive Summary (TL;DR)

Vikunja's WebSocket authentication pipeline skips database session state validation, allowing revoked JWT tokens to establish new real-time event streams and permitting existing connections to leak data indefinitely post-revocation.

Vikunja versions 2.3.0 through 2.6.0 contain an insufficient session expiration vulnerability (CWE-613) within the WebSocket authentication handler. Although Vikunja enforces server-side session tracking and revocation for REST API routes, the WebSocket handshake handler validates cryptographic JWT signatures without querying the database session state. Consequently, revoked JWT tokens can establish new real-time WebSocket connections, and existing connections persist after session revocation.

Vulnerability Overview

Vikunja (code.vikunja.io/api) is an open-source project and task management platform. To provide real-time updates across multi-user workspaces, Vikunja exposes a WebSocket endpoint at GET /api/v2/ws. This endpoint streams live events including task modifications, comment notifications, and project metadata updates to connected clients.

Beginning in version 2.3.0 and refined through version 2.6.0, Vikunja implemented server-side session tracking and revocation capabilities. Users can view and delete active sessions via DELETE /api/v2/user/sessions/{id}. Furthermore, security actions such as enabling Two-Factor Authentication (TOTP) execute DeleteAllUserSessions (pkg/routes/api/v2/user_totp.go:208) to invalidate all active user sessions across devices.

However, a design mismatch exists between the HTTP REST middleware and the WebSocket authentication pipeline. While HTTP REST routes check the session database table before fulfilling requests, the WebSocket endpoint verifies only the cryptographic signature and claim types of the user JWT token. As a result, the WebSocket authentication pipeline fails to enforce session revocation, violating the expected security boundaries of CWE-613.

Root Cause Analysis

The root cause resides in the decoupled token validation mechanism used during the WebSocket authentication handshake in pkg/websocket/connection.go. When a client initiates a connection to /api/v2/ws, the server invokes Connection.handleAuth to process authentication claims.

During handleAuth, token extraction and parsing delegate to auth.GetUserIDFromToken in pkg/modules/auth/auth.go. The function parses the JWT token using the configured service secret and checks internal claim fields. Specifically, it confirms that claims["type"] corresponds to AuthTypeUser and extracts the target user ID.

func GetUserIDFromToken(tokenString string) (int64, error) {
    token, err := jwt.Parse(tokenString, func(_ *jwt.Token) (any, error) {
        return []byte(config.ServiceSecret.GetString()), nil
    })
    if err != nil {
        return 0, err
    }
    claims, ok := token.Claims.(jwt.MapClaims)
    if !ok || !token.Valid {
        return 0, jwt.ErrTokenUnverifiable
    }
    typ, ok := claims["type"].(float64)
    if !ok || int(typ) != AuthTypeUser {
        return 0, jwt.ErrTokenInvalidClaims
    }
    // Session ID ("sid") claim present in claims["sid"] is ignored
    return int64(claims["user_id"].(float64)), nil
}

While NewUserJWTAuthtoken (pkg/modules/auth/auth.go:188) injects a session identifier claim (claims["sid"] = sessionID) into generated access tokens, GetUserIDFromToken does not evaluate the sid claim. No query is performed against the database session table to verify whether the session ID remains active.

Architectural Analysis & Code Differences

The failure model involves both initial handshake authentication and post-connection session lifecycle management. The architectural divergence between REST endpoints and WebSocket channels creates an inconsistent security model across the application surface.

For standard REST HTTP endpoints, authentication middleware retrieves the sid claim from the JWT token and verifies its existence in the database sessions table. If an administrator or user revokes the session, subsequent REST requests fail with 401 Unauthorized regardless of the cryptographic validity of the JWT token.

In contrast, the WebSocket authentication pipeline relies exclusively on signature validity. Furthermore, when DeleteUserSession or DeleteAllUserSessions executes, no broadcast signal or cleanup event is dispatched to the WebSocket connection manager. Consequently, active sockets remain registered in the WebSocket hub, receiving real-time server events indefinitely.

Exploitation Mechanics & PoC Walkthrough

Exploitation requires an attacker or unauthorized user to possess a signed, unexpired JWT token associated with a session that was deleted or revoked on the server. The workflow proceeds through four primary stages.

First, an authenticated user logs into Vikunja and obtains a valid JWT access token. The application embeds both the user ID (user_id) and session ID (sid) in the token payload.

Second, session revocation is triggered. This occurs when the user clicks 'Revoke Session' in the user settings UI, when an administrator revokes active sessions, or when TOTP two-factor authentication is configured, which executes DeleteAllUserSessions.

Third, the client attempts to use the revoked JWT token across both endpoints. An HTTP GET request to /api/v2/tasks is rejected with 401 Unauthorized because the session ID no longer exists in the database. However, a WebSocket connection request to /api/v2/ws using the same token succeeds, establishing a persistent channel.

Fourth, once connected to the WebSocket hub, the client automatically receives server-pushed notifications, including notification.created events. These payloads contain real-time updates on tasks, internal comments, and workspace project changes.

Impact Assessment & Mitigation Guidance

This vulnerability carries a CVSS v3.1 base score of 6.5 (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N). The primary impact is confidentiality loss due to unauthorized access to real-time project updates and user notification feeds.

Because WebSocket connections can remain active for long durations without re-authentication, an attacker who obtains a short-lived access token can retain long-term monitoring access even after the legitimate user revokes all sessions or resets their credentials.

Remediation requires maintainers to modify pkg/websocket/connection.go. During Connection.handleAuth, the handler must extract the sid claim from the incoming JWT and perform a database lookup against the active sessions table prior to upgrading the HTTP connection to a WebSocket protocol.

Additionally, the connection manager must implement a session invalidation listener. When a session row is deleted from the database, the server must push an internal termination signal to the WebSocket hub to forcibly close all open socket instances tied to the revoked sid or user_id.

Official Patches

VikunjaOfficial Security Advisory

Technical Appendix

CVSS Score
6.5/ 10
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N

Affected Systems

Vikunja Server API (`code.vikunja.io/api`)

Affected Versions Detail

Product
Affected Versions
Fixed Version
Vikunja
go-vikunja
>= 2.3.0, <= 2.6.0Not reported
AttributeDetail
CWE IDCWE-613
Attack VectorNetwork (Authenticated WS Handshake with Revoked Token)
CVSS v3.1 Score6.5 (Medium)
ImpactInformation Disclosure via Real-Time Server-Pushed Data Stream
Exploit StatusProof of Concept Available
CISA KEV StatusNot Listed
Affected Componentpkg/websocket/connection.go & pkg/modules/auth/auth.go

MITRE ATT&CK Mapping

T1098Account Manipulation
Persistence
T1539Steal Web Session Cookie / Token
Credential Access
T1119Automated Collection
Collection
CWE-613
Insufficient Session Expiration

The software does not expire, or insufficiently expires, a session token, exposing an opportunity for attackers to reuse expired or revoked session tokens.

Vulnerability Timeline

GitHub Security Advisory GHSA-4hv6-xc92-j86g published
2026-10-09
Public vulnerability details and PoC reported by researcher Tan-JunWei
2026-10-09

References & Sources

  • [1]GitHub Security Advisory GHSA-4hv6-xc92-j86g
  • [2]GitHub Advisory Database Entry
  • [3]Vikunja Source Code Repository

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•17 minutes ago•CVE-2026-107805
7.5

CVE-2026-107805: Unauthenticated Storage Exhaustion in Nginx UI Node Authentication

Nginx UI versions 2.5.0 through 2.5.10 contain an uncontrolled resource consumption vulnerability in the node authentication handler. Unauthenticated remote attackers can exhaust host disk storage and I/O resources by submitting large HTTP request bodies to node-signature endpoints prior to cryptographic signature validation.

Alon Barad
Alon Barad
2 views•6 min read
•about 2 hours ago•GHSA-FPRF-R6RV-XG99
6.5

GHSA-FPRF-R6RV-XG99: Cross-Tenant Task Position Recalculation in Vikunja

A cross-tenant boundary breach vulnerability in Vikunja allows an authenticated user to trigger global task position recalculations across all tenant instances by creating a saved filter with an empty filter string payload.

Amit Schendel
Amit Schendel
5 views•4 min read
•about 3 hours ago•GHSA-HJX8-QV73-F7CM
6.5

GHSA-HJX8-QV73-F7CM: Incomplete Access Revocation Leading to Webhook Data Exfiltration in Vikunja

An access revocation flaw in Vikunja allows removed collaborators to retain outbound webhooks and link shares created prior to revocation, enabling persistent exfiltration of sensitive task data.

Alon Barad
Alon Barad
5 views•5 min read
•about 4 hours ago•GHSA-PJR3-86V4-5P7W
5.4

GHSA-PJR3-86V4-5P7W: Broken Access Control via MAX Aggregation in Vikunja Subtree Permissions

Vikunja v2.6.0 contains a permission inheritance regression in pkg/models/project_access.go where explicit down-restrictions on sub-projects are overridden by higher parent project permissions due to MAX aggregation across project tree nodes.

Alon Barad
Alon Barad
5 views•6 min read
•about 5 hours ago•GHSA-FMMF-XQ98-G327
5.3

GHSA-fmmf-xq98-g327: Write-Level Project Members Can Delete Admin-Tier Link Shares in Vikunja

An authorization bypass vulnerability in Vikunja's link share deletion handlers allows project members with Write privileges to delete Admin-tier link shares. The handler passes an unpopulated struct to the authorization check, causing the permission evaluation to fall back to default Write permissions instead of requiring Admin privileges.

Alon Barad
Alon Barad
8 views•5 min read
•about 6 hours ago•GHSA-M687-P538-R5HP
7.2

GHSA-m687-p538-r5hp: Permissive Localhost CORS Policy Leads to Account Takeover in Vikunja

Vikunja versions 2.2.0 through 2.6.0 contain a Cross-Origin Resource Sharing (CORS) misconfiguration flaw in `code.vikunja.io/api`. Default configurations permit wildcard origins for localhost (`http://127.0.0.1:*` and `http://localhost:*`) with credentialed requests (`Access-Control-Allow-Credentials: true`). Because configuring a public service URL appends to this default list rather than overriding it, production environments inadvertently trust all local origins. A local page or application on a user's machine can execute a credentialed cross-origin request to the token refresh endpoint, extract the returned JWT access token, and achieve complete account takeover.

Alon Barad
Alon Barad
8 views•5 min read