
Persistenza della sessione di listmonk dopo il reset della password e il cambio della password
Persistenza delle sessioni di listmonk dopo il reset e la modifica della password
Ho trovato questo problema mentre esaminavo listmonk, un gestore open-source di newsletter e mailing list, con una semplice domanda di sicurezza in mente:
Quando un utente modifica o resetta una password, l'applicazione termina effettivamente le sessioni già emesse?
In questo caso, la risposta è stata no.
Le sessioni autenticate emesse in precedenza sono rimaste valide dopo entrambe le azioni:
Ciò significava che un cookie di sessione rubato poteva sopravvivere esattamente agli eventi di sicurezza su cui gli utenti fanno affidamento per recuperare il proprio account.
Il problema è stato accettato e gli è stata assegnata la CVE-2026-34828.
Progetto: listmonk su GitHub
CVE: CVE-2026-34828
Il problema ha interessato listmonk, un progetto ampiamente adottato con 5M+ pull Docker.
stolen authenticated session → victim resets or changes password → old session remains valid → attacker retains account access after credential recovery
listmonk è un gestore self-hosted di mailing list e newsletter.
Offre:
Ciò significa che il suo modello di sessione è un vero confine di sicurezza.
La domanda importante qui non era se listmonk supporta il reset della password.
La vera domanda era:
Il reset o la modifica della password revocano effettivamente la persistenza dell'attaccante se una sessione è già stata rubata?
In questo caso, non lo faceva.
Molte revisioni di sicurezza si concentrano in modo troppo ristretto sui bypass di login e sull'escalation dei privilegi più ovvia.
Questo fa perdere di vista un'importante classe di debolezze:
fallimenti del recupero
Se un utente modifica o resetta una password, quell'azione dovrebbe avere un significato reale.
Dovrebbe ridurre la fiducia nelle credenziali precedenti e nel vecchio stato di autenticazione.
Se un attaccante possiede già una sessione valida e quella sessione sopravvive all'evento di recupero, allora la vittima non ha realmente recuperato completamente l'account.
Questo era il problema qui.
Non era un bug di validazione del login. Non era un problema crittografico. Non era un errore nell'hash delle password.
Era un fallimento del ciclo di vita delle sessioni:
Questo è sufficiente a creare una vulnerabilità reale.
Non ho affrontato listmonk colpendo endpoint a caso e sperando che qualcuno cedesse.
Il percorso più solido era identificare prima il confine di fiducia di maggior valore.
Per software fortemente incentrati sull'autenticazione, uno dei migliori confini da testare è questo:
Le modifiche all'account sensibili dal punto di vista della sicurezza revocano le sessioni precedentemente considerate affidabili?
Quella domanda di solito diventa interessante in relazione a:
In listmonk, il segnale più forte è arrivato dai primi due.
È lì che il problema è diventato evidente.
Il bug non era che le modifiche alla password fallivano.
Il bug era che le sessioni sopravvivevano a esse.
Dalla revisione del codice sorgente, il flusso di reset della password:
ma non c'era alcuna revoca visibile delle sessioni precedenti.
Lo stesso schema appariva nel flusso autenticato di modifica della password:
Questo comportamento corrispondeva esattamente ai risultati reali.
Le aree di codice rilevanti che ho esaminato sono state:
cmd/auth.go per il comportamento di password dimenticata/resetcmd/users.go per gli aggiornamenti autenticati del profilointernal/core/users.go per la gestione dell'aggiornamento della passwordPerché il furto di sessione è una condizione di attacco reale.
Quando un attaccante ottiene un cookie di sessione autenticata valido con qualsiasi mezzo, ad esempio:
la vittima dovrebbe essere in grado di terminare quella persistenza dell'attaccante modificando o resettando la password.
Qui, non poteva.
La catena di attacco era semplice:
Questa è l'intera vulnerabilità.
La distinzione importante è la persistenza dopo il recupero.
Molte applicazioni trattano la modifica della password come un evento puramente a livello di credenziali. Non è sufficiente.
La vera domanda non è:
“Il valore della password è cambiato nell'archivio?”
La vera domanda è:
“La relazione di fiducia associata alle sessioni precedenti è stata revocata?”
In listmonk, non lo è stata.
Questo trasforma quella che sarebbe potuta essere una normale manutenzione dell'account in un recupero di sicurezza incompleto.
Questa è la differenza tra:
Ho validato il problema in due flussi separati.
Innanzitutto, ho creato un normale utente di test e ho effettuato l'accesso, salvando il cookie di sessione autenticata.
Poi ho attivato il flusso di password dimenticata, catturato il link di reset e resettato la password.
Dopo il reset:
Una richiesta di validazione rappresentativa appariva così:
GET /api/profile HTTP/1.1
Host: 127.0.0.1:9000
Cookie: session=<old_pre_reset_session>
E il server restituiva ancora:
HTTP/1.1 200 OK
Content-Type: application/json
con il profilo autenticato.
Questo ha confermato l'affermazione principale:
Ho poi validato la stessa classe di bug nel flusso autenticato di modifica della password.
Ho effettuato l'accesso due volte come lo stesso utente e ho salvato due sessioni autenticate valide:
Usando la sessione A, ho modificato la password tramite l'endpoint di aggiornamento del profilo.
Richiesta di esempio:
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"
}
Dopo di che:
Una richiesta successiva utilizzando la sessione B restituiva ancora dati autenticati da /api/profile.
Questo ha dimostrato che il problema non era limitato al percorso di password dimenticata/reset.
Riguardava anche le normali modifiche autenticate della password.
Una sola riproduzione sarebbe già stata sufficiente a mostrare un problema.
Ma validare entrambi i flussi era importante per due motivi.
Ha mostrato che il bug non era isolato a un singolo percorso di recupero marginale.
La stessa proprietà di sicurezza falliva in:
Ha reso il problema più difficile da liquidare come logica di business accidentale.
Era chiaramente una debolezza più ampia nella gestione delle sessioni:
Questo ha dato al problema un peso di sicurezza molto maggiore.
Ho anche testato il flusso di reset su un account con TOTP abilitato, perché volevo sapere se il reset della password avrebbe silenziosamente indebolito o bypassato le aspettative del 2FA.
Quello che ho confermato è stato:
È stato un utile controllo del confine.
Ha circoscritto correttamente il problema.
La vulnerabilità non era:
Il vero problema rimaneva:
È un risultato più pulito e più difendibile.
Il problema è stato ragionevolmente classificato come Alto.
L'impatto chiave qui è l'accesso non autorizzato persistente dopo le azioni di recupero della sicurezza dell'account.
La classificazione dell'advisory era:
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:NHa senso.
L'affermazione non è che un attaccante possa accedere senza credenziali dal nulla.
L'affermazione è che, una volta che un attaccante ha ottenuto una sessione autenticata valida, la vittima non può terminare completamente quell'accesso eseguendo esattamente le azioni di sicurezza che dovrebbero recuperare l'account, cioè il reset e la modifica della password.
È una vulnerabilità reale e difendibile nella gestione delle sessioni.
Alcune persone sottovalutano i bug di persistenza delle sessioni perché presumono che il furto di sessione sia già “game over.”
È troppo semplicistico.
La vera domanda è cosa succede dopo che la vittima nota che qualcosa non va e agisce.
Se:
allora il recupero dell'account è incompleto.
Non è solo un comportamento scomodo. È un errore di sicurezza nel modello di recupero.
Soprattutto in una piattaforma orientata agli amministratori, è un problema significativo con un forte impatto sulla riservatezza.
Il maintainer ha corretto il problema nel commit:
db82035
La direzione principale della correzione è esattamente ciò di cui questo bug aveva bisogno:
È la remediation corretta perché colpisce la proprietà di sicurezza reale che è venuta meno:
la fiducia precedente dovrebbe cessare quando le credenziali cambiano
Una buona correzione per questa classe di bug non riguarda la modifica della validazione della password. Riguarda la revoca dello stato di sessione precedentemente attivo associato all'account.
È quella la parte che ripristina il recupero effettivo.
Questo problema è stato segnalato privatamente tramite il flusso di segnalazione di sicurezza di GitHub.
Il maintainer:
CVE-2026-34828
Una cosa emersa durante la gestione dell'advisory è stato l'ambito.
La segnalazione originale includeva entrambi i casi:
GitHub inizialmente le ha trattate come problemi correggibili in modo indipendente ai fini dell'assegnazione della CVE. È un utile promemoria del fatto che l'ambito dell'advisory conta anche quando la debolezza sottostante è concettualmente simile.
Il risultato finale è stato CVE-2026-34828.
La lezione chiave qui è semplice:
cambiare le credenziali non è sufficiente se la vecchia fiducia autenticata è ancora viva.
Molti sviluppatori ragionano in termini di:
Queste cose contano.
Ma il vero confine di sicurezza è più ampio:
quando si verifica un evento ad alto rischio sull'account, quale stato precedentemente considerato affidabile deve cessare di esserlo?
In questo caso, la risposta avrebbe dovuto essere:
E listmonk non lo faceva.
Questo è il vero insegnamento.
Questa vulnerabilità non riguardava payload elaborati o astuti trucchi di parsing.
Riguardava il porsi la giusta domanda sul confine di fiducia.
In listmonk, la password è cambiata.
L'azione di recupero è stata completata.
Ma la vecchia sessione dell'attaccante era ancora viva.
È per questo che è diventata CVE-2026-34828.
