Mailpit is Vulnerable to Server-Side Request Forgery (SSRF) via Link Check API
Date: 2026-02
Affected: go/github.com/axllent/mailpit
Attack vector: ssrf
Category: vulnerability-disclosure
Severity: Medium
CVE: CVE-2026-27808
CWE: CWE-918
CVSS: 5.8 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N)

### Summary The Link Check API (/api/v1/message/{ID}/link-check) is vulnerable to Server-Side Request Forgery (SSRF). The server performs HTTP HEAD requests to every URL found in an email without validating target hosts or filtering private/internal IP addresses. The response returns status codes and status text per link, making this a non-blind SSRF. In the default configuration (no authentication on SMTP or API), this is fully exploitable remotely with zero user interaction. This is the same class of vulnerability that was fixed in the HTML Check API (CVE-2026-23845 / GHSA-6jxm-fv7w-rw5j) and the screenshot proxy (CVE-2026-21859 / GHSA-8v65-47jx-7mfr), but the Link Check code path was not included in either fix. ### Details The doHead() function in https://github.com/axllent/mailpit/blob/v1.29.0/internal/linkcheck/status.go#L59-L98 creates a plain http.Transport{} and http.Client with no DialContext hook or IP validation: ``` func doHead(link string, followRedirects bool) (int, error) { timeout := time.Duration(10 * time.Second) tr := &http.Transport{} // ... client := http.Client{ Timeout: timeout, Transport: tr, // ... } req, err := http.NewRequest("HEAD", link, nil) // ... res, err := client.Do(req) // No IP validation — requests any URL return res.StatusCode, nil } ``` The call chain is: 1. GET /api/v1/message/{ID}/link-check hits LinkCheck() in https://github.com/axlle


Mitigations:

Architectural layers (MAESTRO):