
listmonk의 비밀번호 재설정 및 비밀번호 변경 후 세션 지속성
listmonk의 비밀번호 재설정 및 변경 후 세션 유지
저는 listmonk라는 오픈소스 뉴스레터 및 메일링 리스트 관리자를 검토하면서 이 문제를 발견했습니다. 간단한 보안 질문 하나를 염두에 두고 있었죠.
사용자가 비밀번호를 변경하거나 재설정하면, 애플리케이션이 실제로 이미 발급된 세션을 종료합니까?
이 경우, 그렇지 않았습니다.
이전에 발급된 인증 세션은 다음 두 가지 경우 모두에서 유효하게 남아 있었습니다:
즉, 도난당한 세션 쿠키가 사용자가 계정을 복구하기 위해 의존하는 정확한 보안 이벤트를 살아남을 수 있었습니다.
이 문제는 접수되었고 CVE-2026-34828이 할당되었습니다.
프로젝트: GitHub의 listmonk
CVE: CVE-2026-34828
이는 Docker 풀이 500만 회 이상인 널리 채택된 프로젝트 listmonk에 영향을 미쳤습니다.
도난당한 인증 세션 → 피해자가 비밀번호 재설정 또는 변경 → 이전 세션 유효 유지 → 공격자가 자격 증명 복구 후에도 계정 접근 유지
listmonk는 자체 호스팅 메일링 리스트 및 뉴스레터 관리자입니다.
다음을 제공합니다:
따라서 세션 모델은 실제 보안 경계입니다.
여기서 중요한 질문은 listmonk가 비밀번호 재설정을 지원하는지 여부가 아니었습니다.
진짜 질문은 이거였습니다:
세션이 이미 도난당한 경우, 비밀번호 재설정 또는 변경이 실제로 공격자의 지속성을 무효화하는가?
이 경우, 그렇지 않았습니다.
많은 보안 검토가 로그인 우회 및 명백한 권한 상승에만 너무 집중하는 경우가 많습니다.
그러면 중요한 취약점 클래스를 놓치게 됩니다:
복구 실패
사용자가 비밀번호를 변경하거나 재설정하면, 그 행동은 의미가 있어야 합니다.
이전 자격 증명 및 이전 인증 상태에 대한 신뢰를 줄여야 합니다.
공격자에게 이미 유효한 세션이 있고 그 세션이 복구 이벤트에서 살아남는다면, 피해자는 실제로 계정을 완전히 복구한 것이 아닙니다.
이것이 여기서의 문제였습니다.
이는 로그인 검증 버그가 아니었습니다.
암호화 문제도 아니었습니다.
비밀번호 해싱 실패도 아니었습니다.
세션 수명 주기 실패였습니다:
그것만으로도 실제 취약점이 되기에 충분합니다.
저는 무작위로 엔드포인트를 때리며 하나가 넘어지길 바라는 식으로 listmonk에 접근하지 않았습니다.
더 강력한 방법은 먼저 가장 가치가 높은 신뢰 경계를 식별하는 것이었습니다.
인증이 중요한 소프트웨어의 경우, 테스트하기 가장 좋은 경계 중 하나는 다음과 같습니다:
보안에 민감한 계정 변경 사항이 이전에 신뢰된 세션을 무효화합니까?
이 질문은 보통 다음과 같은 경우에 흥미로운 결과를 낳습니다:
listmonk에서는 처음 두 가지에서 가장 강력한 신호가 나왔습니다.
그곳에서 문제가 명확해졌습니다.
버그는 비밀번호 변경이 실패한 것이 아니었습니다.
버그는 세션이 비밀번호보다 더 오래 살아남은 것입니다.
소스 검토 결과, 비밀번호 재설정 흐름은:
이전 세션에 대한 명시적인 무효화는 없었습니다.
동일한 패턴이 인증된 비밀번호 변경 흐름에서도 나타났습니다:
그러한 동작이 실제 결과와 정확히 일치했습니다.
제가 검토한 관련 코드 영역은 다음과 같습니다:
cmd/auth.go - 비밀번호 찾기/재설정 동작cmd/users.go - 인증된 프로필 업데이트internal/core/users.go - 비밀번호 업데이트 처리세션 도용은 실제 공격 조건이기 때문입니다.
공격자가 어떤 방식으로든 유효한 인증 세션 쿠키를 얻으면 (예:
피해자는 비밀번호를 변경하거나 재설정하여 공격자의 지속성을 종료할 수 있어야 합니다.
여기서는 그럴 수 없었습니다.
공격 체인은 간단했습니다:
그것이 전체 취약점입니다.
중요한 차이는 복구 후 지속성입니다.
많은 애플리케이션이 비밀번호 변경을 순전히 자격 증명 수준의 이벤트로 취급합니다.
그것만으로는 충분하지 않습니다.
진짜 질문은 이것이 아닙니다:
"비밀번호 값이 저장소에서 변경되었습니까?"
진짜 질문은 이것입니다:
"이전 세션에 첨부된 신뢰 관계가 무효화되었습니까?"
listmonk에서는 그렇지 않았습니다.
그것은 평범한 계정 유지 관리가 불완전한 보안 복구로 변하는 지점입니다.
이것이 다음 사이의 차이입니다:
저는 두 가지 별도 흐름에서 이 문제를 검증했습니다.
먼저 일반 테스트 사용자를 만들고 로그인하여 인증된 세션 쿠키를 저장했습니다.
그런 다음 비밀번호 찾기 흐름을 트리거하고 재설정 링크를 캡처한 후 비밀번호를 재설정했습니다.
재설정 후:
대표적인 검증 요청은 다음과 같았습니다:
GET /api/profile HTTP/1.1
Host: 127.0.0.1:9000
Cookie: session=<old_pre_reset_session>
그리고 서버는 여전히 다음을 반환했습니다:
HTTP/1.1 200 OK
Content-Type: application/json
인증된 프로필과 함께.
이로써 핵심 주장이 확립되었습니다:
그런 다음 동일한 종류의 버그를 인증된 비밀번호 변경 흐름에서 검증했습니다.
동일한 사용자로 두 번 로그인하고 두 개의 유효한 인증 세션을 저장했습니다:
세션 A를 사용하여 프로필 업데이트 엔드포인트를 통해 비밀번호를 변경했습니다.
예시 요청:
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"
}
그 후:
세션 B를 사용한 후속 요청이 여전히 /api/profile에서 인증된 데이터를 반환했습니다.
이는 문제가 비밀번호 찾기/재설정 경로에만 국한되지 않음을 증명했습니다.
일반적인 인증된 비밀번호 변경에도 영향을 미쳤습니다.
하나의 재현만으로도 문제를 보여주기에 충분했을 것입니다.
하지만 두 흐름을 모두 검증하는 것은 두 가지 이유로 중요했습니다.
이는 버그가 하나의 특수 복구 경로에만 국한되지 않음을 보여주었습니다.
동일한 보안 속성이 다음 두 경우에서 실패했습니다:
이를 우연한 비즈니스 로직으로 치부하기 어렵게 만들었습니다.
이는 분명히 더 광범위한 세션 관리 취약점이었습니다:
이로 인해 이슈의 보안적 비중이 훨씬 더 강력해졌습니다.
또한 TOTP가 활성화된 계정에서 재설정 흐름을 테스트했습니다. 비밀번호 재설정이 조용히 2FA 기대치를 약화시키거나 우회하지는 않는지 확인하고 싶었기 때문입니다.
제가 확인한 것은:
이는 유용한 경계 확인이었습니다.
문제를 올바르게 좁혀주었습니다.
취약점은 다음이 아니었습니다:
진짜 문제는 여전히 동일했습니다:
이는 더 깔끔하고 방어하기 쉬운 발견입니다.
이 이슈는 합리적으로 높음(High) 으로 분류되었습니다.
주요 영향은 계정 보안 복구 조치 후 지속적인 무단 접근입니다.
권고 분류는 다음과 같았습니다:
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N이는 타당합니다.
주장은 공격자가 아무 것도 없이 자격 증명 없이 로그인할 수 있다는 것이 아닙니다. 주장은 공격자가 유효한 인증 세션을 얻은 후, 피해자가 계정을 복구하기 위해 수행해야 하는 정확한 보안 조치(비밀번호 재설정 및 비밀번호 변경)를 수행해도 해당 접근을 완전히 종료할 수 없다는 것입니다.
이는 실제적이고 방어 가능한 세션 관리 취약점입니다.
어떤 사람들은 세션 도용이 이미 "게임 오버"라고 가정하기 때문에 세션 지속성 버그를 과소평가합니다.
그것은 너무 단순합니다.
진짜 질문은 피해자가 문제를 알아차리고 조치를 취한 후에 무슨 일이 일어나는지입니다.
만약:
계정 복구는 불완전합니다.
이는 단순히 어색한 동작이 아닙니다. 복구 모델의 보안 실패입니다.
특히 관리자용 플랫폼에서는 기밀성 영향이 큰 의미 있는 문제입니다.
메인테이너가 다음 커밋에서 문제를 수정했습니다:
db82035
핵심 수정 방향은 이 버그에 정확히 필요한 것입니다:
이는 올바른 해결책입니다. 실패한 실제 보안 속성을 대상으로 하기 때문입니다:
자격 증명이 변경되면 이전 신뢰는 사라져야 합니다
이러한 종류의 버그에 대한 좋은 수정은 비밀번호 검증을 변경하는 것이 아닙니다. 계정에 연결된 이전에 활성화된 세션 상태를 무효화하는 것입니다.
그것이 실제 복구를 복원하는 부분입니다.
이 이슈는 GitHub의 보안 보고 흐름을 통해 비공개로 보고되었습니다.
메인테이너는:
CVE-2026-34828
권고 처리 과정에서 범위에 관한 한 가지 사항이 있었습니다.
원래 보고서에는 다음이 모두 포함되었습니다:
GitHub는 처음에 이를 CVE 할당 목적상 독립적으로 수정 가능한 이슈로 취급했습니다. 이는 근본적인 취약점이 개념적으로 유사하더라도 권고 범위가 중요하다는 유용한 알림입니다.
최종 결과는 CVE-2026-34828이었습니다.
핵심 교훈은 간단합니다:
이전 인증 신뢰가 여전히 살아 있다면 자격 증명을 변경하는 것만으로는 충분하지 않습니다.
많은 개발자는 다음 측면에서 생각합니다:
이런 것들은 중요합니다.
하지만 실제 보안 경계는 더 넓습니다:
고위험 계정 이벤트가 발생할 때, 이전에 신뢰되었던 어떤 상태가 더 이상 신뢰되지 않아야 합니까?
이 경우, 답변은 다음과 같아야 했습니다:
그리고 listmonk는 그렇게 하지 않았습니다.
이것이 진짜 핵심 교훈입니다.
이 취약점은 화려한 페이로드나 영리한 파서 트릭에 관한 것이 아니었습니다.
올바른 신뢰 경계 질문을 하는 것이었습니다.
listmonk에서 비밀번호가 변경되었습니다.
복구 작업이 완료되었습니다.
하지만 공격자의 이전 세션은 여전히 살아 있었습니다.
그것이 이 이슈가 CVE-2026-34828이 된 이유입니다.
