CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Dashboard
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-27808
5.80.05%

Return to Sender: Turning Mailpit into an Internal Port Scanner

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 26, 2026·6 min read·4 visits

PoC Available

Executive Summary (TL;DR)

Mailpit versions prior to 1.29.2 contain a logic flaw in the 'Link Check' feature. The application fails to validate if a URL points to a local or private IP address before initiating a connection. This allows an attacker to use the Mailpit server as a proxy to scan the internal network (localhost, 10.x.x.x) or access cloud instance metadata (AWS/GCP), simply by sending an email containing a crafted link.

A critical Server-Side Request Forgery (SSRF) vulnerability in Mailpit's Link Check API allows unauthenticated remote attackers to map internal networks and enumerate cloud metadata. By injecting malicious URLs into emails and triggering the application's automated link verification, attackers can force the server to issue HTTP requests to arbitrary destinations, bypassing network segmentation.

The Hook: When 'Helpful' Becomes 'Harmful'

Mailpit is the darling of the developer world. It is the modern, Go-based successor to MailHog—a tool designed to catch emails sent by your application during development so you don't accidentally spam your entire customer database while testing a password reset flow. It sits quietly in your staging environment or on your local machine, capturing SMTP traffic and presenting it in a nice web UI.

One of Mailpit's "helpful" features is the Link Checker. The idea is sound: developers want to know if the links in their marketing emails are broken before they go live. Mailpit parses the email, finds the anchor tags, and offers an API endpoint to verify them. It creates a convenient dashboard showing which links return 200 OK and which return 404 Not Found.

But here is the catch: to check a link, Mailpit has to visit the link. In security terms, the application acts as an HTTP proxy. If you don't strictly control where that proxy is allowed to go, you have just handed an attacker a skeleton key to your internal network. You built a tool to catch mail, but CVE-2026-27808 turns it into a tool to catch shells.

The Flaw: Promiscuous HTTP Clients

The vulnerability resides in internal/linkcheck/status.go. The function doHead() was responsible for performing the connectivity check. In earlier versions of Mailpit, the developers utilized Go's standard http.Client with a default transport configuration.

Go's default HTTP client is famously promiscuous. It does exactly what you ask it to do. If you ask it to fetch http://google.com, it goes to Google. If you ask it to fetch http://localhost:22, it tries to talk HTTP to your SSH daemon. If you ask it to fetch http://169.254.169.254/latest/meta-data/, it happily talks to the AWS metadata service.

The flaw wasn't a buffer overflow or a complex race condition; it was a lack of boundary validation. The code blindly trusted the URLs extracted from the email body. It failed to implement an "allowlist" of permitted schemes or a "blocklist" of private IP ranges (RFC 1918). It essentially treated user input (the email content) as a trusted command to initiate network traffic.

The Code: The Safe Dialer Pattern

To fix an SSRF in Go, you cannot simply verify the URL string. Attackers can use DNS rebinding or alternative IP formats (e.g., 2130706433 for 127.0.0.1) to bypass string matching. The only robust way to fix this is to hook into the Dialer—the component that actually opens the TCP connection.

The patch in version 1.29.2 introduces a safeDialContext. Here is the logic breakdown of the fix:

1. Resolve First, Connect Second Instead of letting the HTTP client handle DNS, the fix manually resolves the hostname to an IP address first.

2. The Blocklist The resolved IPs are checked against a strict list of forbidden ranges using a new IsInternalIP helper. This blocks Loopback (127.0.0.0/8), Private Networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12), and Link-Local addresses (169.254.0.0/16).

// Simplified view of the patch logic
func safeDialContext(ctx context.Context, network, addr string) (net.Conn, error) {
    host, port, _ := net.SplitHostPort(addr)
    // Step 1: Resolve IP manually
    ips, _ := net.DefaultResolver.LookupIPAddr(ctx, host)
 
    for _, ip := range ips {
        // Step 2: Check blocklist
        if IsInternalIP(ip.IP) {
             return nil, errors.New("blocked internal IP")
        }
    }
    
    // Step 3: Dial the SPECIFIC VALIDATED IP, not the hostname
    // This prevents DNS Rebinding attacks.
    return dialer.DialContext(ctx, network, net.JoinHostPort(ips[0].IP.String(), port))
}

3. Redirect Handling The fix also includes a CheckRedirect hook. This is critical because a safe external URL (e.g., http://attacker.com/safe) could redirect to http://127.0.0.1/secret, bypassing the initial check. The patch ensures the safe dialer is used for every hop in the chain.

The Exploit: Internal Reconnaissance

Exploiting this requires no authentication in default configurations. The attack vector works because Mailpit processes emails received via SMTP, and then exposes the Link Check results via HTTP API.

Phase 1: The Setup The attacker connects to the Mailpit SMTP port (usually 1025) or sends an email through an application that relays to Mailpit. The email body contains HTML with links targeting the internal infrastructure.

Subject: Trojan Horse
 
Check out these "harmless" links:
<a href="http://127.0.0.1:6379">Local Redis</a>
<a href="http://169.254.169.254/latest/meta-data/">AWS Metadata</a>
<a href="http://10.0.0.5:9200">Internal ElasticSearch</a>

Phase 2: The Trigger The attacker queries the Mailpit API list endpoint to find the ID of the email they just sent. Then, they trigger the vulnerability:

GET /api/v1/message/{MESSAGE_ID}/link-check

Phase 3: The Oracle Mailpit attempts to HEAD these URLs. The JSON response will contain the status of each link.

  • If 127.0.0.1:6379 returns a connection error, Redis isn't there.
  • If it returns a protocol error or a generic timeout (depending on how the HTTP client handles the Redis protocol handshake), the attacker knows the port is open.
  • If 169.254.169.254 returns 200 OK, the attacker knows they are in a cloud environment and can proceed to enumerate role names and permissions.

Because the API returns specific error messages and status codes, this acts as a high-speed internal port scanner.

The Impact: Why This Matters

While CVSS 5.8 might look "Medium," the contextual severity is often Critical. Mailpit is almost exclusively deployed in development and staging environments. These environments are notoriously lax on security.

1. Cloud Identity Theft: If Mailpit is running in AWS/GCP/Azure, this SSRF allows an attacker to steal the temporary credentials assigned to the instance. This often leads to full account compromise if the instance has over-privileged IAM roles (e.g., S3 full access).

2. Unauthenticated Internal Services: Developers often run databases like Redis, MongoDB, or Elasticsearch without authentication on localhost because "it's just dev." This vulnerability bridges the gap from the outside world directly to those open ports.

3. CI/CD Pipeline Poisoning: If Mailpit is running inside a CI pipeline, accessing the internal network might allow an attacker to interfere with build artifacts or steal source code.

Official Patches

MailpitRelease notes for v1.29.2 containing the fix.

Fix Analysis (1)

Technical Appendix

CVSS Score
5.8/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N
EPSS Probability
0.05%
Top 100% most exploited

Affected Systems

Mailpit < 1.29.2Development EnvironmentsCI/CD Pipelines using Mailpit

Affected Versions Detail

Product
Affected Versions
Fixed Version
Mailpit
axllent
< 1.29.21.29.2
AttributeDetail
CWE IDCWE-918 (Server-Side Request Forgery)
Attack VectorNetwork (API Triggered)
CVSS v3.15.8 (Medium)
EPSS Score0.047%
ImpactInternal Reconnaissance / Metadata Exposure
Exploit StatusPoC Available

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1595Active Scanning
Reconnaissance
T1552Unsecured Credentials
Credential Access
CWE-918
Server-Side Request Forgery (SSRF)

Known Exploits & Detection

GitHub AdvisoryAdvisory containing reproduction steps and root cause analysis.

Vulnerability Timeline

Patch Commit Merged
2026-02-24
GHSA Advisory Published
2026-02-25
CVE-2026-27808 Assigned
2026-02-25

References & Sources

  • [1]GHSA-mpf7-p9x7-96r3: SSRF in Link Check
  • [2]NVD Entry for CVE-2026-27808

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.