CVE-2026-102608 Overview
CVE-2026-102608 is a command injection vulnerability in ZoneMinder, an open-source closed-circuit television (CCTV) software application. The downloadEvents() function manually wraps a monitor Name value in single quotes instead of using PHP's escapeshellarg() before placing the value into shell commands. An authenticated user with monitor-create or monitor-edit permission can store a monitor Name containing shell metacharacters. When a user with Events View permission exports that monitor's events, the stored name reaches both the ffmpeg concatenation command and the tar or zip archive command, breaking out of manual quoting. Arbitrary commands then execute as the web server user. The issue is fixed in version 1.38.3.
Critical Impact
Stored command injection allows an authenticated low-privilege ZoneMinder user to achieve arbitrary code execution as the web server account during event export.
Affected Products
- ZoneMinder versions prior to 1.38.3
- ZoneMinder deployments exposing event export functionality to multi-user web interfaces
- Any CCTV deployment granting monitor-create or monitor-edit permission to non-administrators
Discovery Timeline
- 2026-10-16 - CVE-2026-102608 published to NVD
- 2026-10-19 - Last updated in NVD database
Technical Details for CVE-2026-102608
Vulnerability Analysis
The flaw is a stored OS command injection [CWE-78] triggered during event export. ZoneMinder's downloadEvents() logic in web/includes/download_functions.php constructs shell commands by concatenating user-controlled monitor Name values into single-quoted strings. Because the quoting is applied manually, a Name containing a literal single quote terminates the quoted segment and allows arbitrary shell syntax to follow. The injected payload reaches two separate sinks: the ffmpeg -f concat command used to merge event video and the archive command (tar or zip) used to package the export. Both sinks execute via exec(), so arbitrary commands run with the privileges of the web server user, typically www-data or apache.
Root Cause
The root cause is improper neutralization of special elements used in an OS command. The vulnerable code paths relied on hand-written single-quote wrapping instead of PHP's dedicated escapeshellarg() function. Additionally, the archive command invocation did not use the -- end-of-options marker, allowing filename operands beginning with - to be interpreted as command-line switches.
Attack Vector
Exploitation requires two authenticated roles. First, a user with monitor-create or monitor-edit permission stores a crafted monitor Name containing shell metacharacters. Second, any user with Events View permission triggers an event export for that monitor, which invokes downloadEvents() and executes the injected commands.
// Vulnerable (pre-1.38.3) and patched code in web/includes/download_functions.php
// Source: https://github.com/ZoneMinder/zoneminder/commit/2de2ae44a1d751bad4b020c5573b2d58c59c1525
} else {
ZM\Error("Can't open event images export file 'event_files.txt'");
}
- $cmd = ZM_PATH_FFMPEG.' -f concat -safe 0 -i event_files.txt -c copy \''.$export_dir.'/'.$mergedFileName. '\' 2>&1';
+ $cmd = ZM_PATH_FFMPEG.' -f concat -safe 0 -i event_files.txt -c copy '.escapeshellarg($export_dir.'/'.$mergedFileName). ' 2>&1';
exec($cmd, $output, $return);
ZM\Debug($cmd.' return code: '.$return.' output: '.print_r($output,true));
$exportFileList[] = $mergedFileName;
The patch replaces manual single-quote wrapping with escapeshellarg(). A follow-up commit also adds the -- end-of-options marker before filename operands passed to tar, zip, and gzip:
// Source: https://github.com/ZoneMinder/zoneminder/commit/b5605e01c14354fc8e2dcae8cefd90c3674880d9
if ($command) {
- $command .= ' '.escapeshellarg($mergedFileName); # Name of the file to be added
+ $command .= ' -- '.escapeshellarg($mergedFileName); # Name of the file to be added
if (executeShelCommand($command, $deleteFile = $mergedFileName) === false) return false;
}
Stop Remote Code Execution Before It Runs
Singularity™ Endpoint detects and blocks exploit attempts at machine speed, including zero-days and novel attack techniques.
Stop Exploit AttemptsDetection Methods for CVE-2026-102608
Indicators of Compromise
- Monitor Name values stored in the ZoneMinder database that contain single quotes, backticks, $(), ;, |, or & characters
- Unexpected child processes of the web server account spawning shells, curl, wget, nc, or python during event export operations
- Entries in ZoneMinder debug logs showing ffmpeg -f concat or tar/zip commands containing shell metacharacters outside quoted segments
Detection Strategies
- Audit the Monitors table for Name values containing shell metacharacters using a SQL query against the ZoneMinder database
- Monitor process execution telemetry for www-data or apache spawning non-standard binaries following HTTP requests to index.php?view=download or event export endpoints
- Inspect web server access logs for POST requests to monitor edit endpoints followed by GET requests to the event export handler
Monitoring Recommendations
- Enable detailed PHP execution logging on the ZoneMinder web host and alert on exec() invocations containing suspicious patterns
- Baseline normal child processes of the web server account and alert on deviations, especially outbound network tools
- Forward web server, PHP, and OS process telemetry to a centralized analytics platform for correlation of monitor edits with subsequent export activity
How to Mitigate CVE-2026-102608
Immediate Actions Required
- Upgrade ZoneMinder to version 1.38.3 or later, which replaces manual quoting with escapeshellarg() and adds the -- end-of-options marker
- Review all existing monitor Name values and remove or rename any entries containing shell metacharacters before upgrading
- Restrict monitor-create and monitor-edit permissions to trusted administrators only
Patch Information
The fix is included in ZoneMinder Release 1.38.3. The relevant commits are 2de2ae4, b3a7c05, and b5605e0. Full details are documented in ZoneMinder Security Advisory GHSA-88m4-hrgp-m9v3 and the Script Kittens technical write-up.
Workarounds
- Temporarily revoke Events View permission for untrusted users until the upgrade is applied
- Place the ZoneMinder web interface behind a network-level access control such as a VPN or source IP allowlist
- Run the ZoneMinder web process under a hardened account with no shell, restrictive filesystem permissions, and no outbound network access
# Example audit query to find monitor names containing shell metacharacters
mysql -u zmuser -p zm -e "SELECT Id, Name FROM Monitors WHERE Name REGEXP '[\\'\\\"\\\\\\\\\\\\$\\\\\\\\\\\\\\\\\\\\\\\\\\\\;\\\\\\\\\\\\|\\\\\\\\\\\\&\\\\\\\\\\\\\\\\\\\\\\\\\\\\`()<>]';"
# Example upgrade on Debian/Ubuntu once 1.38.3 is in your repository
sudo apt-get update
sudo apt-get install --only-upgrade zoneminder
sudo systemctl restart zoneminder apache2
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

