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



CVE-2026-34828
7.1

CVE-2026-34828: Insufficient Session Expiration in listmonk

Amit Schendel
Amit Schendel
Senior Security Researcher

Apr 2, 2026·7 min read·0 visits

PoC Available

Executive Summary (TL;DR)

Listmonk prior to version 6.1.0 does not invalidate active session tokens upon password changes or resets. Attackers with stolen session cookies can maintain persistent authenticated access despite victim credential rotation.

Listmonk versions 4.1.0 through 6.0.x contain an Insufficient Session Expiration vulnerability (CWE-613) within the application's authentication lifecycle handlers. The software fails to revoke existing authenticated sessions when a user undergoes a password reset or performs an intentional password change. This oversight enables an attacker who has acquired a valid session cookie to maintain unauthorized, persistent access to the compromised account, successfully bypassing the primary defense mechanism of credential rotation.

Vulnerability Overview

Listmonk is an open-source, self-hosted newsletter and mailing list manager written in Go and backed by a PostgreSQL database. The software relies on server-side session management to handle administrator and user authentication. Sessions are generated upon successful login, stored persistently in the database, and tracked via an HTTP cookie delivered to the client.

CVE-2026-34828 identifies a structural flaw in how listmonk manages the lifecycle of these sessions during critical security events. Specifically, the application exhibits an Insufficient Session Expiration vulnerability (CWE-613). When an account password is changed or reset, the application updates the authentication credentials but fails to terminate preexisting sessions associated with that user.

This architecture fundamentally decouples the session state from the credential state. Consequently, the primary remediation strategy for suspected account compromise—rotating the account password—fails to neutralize the threat. An attacker who has previously compromised an active session token retains access until the original token reaches its natural Time-To-Live (TTL) expiration.

The attack surface requires the threat actor to have preemptively obtained a valid session cookie. This is typically achieved through secondary attack vectors, such as Cross-Site Scripting (XSS), physical access to an unlocked terminal, endpoint malware, or network traffic interception on insecure connections.

Root Cause Analysis

The root cause of CVE-2026-34828 resides in the application's user profile update and password reset routines. The application tracks user sessions via a dedicated sessions table in the PostgreSQL database. The authentication middleware validates incoming requests by extracting the session ID from the cookie, verifying its cryptographic signature, checking its TTL, and confirming its presence in the database.

During a password reset flow, orchestrated by the doResetPassword handler in cmd/auth.go, the application successfully receives the valid reset token and processes the new password. The backend then issues a SQL UPDATE statement targeting the users table, overwriting the existing password_hash with the newly generated bcrypt hash.

However, this routine lacks a corresponding cleanup operation against the sessions table. The internal/core/users.go library, which abstracts the database interactions, did not implement any logic to invalidate or purge session records tied to the affected user ID.

Because the session validation middleware strictly evaluates the token's validity against the sessions table without cross-referencing a password version identifier or checking a last_password_change timestamp, the preexisting session tokens remain entirely valid. The application logic assumes session validity based solely on the token's existence, ignoring state changes in the underlying credential store.

Code Analysis and Patch Verification

The vulnerability was resolved in commit db82035d619348949512dafdaf60c86037cafc9e. The fix introduces a unified mechanism to purge active sessions from the database when credential-altering events occur. The core addition is a new parameterized SQL query in queries/users.sql.

-- Pre-patch: No session deletion query existed for user updates.
-- Post-patch: Added to queries/users.sql
-- name: delete-user-sessions
DELETE FROM sessions WHERE data->>'user_id' = $1 AND ($2 = '' OR id != $2);

This query targets the JSONB data column in the sessions table to match the specific user ID. It conditionally spares the currently active session if an ID is provided in parameter $2, preventing the user initiating the password change from being unexpectedly logged out of their current device.

The Go backend was updated to utilize this query. In cmd/users.go, the handler responsible for processing user profile updates was modified to invoke the new DeleteUserSessions wrapper function.

// Modified cmd/users.go - UpdateUserProfile handler
func (a *App) UpdateUserProfile(c echo.Context) error {
    // ... (input validation and user update logic)
    
    // Post-patch addition: Revoke all other sessions upon password change
    if req.Password != "" {
        currentSession := auth.GetSessionID(c)
        if err := a.core.DeleteUserSessions(user.ID, currentSession); err != nil {
            a.log.Errorf("failed to clear sessions: %v", err)
        }
    }
    return c.JSON(http.StatusOK, true)
}

A similar implementation was added to cmd/auth.go for the unauthenticated password reset flow, where parameter $2 is explicitly left empty ("") to indiscriminately terminate all sessions for that user ID.

Exploitation Methodology

Exploitation of CVE-2026-34828 requires an attacker to possess a stolen session cookie. The exploit lifecycle begins when the threat actor compromises the victim's session, typically through client-side vulnerabilities, local machine access, or session hijacking techniques.

Once the victim detects suspicious activity, the standard incident response protocol dictates changing the account password. The victim authenticates to listmonk and navigates to the Profile settings to execute a password change, or utilizes the "Forgot Password" feature to reset the credentials via email.

> [!NOTE] > The vulnerability execution occurs precisely when the server processes the password change. The application commits the new password hash to the database but leaves the attacker's active session undisturbed in the session store.

The attacker continues to interface with the listmonk API by injecting the originally stolen session cookie into subsequent HTTP requests. The server processes the session identifier, finds a matching and unexpired record in the database, and authorizes the transaction.

GET /api/profile HTTP/1.1
Host: listmonk.example.local
Cookie: session=a8b3c9d2...
 
HTTP/1.1 200 OK
Content-Type: application/json
{
    "id": 1,
    "username": "admin",
    "role": "super-admin"
}

The persistence is maintained until the stolen session reaches its absolute expiration time, granting the attacker uninterrupted administrative or user-level access to the mailing list infrastructure.

Impact Assessment

The exploitation of this vulnerability results in persistent, unauthorized access to the listmonk instance. The severity is highly dependent on the privileges associated with the compromised session. If the session belongs to a super-admin, the threat actor retains complete control over the application, including the ability to exfiltrate subscriber databases, modify mailing lists, alter application configurations, and distribute malicious campaigns.

The CVSS v3.1 vector evaluates to 7.1 (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N). The network attack vector (AV:N) and low attack complexity (AC:L) reflect the ease of replaying a valid cookie over the network. The privileges required (PR:L) denote that the attacker acts within the context of the compromised user account. Confidentiality impact (C:H) is high due to the exposure of personal subscriber data.

This vulnerability fundamentally degrades the integrity of the application's incident response mechanisms. System administrators and users operating under the assumption that a password reset secures a compromised account remain unknowingly exposed to continuous exploitation.

Remediation and Mitigation

The definitive remediation for CVE-2026-34828 is upgrading the listmonk application to version 6.1.0 or later. This release incorporates the DeleteUserSessions logic, ensuring that session lifecycles are correctly tied to credential validity.

For environments where immediate patching is administratively or technically unfeasible, a manual mitigation strategy must be employed. Administrators can enforce a global session invalidation by directly interacting with the PostgreSQL database. Executing DELETE FROM sessions; will immediately terminate all active sessions, forcing all users to re-authenticate using their current credentials.

To detect potential historical exploitation, security engineers should audit the application logs and database records. Evidence of exploitation may present as multiple distinct IP addresses utilizing the same user ID within the sessions table immediately following a password reset event recorded in the system audit logs.

Network defenders can additionally implement Web Application Firewall (WAF) rules designed to monitor for session anomalies. Detecting a single session cookie generating requests from geographically disparate locations within an impossibly short timeframe (impossible travel) serves as a robust indicator of session theft and concurrent usage.

Official Patches

knadhSource code patch introducing DeleteUserSessions mechanism

Fix Analysis (1)

Technical Appendix

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

Affected Systems

listmonk standalone Go binarylistmonk Docker container

Affected Versions Detail

Product
Affected Versions
Fixed Version
listmonk
knadh
>= 4.1.0, < 6.1.06.1.0
AttributeDetail
CWE IDCWE-613
Attack VectorNetwork
CVSS Score7.1 (High)
Exploit StatusProof of Concept (PoC) available
KEV StatusNot Listed
ImpactPersistent Unauthorized Access

MITRE ATT&CK Mapping

T1539Steal Session Cookie
Credential Access
T1550.004Use Alternate Authentication Material: Web Session Cookie
Defense Evasion
T1098Account Manipulation
Persistence
CWE-613
Insufficient Session Expiration

The system does not adequately terminate a user session upon critical account lifecycle events, allowing an attacker to maintain persistent unauthorized access.

Known Exploits & Detection

Local AnalysisHTTP request snippet demonstrating session reuse against /api/profile endpoint post-password reset.

Vulnerability Timeline

Fix committed to listmonk master branch
2026-03-23
GitHub Advisory GHSA-h5j9-cvrw-v5qh published
2026-04-01
CVE-2026-34828 assigned and published
2026-04-02
listmonk version 6.1.0 released with the fix
2026-04-02

References & Sources

  • [1]GitHub Security Advisory: GHSA-h5j9-cvrw-v5qh
  • [2]Fix Commit: db82035

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.