CVE-2026-34584

CVE-2026-34584

Area
Web / AppSec
Credit
Merged Contribution
Credit Note
Amemoyoi가 bulk subscriber 변경과 admin JSON export 두 variant에 기여 · 여러 연구자의 hotpath 보고가 하나의 CVE로 통합됨
CVSS
5.4
CVSS Source
CNA / Vendor
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N
CWE
CWE-639
Impact
Authorization Bypass
Key Finding
list 권한이 누락된 여러 경로 가운데 bulk subscriber 변경과 관리자 JSON export 두 variant를 확인했습니다.
Published
Apr 2, 2026
Score Note
Severity
Medium
Status
Public
Target
listmonk · Subscriber management
하나로 통합 공개된 listmonk 접근 제어 이슈 중, 내가 확인한 두 경로는 bulk subscriber 변경과 관리자 JSON export였습니다. 기여 범위와 다른 보고자의 범위를 분리해 정리했습니다.
Taegu Ha · listmonk · CWE-639 · CVSS 5.4
2026년 4월 2일 공개 · listmonk 6.1.0에서 수정 · 여러 보고가 하나의 CVE로 통합됨 · 공식 기록

한눈에 보기

🔎
listmonk의 제한된 multi-user 환경에서 UI가 숨긴 subscriber ID를 bulk handler나 JSON export에 직접 넣으면, caller가 허용된 list scope를 다시 확인하지 않아 다른 list의 subscriber를 수정하거나 읽을 수 있었습니다.
구분
확인 내용
프로젝트·컴포넌트
listmonk subscriber bulk action·JSON export
공격 입력
권한 밖 list에 속한 subscriber ID
필요 조건
접근 list가 제한된 authenticated multi-user account
취약 지점
ID lookup 뒤 caller-authorized list scope를 적용하지 않는 object-level authorization
검증 결과
variant 1: modify·reassign·blocklist, variant 2: 다른 list subscriber export
영향
subscriber data read·write authorization bypass
수정 원칙
모든 조회와 action을 caller가 허용된 list 집합에 scope

공격 흐름

검증 결론: 이 포트폴리오에서 직접 확인한 범위는 bulk write와 JSON export의 두 variant이며, 통합 CVE의 다른 주장까지 확장하지 않았습니다.

취약점 개요

listmonk의 multi-user 환경에서는 사용자가 접근할 수 있는 list가 제한될 수 있습니다. subscriber 자체를 조회하거나 수정하는 endpoint는 subscriber ID가 존재하는지만 보는 것이 아니라, 그 subscriber가 속한 list에 호출자가 권한을 갖는지 확인해야 합니다.
공개 CVE는 CSV import 등 여러 접근 제어 경로를 통합한 건입니다. 이 글에서는 내가 직접 확인한 두 변형만 다룹니다. 첫째는 bulk UI에서 권한 없는 list의 subscriber를 수정·재배정·blocklist 처리하는 경로, 둘째는 admin subscriber JSON export로 해당 subscriber 데이터를 가져오는 경로입니다.
내가 확인한 읽기 경로
admin subscriber JSON export
내가 확인한 쓰기 경로
bulk modify·reassign·blocklist
필요 조건
권한이 분리된 untrusted multi-user 환경
공개 범위
다른 보고자의 변형과 함께 하나의 CVE로 통합

조사 대상

role 이름이나 admin 화면 접근만으로 권한을 추론하지 않고, 각 handler가 대상 subscriber의 list membership을 authorization query에 포함하는지 확인했습니다. bulk endpoint는 UI에서 숨겨진 대상을 ID로 직접 지정할 수 있는지 따로 봤습니다.
공개 advisory의 범위가 넓기 때문에 어떤 결과가 내 조사에서 나온 것인지 먼저 분리했습니다. CSV import를 포함한 통합 CVE 전체를 단독 발견으로 쓰지 않고, 보존된 두 variant의 흐름과 증거만 설명합니다.
접근할 수 없는 list의 subscriber ID를 직접 지정했을 때 읽기와 bulk 변경 handler가 list 권한을 다시 확인하는가?

원인 분석

bulk UI handler는 요청에 포함된 subscriber ID와 action을 처리했지만 대상 subscriber가 호출자에게 허용된 list 범위에 있는지 일관되게 제한하지 않았습니다. 화면 목록에는 나타나지 않는 대상을 직접 ID로 보내 변경 결과를 확인했습니다.
JSON export 경로도 subscriber ID로 객체를 찾은 뒤 list permission을 같은 기준으로 적용하지 않았습니다. 읽기와 쓰기가 서로 다른 handler였지만 공통 원인은 object lookup 이후 상위 list authorization의 누락이었습니다.
두 변형에서 공통으로 확인한 처리 순서
request subscriber IDs │ ├─ bulk action → modify / reassign / blocklist └─ JSON export → subscriber data response missing step: target subscriber ∈ caller-authorized lists ?
입력에서 영향까지의 경로
  1. 제한된 사용자가 자신의 list 관리 화면에 로그인합니다.
  1. 다른 list의 subscriber ID를 요청에 직접 넣습니다.
  1. handler가 ID로 subscriber를 조회합니다.
  1. 상위 list 권한 확인 없이 action 또는 export를 수행합니다.
  1. 권한 없는 subscriber 데이터나 상태가 영향을 받습니다.

재현 및 검증

서로 다른 list 권한을 가진 두 사용자를 만들고 각 list에 식별 가능한 subscriber를 넣었습니다. 제한 사용자의 UI에 대상 subscriber가 보이지 않는 것을 먼저 확인했습니다.
그 다음 browser가 보내는 bulk 요청의 subscriber ID만 권한 없는 대상 ID로 바꾸고 수정, list 재배정, blocklist action을 각각 확인했습니다. 별도로 admin JSON export URL에 같은 대상 ID를 넣어 응답에 subscriber 데이터가 포함되는지 확인했습니다.
# 제한 사용자 session POST bulk action with unauthorized subscriber_id GET admin subscriber JSON export for the same id
검사
입력·조건
관찰
의미
목록 대조군
제한 사용자 UI
대상 subscriber 미표시
list 권한 분리 확인
Bulk 변경
권한 없는 subscriber ID
상태·list 변경 반영
쓰기 경로 권한 누락
JSON export
같은 subscriber ID
subscriber 데이터 반환
읽기 경로 권한 누락
정상 대상
허용 list의 subscriber
동일 action 정상
기능 자체와 권한 오류 분리
내 조사에서 확인한 두 variant
authorized list A: subscriber 101 unauthorized list B: subscriber 202 restricted user UI -> subscriber 202 absent bulk request(id=202) -> modification persisted JSON export(id=202) -> subscriber 202 data returned

판단 변화

UI 숨김

처음에는 UI에서 다른 list의 subscriber가 보이지 않아 권한이 적용된 것으로 보였습니다. 하지만 UI filtering과 mutation authorization은 별개입니다. request ID를 직접 바꿔 server-side check를 확인했습니다.

단일 endpoint

bulk action 하나만의 실수로 볼 수 있었지만 JSON export에서 같은 경계가 반복됐습니다. 특정 route bug에서 object lookup 뒤 list scope가 빠지는 공통 패턴으로 판단을 확장했습니다.

기여 범위

최종 advisory는 여러 연구자의 report를 하나로 통합했습니다. 따라서 CVE 제목에 포함된 CSV import 등 내가 직접 재현하지 않은 변형은 내 발견으로 서술하지 않았습니다. 이 구분을 글 처음과 결과에 모두 남겼습니다.

영향과 수정

권한이 분리된 multi-user 환경에서 제한 사용자가 다른 list의 subscriber 정보를 읽거나 bulk action으로 상태와 소속을 바꿀 수 있었습니다. 단일 사용자 설치나 모든 사용자가 신뢰되는 운영에서는 전제가 달라집니다.

확인한 범위

  • 권한 없는 subscriber의 bulk 변경
  • 권한 없는 subscriber JSON export
  • UI visibility와 server authorization의 차이

제외한 범위

  • 통합 CVE의 모든 변형을 단독 발견했다는 주장
  • 비인증 접근
  • single-user 환경의 동일 영향

수정

6.1.0에서는 subscriber read와 mutation query에 호출자가 접근 가능한 list scope를 일관되게 적용했습니다. bulk 요청도 각 대상 ID를 처리하기 전에 동일한 object-level authorization을 거쳐야 합니다.

분석 기준과 증거 보존

항목
최종 감사 결과
소스 기준
listmonk checkout 171a597ff2f20e29dad9894418a4934f9ed30a58
원본 검증
제한 계정에서 권한 밖 subscriber ID를 bulk handler와 JSON export에 전달한 두 variant를 확인하고 안전한 관찰 기록으로 추출
GitHub 보존 상태
Public 저장소 main의 감사 commit c04cacf; evidence 4개와 root manifest.json에 size·SHA-256 고정
무결성
사례별 SHA256SUMS 검증 통과, root manifest의 모든 file hash와 실제 파일 일치, README 상대 링크 확인 완료
보존 경계·제약
raw session에는 secret·credential이 있어 의도적으로 제외. 확인하지 않은 HTTP path나 payload는 새로 만들지 않음
감사 완료
2026-08-23 · Docker/로컬 원본 대조 후 GitHub push 완료

관련 파일

2026-08-23 최종 감사

공개 advisory·CVE 레코드에 더해, 개인 정보와 비밀값을 제거한 sanitized-reproduction-observations.md를 보존했습니다. 이 파일은 직접 확인한 bulk·JSON export 사실만 기록하며 raw session을 대체하지 않습니다.

느낀 점

하나의 CVE가 반드시 한 사람이 한 경로에서 발견한 한 버그를 뜻하지 않는다는 점을 실무적으로 배웠습니다. 결과를 크게 보이게 만드는 것보다 내 contribution의 경계를 정확히 적는 편이 기술 설명과 신뢰에 모두 도움이 됐습니다.
bulk 기능은 한 번의 권한 누락이 많은 객체에 적용되므로 UI에 보이는 목록보다 request payload의 각 ID가 어디에서 scope되는지를 봐야 했습니다. 이후 관리 기능에서는 list, export, bulk를 하나의 묶음으로 점검하게 됐습니다.