| Reporter | Title | Published | Views | Family All 15 |
|---|---|---|---|---|
| CVE-2026-34828 | 2 Apr 202617:32 | – | attackerkb | |
| CVE-2026-34828 | 1 Apr 202607:08 | – | circl | |
| listmonk 代码问题漏洞 | 2 Apr 202600:00 | – | cnnvd | |
| CVE-2026-34828 | 2 Apr 202617:32 | – | cve | |
| CVE-2026-34828 listmonk: Active sessions remain valid after password reset and password change | 2 Apr 202617:32 | – | cvelist | |
| listmonk's active sessions remain valid after password reset and password change | 1 Apr 202623:48 | – | github | |
| CVE-2026-34828 | 2 Apr 202618:16 | – | nvd | |
| GHSA-H5J9-CVRW-V5QH listmonk's active sessions remain valid after password reset and password change | 1 Apr 202623:48 | – | osv | |
| PT-2026-29816 | 1 Apr 202600:00 | – | ptsecurity | |
| CVE-2026-34828 | 3 Apr 202623:01 | – | redhatcve |
# CVE-2026-34828
listmonk’s Session Persistence After Password Reset and Password Change
## Intro
I found this issue while reviewing **listmonk**, an open-source newsletter and mailing list manager, with a simple security question in mind:
**When a user changes or resets a password, does the application actually terminate already-issued sessions?**
In this case, the answer was no.
Previously issued authenticated sessions remained valid after both:
- **password reset**
- **password change**
That meant a stolen session cookie could survive the exact security events that users rely on to recover their account.
The issue was accepted and assigned **CVE-2026-34828**.
**Project:** [listmonk on GitHub](https://github.com/knadh/listmonk)
**CVE:** CVE-2026-34828
This affected listmonk, a widely adopted project with **5M+** Docker pulls.
<img width="840" height="760" alt="photo0" src="https://github.com/user-attachments/assets/c383873f-c2b1-4868-af6a-b13a4ee5b2ac" />
---
## Attack Chain
`stolen authenticated session → victim resets or changes password → old session remains valid → attacker retains account access after credential recovery`
---
## What listmonk Does
**listmonk** is a self-hosted mailing list and newsletter manager.
It provides:
- admin authentication
- user management
- campaign creation
- subscriber management
- SMTP and operational settings
- browser-based administration
That means its session model is a real security boundary.
The important question here was not whether listmonk supports password reset.
The real question was:
**Does password reset or password change actually revoke attacker persistence if a session has already been stolen?**
In this case, it did not.
---
## Why This Bug Was Worth Looking At
A lot of security reviews focus too narrowly on login bypasses and obvious privilege escalation.
That misses an important class of weaknesses:
**recovery failures**
If a user changes or resets a password, that action is supposed to be meaningful.
It is supposed to reduce trust in older credentials and old authentication state.
If an attacker already has a valid session and that session survives the recovery event, then the victim has not actually recovered the account fully.
That was the issue here.
This was not a login validation bug.
It was not a crypto issue.
It was not a password hashing failure.
It was a **session lifecycle failure**:
- password state changed,
- account recovery occurred,
- but old sessions were still trusted.
That is enough to create a real vulnerability.
---
## The Boundary I Focused On
I did not approach listmonk by randomly hitting endpoints and hoping one would fall over.
The stronger path was to identify the highest-value trust boundary first.
For authentication-heavy software, one of the best boundaries to test is this:
> **Do security-sensitive account changes revoke previously trusted sessions?**
That question usually becomes interesting around:
- password reset
- password change
- 2FA changes
- account recovery flows
In listmonk, the strongest signal came from the first two.
That is where the issue became clear.
---
## Root Cause
The bug was not that password changes failed.
The bug was that **sessions outlived them**.
From source review, the password reset flow:
- generated and validated a one-time reset token,
- updated the password,
- created a new session,
but there was no visible revocation of older sessions.
The same pattern appeared in the authenticated password change flow:
- the password was updated,
- but older already-issued sessions were not invalidated.
That behavior matched the live results exactly.
Relevant code areas I reviewed were:
- `cmd/auth.go` for forgot/reset behavior
- `cmd/users.go` for authenticated profile updates
- `internal/core/users.go` for password update handling
### Why this is exploitable
Because session theft is a real attack condition.
Once an attacker obtains a valid authenticated session cookie through any means such as:
- browser compromise
- malware
- shared workstation access
- XSS in another component
- proxy or debugging leakage
- accidental cookie exposure
the victim should be able to terminate that attacker persistence by changing or resetting the password.
Here, they could not.
The attack chain was straightforward:
- attacker has a valid session cookie
- victim performs password reset or password change
- old password becomes invalid
- new password works
- attacker’s old session still authenticates successfully
That is the whole vulnerability.
---
## What Makes This a Security Issue, Not Just Application Behavior
The important distinction is persistence after recovery.
Plenty of applications treat password change as a purely credential-level event.
That is not enough.
The real question is not:
> “Did the password value change in storage?”
The real question is:
> “Did the trust relationship attached to older sessions get revoked?”
In listmonk, it did not.
That turns what could have been ordinary account maintenance into incomplete security recovery.
That is the difference between:
- ordinary session continuity
- and a real security weakness
---
## PoC
I validated the issue in two separate flows.
### Case 1: Password reset does not revoke existing sessions
First, I created a normal test user and logged in, saving the authenticated session cookie.
Then I triggered the forgot-password flow, captured the reset link, and reset the password.
After reset:
- the **old password no longer worked**
- the **new password worked**
- but the **old pre-reset session cookie still authenticated successfully**
A representative validation request looked like this:
```http
GET /api/profile HTTP/1.1
Host: 127.0.0.1:9000
Cookie: session=<old_pre_reset_session>
```
And the server still returned:
```http
HTTP/1.1 200 OK
Content-Type: application/json
```
with the authenticated profile.
That established the core claim:
- recovery completed,
- credentials changed,
- but existing session trust remained intact.
---
### Case 2: Password change does not revoke parallel active sessions
I then validated the same class of bug in the authenticated password change flow.
I logged in twice as the same user and saved two valid authenticated sessions:
- session A
- session B
Using session A, I changed the password through the profile update endpoint.
Example request:
```http
PUT /api/profile HTTP/1.1
Host: 127.0.0.1:9000
Cookie: session=<session_A>
Content-Type: application/json
{
"name":"victim1",
"email":"[email protected]",
"password":"VictimChanged123"
}
```
After that:
- the **old password no longer worked**
- the **new password worked**
- but **session B remained valid**
A follow-up request using session B still returned authenticated data from `/api/profile`.
That proved the issue was not limited to the forgot/reset path.
It affected normal authenticated password changes too.
---
## Why the Two Reproductions Matter
One reproduction would already have been enough to show a problem.
But validating both flows mattered for two reasons.
### First
It showed the bug was **not isolated to one edge-case recovery path**.
The same security property failed in:
- unauthenticated recovery-driven password reset
- authenticated in-session password change
### Second
It made the issue harder to dismiss as accidental business logic.
This was clearly a broader session management weakness:
- password state changed,
- but existing sessions remained trusted.
That gave the issue much stronger security weight.
---
## TOTP Validation
I also tested the reset flow on a **TOTP-enabled** account because I wanted to know whether password reset would silently weaken or bypass 2FA expectations.
What I confirmed was:
- password reset still succeeded
- TOTP remained enabled
- a fresh login with the new password still redirected to the 2FA step
- so this was **not** a direct 2FA bypass
That was a useful boundary check.
It narrowed the issue correctly.
The vulnerability was not:
- “password reset disables TOTP”
- or “password reset bypasses TOTP”
The real issue remained:
- **already-issued sessions still survived sensitive account security changes**
That is a cleaner and more defensible finding.
---
## Severity and Classification
This issue was reasonably classified as **High**.
The key impact here is persistent unauthorized access after account security recovery actions.
The advisory classification was:
- **CWE-613**: Insufficient Session Expiration
- **CVSS:** `CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N`
That makes sense.
The claim is not that an attacker can log in without credentials from nothing.
The claim is that once an attacker has obtained a valid authenticated session, the victim cannot fully terminate that access by performing the exact security actions that are supposed to recover the account, namely password reset and password change.
That is a real and defensible session-management vulnerability.
---
## Why This Was Still Worth Reporting
Some people underrate session persistence bugs because they assume session theft is already “game over.”
That is too simplistic.
The real question is what happens **after** the victim notices something is wrong and takes action.
If:
- the victim resets the password,
- or changes it manually,
- and the attacker still keeps their stolen session,
then account recovery is incomplete.
That is not just awkward behavior.
That is a security failure in the recovery model.
Especially in an admin-facing platform, that is a meaningful issue with strong confidentiality impact.
---
## Fix Analysis
The maintainer fixed the issue in commit:
```text
db82035
```
The core fix direction is exactly what this bug needed:
- invalidate older sessions after password reset
- invalidate older sessions after password change
That is the correct remediation because it targets the real security property that failed:
**older trust should die when credentials change**
A good fix for this class of bug is not about changing password validation.
It is about revoking previously active session state attached to the account.
That is the part that restores actual recovery.
---
## Disclosure
This issue was reported privately through GitHub’s security reporting flow.
The maintainer:
- reviewed the report
- accepted it as a security issue
- patched the behavior
- and the issue was assigned:
**CVE-2026-34828**
One thing that came up during advisory handling was scope.
The original report included both:
- password reset session persistence
- password change session persistence
GitHub initially treated these as independently fixable issues for CVE assignment purposes.
That is a useful reminder that advisory scope matters even when the underlying weakness is conceptually similar.
The final result was **CVE-2026-34828**.
---
## What This Bug Actually Teaches
The key lesson here is simple:
> changing credentials is not enough if old authenticated trust is still alive.
A lot of developers think in terms of:
- password correctness
- token correctness
- login success
- reset token validity
Those things matter.
But the real security boundary is broader:
**when a high-risk account event happens, what previously trusted state must stop being trusted?**
In this case, the answer should have been:
- old sessions
And listmonk was not doing that.
That is the real takeaway.
---
## Key Points
- session revocation is part of account recovery security
- password reset should not leave previously issued sessions alive
- password change should not leave parallel active sessions alive
- session theft remains meaningful if recovery events do not revoke trust
- testing multiple related flows makes a report stronger
- narrowing away from false leads like 2FA bypass helps keep the finding clean
---
## Final Words
This vulnerability was not about fancy payloads or clever parser tricks.
It was about asking the right trust-boundary question.
In listmonk, the password changed.
The recovery action completed.
But the attacker’s old session still lived.
That is why this became **CVE-2026-34828**.
<img width="840" height="760" alt="photo0" src="https://github.com/user-attachments/assets/687d8854-fc9d-4764-a00b-9518b8fe38e8" />Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation