Skip to content

Fix OS command injection in swatchrc dosnmp() (CVE-2026-73570) - #332

Open
mgamboa wants to merge 2 commits into
Zimbra:developfrom
mgamboa:fix/cve-2026-73570-swatchrc
Open

Fix OS command injection in swatchrc dosnmp() (CVE-2026-73570)#332
mgamboa wants to merge 2 commits into
Zimbra:developfrom
mgamboa:fix/cve-2026-73570-swatchrc

Conversation

@mgamboa

@mgamboa mgamboa commented Aug 25, 2026

Copy link
Copy Markdown

Fix OS command injection in swatchrc dosnmp() (CVE-2026-73570)

Summary

This PR replaces the backtick shell-string construction inside the dosnmp() subroutine of rpmconf/Conf/swatchrc with a list-form system(@cmd) call, eliminating OS command injection through parsed log fields.

Vulnerability

The vulnerable line interpolated $args{SERVICE} — a field parsed out of matched syslog lines by swatchdog's watchfor rules — directly into a double-quoted backtick expression:

`$snmptrap $snmpsvctrap $snmpsvcname s $args{SERVICE} $snmpsvcstatus i $statuses{$args{STATUS}}`

Perl passes backtick content to /bin/sh, so any shell metacharacters surviving in the field are executed with the privileges of the zimbra user.

Because postfix/smtpd logs attacker-controlled SMTP dialog strings verbatim to /var/log/zimbra.log — the same stream swatchdog parses — an unauthenticated attacker with reachability to TCP/25 can forge log lines that satisfy the service-change watch rules and populate $args{SERVICE} with arbitrary shell payloads. This yields unauthenticated RCE. Notably, exploitation does not require SNMP to be configured or functional: both compromised environments observed had no trap receiver at all.

This is tracked as CVE-2026-73570 and has been actively exploited in the wild. Full technical details were reported to security@zimbra.com per the Responsible Disclosure Policy.

Upgrade regression

The vulnerable template is still shipped by current GA builds. During a real-world upgrade from 10.1.5_GA to 10.1.20_GA_0326.RHEL9_64_20260825120723 performed on 2026-08-25, both /opt/zimbra/conf/swatchrc and /opt/zimbra/conf/swatchrc.in were regenerated with the exploitable line still present, requiring an out-of-band emergency re-patch. This fix ensures future builds and upgrades ship a safe template.

The fix

-perlcode 0 sub dosnmp {   my %args = (@_); print "SNMP notification: $args{MESSAGE}\n"; `$snmptrap $snmpsvctrap $snmpsvcname s $args{SERVICE} $snmpsvcstatus i $statuses{$args{STATUS}}`; }
+perlcode 0 sub dosnmp {   my %args = (@_); print "SNMP notification: $args{MESSAGE}\n"; my @cmd = ('/opt/zimbra/common/bin/snmptrap','-v','2c','-c','zimbra',$traphost,'',$snmpsvctrap,$snmpsvcname,'s',$args{SERVICE},$snmpsvcstatus,'i',$statuses{$args{STATUS}}); system(@cmd); }

A list-form system(@cmd) bypasses the shell entirely (execvp() semantics), so no argument can introduce metacharacters while producing byte-for-byte equivalent snmptrap invocations.

Validation

Validated in production on two independent ZCS FOSS servers (RHEL 9, single-server installs):

  • Patched configuration deployed on both hosts is byte-identical (md5: a94195b75831fa41840cfd42b10e79c9 of the patched line).
  • swatchdog compiles the generated script cleanly; watchers stable across restarts and multi-day monitoring windows.
  • SNMP notification path exercised end-to-end (matched events dispatch into dosnmp(); snmptrap receives well-formed arguments).

Related observation

rpmconf/Conf/auditswatchrc interpolates unvalidated parsed fields ($1, $2 = IP/account from auth-failure log lines) into exec /bin/echo "..." actions. swatchdog executes these through the shell as well; a similar hardening pass there would close the same bug class for brute-force notification paths.

Replace the backtick shell string in dosnmp() with a list-form
system(@cmd) call. The previous construction interpolated parsed
log fields ($args{SERVICE}) directly into a /bin/sh command line,
allowing unauthenticated remote command execution as the zimbra
user via log injection through SMTP-supplied strings.

The list-form call passes every argument directly to execvp()
without any shell interpretation, preserving identical SNMP trap
behavior.

Validated in production on two independent ZCS 10.1.20 FOSS
servers (RHEL 9): byte-identical patched configuration across
hosts, swatchdog compiles cleanly, watchers stable, SNMP
notification path exercised end-to-end.

Note: the vulnerable template is still shipped by current GA
builds; a 10.1.5 -> 10.1.20_GA_0326.RHEL9_64_20260825120723
upgrade regenerated the exploitable configuration on the day of
this writing.

Signed-off-by: Mario Gamboa Pang <mario.gamboa@gmail.com>
@CLAassistant

CLAassistant commented Aug 25, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants