Feb 26, 2026·6 min read·27 visits
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.
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 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.
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.
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.
127.0.0.1:6379 returns a connection error, Redis isn't there.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.
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.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Mailpit axllent | < 1.29.2 | 1.29.2 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-918 (Server-Side Request Forgery) |
| Attack Vector | Network (API Triggered) |
| CVSS v3.1 | 5.8 (Medium) |
| EPSS Score | 0.047% |
| Impact | Internal Reconnaissance / Metadata Exposure |
| Exploit Status | PoC Available |
A vulnerability in the Slack and Mattermost platform adapters for NousResearch hermes-agent permits an unauthenticated remote attacker to execute arbitrary mass mentions. By leveraging prompt injection, an attacker can bypass output sanitization logic and trigger workspace-wide notification exhaustion.
CVE-2026-9306 is a critical unauthenticated Insecure Direct Object Reference (IDOR) vulnerability located in the QuantumNous new-api application, affecting versions up to and including 0.12.1. The flaw is caused by improper middleware ordering combined with a lack of object-level authorization checks. This allows remote, unauthenticated attackers to retrieve sensitive Midjourney images belonging to other users by supplying a valid task identifier.
The instagrapi library prior to version 2.6.9 contains an improper input validation vulnerability within its challenge handling mechanism. Maliciously crafted server responses can manipulate the client into forwarding session cookies and credentials to an external attacker-controlled domain.
GHSA-QQQM-5547-774X is a critical path traversal vulnerability in the FileBrowser Quantum application, specifically within the Go backend package. The vulnerability resides in the HTTP handler responsible for processing bulk file modifications via the public API. Unauthenticated attackers can exploit an order-of-operations flaw in the path sanitization logic to bypass intended directory restrictions. This allows adversaries to arbitrarily read, move, and overwrite files on the underlying filesystem by supplying specially crafted HTTP PATCH requests.
The qs query string parsing and serialization library for Node.js is vulnerable to a synchronous Denial of Service (DoS) attack. The vulnerability manifests as a process-terminating TypeError when processing arrays with null or undefined elements under specific configuration parameters.
The aiosend library prior to version 3.0.6 contains a pre-authentication Denial of Service (DoS) vulnerability in its webhook handling mechanism. The software processes and deserializes incoming JSON payloads before verifying the cryptographic signature, allowing unauthenticated attackers to exhaust server CPU and memory resources by sending large, complex payloads.