CVE-2026-73570: Verified Reproduction
CVE-2026-73570: Zimbra Collaboration unauthenticated RCE via Swatchdog/SNMP log-injection command injection swatchrc dosnmp Perl backtick
CVE-2026-73570 is verified against the affected target. Vulnerability class: RCE. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00327.
What Is CVE-2026-73570?
CVE-2026-73570 is a high-severity RCE vulnerability. Pruva has independently reproduced it and publishes a verified, runnable proof-of-concept (reproduction REPRO-2026-00327).
CVE-2026-73570 Severity
CVE-2026-73570 is rated high severity.
High — serious impact or readily exploitable. Prioritize remediation.
How to Reproduce CVE-2026-73570
pruva-verify REPRO-2026-00327 curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00327/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2026-73570
- reached the target end-to-end
- full exploit chain demonstrated
- on the real production code path
- high confidence
- the upstream fix blocks the same trigger
unauthenticated pipelined SMTP VRFY plus a forged Service status change record sent to installed ZCS packaged Postfix
- external TCP peer
- ZCS packaged Postfix
- /var/log/zimbra.log
- packaged zmswatch as zimbra
- vulnerable dosnmp Perl backtick shell
How the agent worked
Root Cause and Exploit Chain for CVE-2026-73570
CVE-2026-73570 is an unauthenticated command-injection vulnerability in Zimbra Collaboration's SNMP monitoring path. An external SMTP peer can make the ZCS-packaged Postfix service log attacker-controlled text resembling a Zimbra Service status change record. The installed, packaged zmswatch process matches that log line and passes its attacker-controlled SERVICE capture to dosnmp(). Before ZCS 10.1.20, dosnmp() interpolates SERVICE into a Perl backtick command, invoking /bin/sh and permitting command execution as the zimbra operating-system user.
- Affected component: Zimbra Collaboration Suite MTA/SNMP monitoring (
zimbra-mta, optionalzimbra-snmp,/opt/zimbra/conf/swatchrc, packaged Postfix, and packagedzmswatch). - Affected versions: ZCS releases before 10.1.20 with the vulnerable Swatchdog configuration.
- Required configuration: The SNMP package is installed, SNMP notifications are enabled,
zmswatchis running, and the SMTP listener is reachable. - Risk: High. A remote unauthenticated attacker can execute shell commands as the
zimbraaccount, which can disclose Zimbra configuration/credentials or alter mail-service data.
Impact Parity
- Disclosed/claimed maximum impact: Unauthenticated remote code/command execution through the public SMTP protocol path.
- Reproduced impact from this run: Two clean installed-ZCS product instances accepted attacker-controlled SMTP bytes over an external TCP connection to packaged Postfix, logged them to
/var/log/zimbra.log, processed them with packagedzmswatchrunning aszimbra, and created unique shell-expanded markers:v1:u999:nzimbraandv2:u999:nzimbra. - Parity:
full - Not demonstrated: No interactive shell, persistence, credential theft, or privilege escalation beyond the
zimbraaccount was attempted or claimed.
Root Cause
The vulnerable Zimbra Swatchdog rules match Postfix log records of the form : Service status change: (\S+) (.*) changed from .... A compact SMTP command-pipelining violation can place attacker input in that log format. The second capture becomes SERVICE and flows to dosnmp().
The vulnerable ZCS 10.1.0 package input contains:
`$snmptrap $snmpsvctrap $snmpsvcname s $args{SERVICE} $snmpsvcstatus i $statuses{$args{STATUS}}`;
Perl backticks invoke a shell. Consequently, shell metacharacters and command substitutions in SERVICE are interpreted instead of remaining one SNMP argument. The installed vulnerable /opt/zimbra/conf/swatchrc.in has SHA-256 b0b36f69787aad1ad02b3bccac8043187de7113bea1aa49669e31ed98160c02e.
The authentic ZCS 10.1.20 zimbra-mta-patch package replaces this with LIST-form system():
system("/opt/zimbra/common/bin/snmptrap", "-v", "2c", "-c", "zimbra", $traphost, "", $snmpsvctrap, $snmpsvcname, "s", $args{SERVICE}, $snmpsvcstatus, "i", $statuses{$args{STATUS}});
LIST-form execution passes SERVICE as one literal argument without invoking a shell. The authentic fixed swatchrc.in has SHA-256 06e9be7dfad44519dd3f0f9c70673d7ccce6dbfb18bf54dc5ff2c5078a4c4a5c. The exact official fixed package is zimbra-mta-patch 10.1.20.1783342495-1.u22, package SHA-256 f242ee41af609b940c091d4bf9dab7ff1dd641134865d045850cfe00cbdee593.
The release-level fix is documented at https://wiki.zimbra.com/wiki/Zimbra_Releases/10.1.20; this reproduction does not rely on a generated approximation or an inferred source commit.
Reproduction Steps
- Run
bash bundle/repro/reproduction_steps.shfrom any directory. The script usesPRUVA_ROOTwhen set. - The script reads
bundle/project_cache_context.jsonand first uses the prepared project cache. If necessary, it downloads the pinned official ZCS 10.1.0 Ubuntu 22 installer archive and authentic ZCS 10.1.20 MTA patch, verifies their SHA-256 digests, and constructs installed product images. - It creates two clean vulnerable and two clean fixed instances. Every instance starts installed ZCS LDAP state, packaged ZCS Postfix, rsyslog's Zimbra mail-log route, and packaged
zmswatchaszimbra. - For each instance, an external Python TCP peer connects through a host-loopback published port, receives the real Postfix banner, and pipelines
VRFYwith a 99-byte forged service-status record. - Vulnerable success requires both unique victim-shell markers. Fixed success requires the authentic 10.1.20 package identity, the same log/parser path, no marker, and a trace showing the entire metacharacter-bearing payload preserved as literal
snmptrapargv[9]. - The final script was executed successfully twice consecutively; each execution internally performed all four isolated attempts.
Evidence
Primary current-run evidence is under bundle/repro/evidence/:
source-identity.txtbinds the official archive/package digests and immutable vulnerable/fixed runtime image IDs.vulnerable-1/attack-request.txtcontains the actual SMTP transaction bytes.vulnerable-1/smtp.transcriptrecords the real ZCS Postfix banner and protocol exchange.vulnerable-1/zimbra.logproves packaged Postfix logged the attacker-selected forged record.vulnerable-1/processes.txtshows Postfixsmtpdaspostfixand packaged Swatchdog plus its generated parser aszimbra.vulnerable-1/package-identity.txtrecords ZCS 10.1.0,zimbra-postfix 3.6.14,zimbra-perl-swatchdog 3.2.4, andzimbra-snmp 10.1.0.vulnerable-1/marker.txtcontainsv1:u999:nzimbra(SHA-25685fe5f908055df71908e93700df6808558cda5b1e30d390f0247ec365f4d2803).vulnerable-2/marker.txtcontainsv2:u999:nzimbra(SHA-256483742d1e7d96aab6b5fdab8ac45189bed7036ccc9ba3d1b0cf150dbb54bf7ba).fixed-1/result.jsonandfixed-2/result.jsonrecordtarget_path_reached=trueandmarker_present=false.fixed-1/snmptrap.traceandfixed-2/snmptrap.traceshow the attack string preserved literally as one argument under LIST-formsystem().bundle/repro/runtime_manifest.jsonrecordsentrypoint_kind=tcp_peer, all three runtime gates as true, exact target identities, and digest-bound proof artifacts.bundle/repro/validation_verdict.jsonrecordsconfirmed,network_protocol,production_path, and observedcode_execution.bundle/logs/reproduction_steps.logrecords the latest complete orchestration result.
Key current-run excerpts:
v1:u999:nzimbra
v2:u999:nzimbra
postfix smtpd ... improper command pipelining after VRFY ... : Service status change: h x;echo v1:u$(id -u):n$(id -un)>/tmp/p0;# ...
argv[9]=<x;echo f1:u$(id -u):n$(id -un)>/tmp/p2;#>
Recommendations / Next Steps
- Upgrade affected installations to ZCS 10.1.20 or later with the complete vendor-supported package closure.
- Verify that
/opt/zimbra/conf/swatchrc.inuses LIST-formsystem()and regenerate/opt/zimbra/conf/swatchrcwith the normal Zimbra tooling. - Until upgrading, disable SNMP notifications or stop
zmswatchif operationally acceptable. - Inspect Zimbra logs and filesystem/web-root modifications for exploitation indicators; rotate credentials in Zimbra configuration if compromise is suspected.
- Add an end-to-end regression that sends shell metacharacters through SMTP and asserts they arrive at
snmptrapas one literal argument without command side effects.
Additional Notes
- The reproduction is idempotent. It deletes prior attempt evidence, starts fresh isolated containers and ports, and removes every attempt container on exit.
- The primary oracle is non-sanitized product-visible shell execution through the installed production path; no sanitizer was used.
- The real
snmptrapexecutable is used for the vulnerable success path. A recording wrapper is introduced only after the fixed negative-control path has already proven no marker, solely to demonstrate literal fixed-version argv boundaries. - LDAP's test database is recreated per instance because installation-time LMDB files are sparse and unsuitable for a portable image; this does not replace or modify Postfix,
zmswatch,swatchrc, or the vulnerable/fixed sink. - The trigger must remain within Postfix's observed 100-byte client-text log limit; the final forged record is 99 bytes.
CVE-2026-73570 Reproduction Transcript
The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.
Full session Replay every step — scrub the timeline or play it back.
python3 -c "
import json
d=json.load(open('/workspace/bundle/learning/exploit_knowledge_preflight.json'))
for r in d['results']:
rec=r['record']['body']['record']
print('ID:', r['record']['id'])
print('type:', rec.get('record_type'), '| kind:', rec.get('type'))
print('title:', r['record']['title'])
print('summary:', r['record']['summary'][:300])
print('state:', r['record']['state'])
print('preconditions:', [p['description'][:100] for p in r['record'].get('preconditions',[])])
print('---')
print('snapshot sha256 keys:', [k for k in d.keys()])
"EXPLOIT-KNOWLEDGE PREFLIGHT REVIEW REQUIRED: `run_shell` is blocked until this agent calls `review_exploit_knowledge_preflight` with snapshot_sha256 `6b72a8cf0ace8f494d59ec94af88ffb62b1e8eb1b4b4d64aa703302251949b24` and exactly one disposition for each candidate ID [0b9a4106-695d-4727-b599-99817c4b33ab, 1092233e-27a0-4445-a32f-868a0da12bf5, 2b3b033a-4174-4710-a699-55a0fedc64a2, 667e5ef6-0d17-4982-a55b-e41007d54f03]. Historical records remain reference-only; review their typed mechanisms and prec...
Unknown error
python3 -c "
import json
d=json.load(open('/workspace/bundle/learning/exploit_knowledge_preflight.json'))
for r in d['results']:
rec=r['record']['body']['record']
print('ID:', r['record']['id'])
print('type:', rec.get('record_type'), '| kind:', rec.get('type'))
print('title:', r['record']['title'])
print('summary:', r['record']['summary'][:400])
print('state:', r['record']['state'])
print('preconds:', [p['description'][:120] for p in r['record'].get('preconditions',[])])
print('---')
"{"cwd":"/workspace","duration_ms":78,"exit_code":0,"stderr":"","stdout":"ID: 1092233e-27a0-4445-a32f-868a0da12bf5\ntype: None | kind: command_execution\ntitle: Unauthenticated command execution through installed ZCS SMTP and zmswatch\nsummary: Two independently cloned, fully installed vulnerable ZCS product runtimes converted external unauthenticated SMTP VRFY input into unique zimbra-user command markers. Two fresh clones updated with the actual ZCS 10.1.20 package closure reached Postfix and zmswatch but created no marker.\nstate: observed\npreconds: ['The installed vulnerable swatchrc uses Perl backticks in dosnmp; ZCS 10.1.20 replaces this with list-form system().', 'The optional installed ZCS zimbra-snmp package is present, SNMP notifications are enabled, and packaged zmswatch is runn', 'An unauthenticated remote peer can reach installed ZCS Postfix TCP/25 and malformed VRFY arguments are written to /var/l']\n---\nID: 0b9a4106-695d-4727-b599-99817c4b33ab\ntype: None | kind: control_flow_influence\ntitle: Installed ZCS external SMTP-to-zmswatch command control\nsummary: Two fresh installed-ZCS product attempts accepted external unauthenticated SMTP connections, logged attacker-… [truncated]which perl swatch postfix postconf python3 curl git jq 2>/dev/null; perl -v 2>/dev/null | head -2; ls /pruva/project-cache/ 2>/dev/null; id; sudo -n true 2>&1 | head -1/usr/bin/perl /usr/bin/python3 /usr/bin/curl /usr/local/bin/git /usr/bin/jq This is perl 5, version 40, subversion 1 (v5.40.1) built for x86_64-linux-gnu-thread-multi repo-mirrors
ls /pruva/project-cache/repo-mirrors/ 2>/dev/null; sudo -n apt-get -v 2>&1 | head -1; apt-cache policy swatch postfix 2>/dev/null | head -20apt 3.2.0 (amd64)
Artifacts and Evidence for CVE-2026-73570
Scripts, logs, diffs, and output captured during the reproduction.
How to Fix CVE-2026-73570
FAQ: CVE-2026-73570
Is CVE-2026-73570 exploitable?
How severe is CVE-2026-73570?
What type of vulnerability is CVE-2026-73570?
How can I reproduce CVE-2026-73570?
Is the CVE-2026-73570 reproduction verified?
References for CVE-2026-73570
Authoritative sources for CVE-2026-73570 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.