This release includes 8 security fixes for security teams reviewing exposed deployments.
Topics
+3 more
Affected surfaces
ReleasePort's take
Moderate signalVersionβ―1.38.3 introduces critical security hardening for the ConfigsController and FilterTerm evaluation, eliminating privilegeβescalation risks via RBAC checks and removal of eval().
Why it matters: The release adds System=Edit RBAC checks to prevent API privilege escalation (severityβ―95) and replaces eval() with safe compare(), fixing RCE vulnerabilitiesβcritical for any deployment exposing the ConfigsController or FilterTerm APIs.
Summary
AI summaryBroad release touches Web Interface & API, π Security & Hardening, π― ONVIF Improvements, and π Authentication & Permissions.
Changes in this release
| Type | Severity | Summary | CVE |
|---|---|---|---|
| Security | Critical |
Adds System=Edit RBAC checks to ConfigsController edit/delete preventing API privilege escalation (RCE). Adds System=Edit RBAC checks to ConfigsController edit/delete preventing API privilege escalation (RCE). Source: llm_adapter@2026-05-28 Confidence: high |
β |
| Security | Critical |
Replaces eval() in FilterTerm SystemLoad/DiskPercent/DiskBlocks evaluation with safe compare(), fixing RCE (evalβbased). Replaces eval() in FilterTerm SystemLoad/DiskPercent/DiskBlocks evaluation with safe compare(), fixing RCE (evalβbased). Source: llm_adapter@2026-05-28 Confidence: high |
β |
| Security | High |
Sanitizes monitor Device path to prevent command injection (GHSA-g66m-77fq-79v9). Sanitizes monitor Device path to prevent command injection (GHSA-g66m-77fq-79v9). Source: llm_adapter@2026-05-28 Confidence: high |
β |
| Security | High |
Escapes URLs in camera probe wget() to prevent command injection (GHSA-745h-vg7c-73cg). Escapes URLs in camera probe wget() to prevent command injection (GHSA-745h-vg7c-73cg). Source: llm_adapter@2026-05-28 Confidence: high |
β |
| Security | High |
Hardens ffmpeg path handling in Event.php to prevent command injection. Hardens ffmpeg path handling in Event.php to prevent command injection. Source: granite4.1:30b@2026-05-28-audit Confidence: low |
β |
| Security | High |
Sanitizes export filename/connkey at AJAX boundary and suppresses raw SQL error text in events ajax responses (XSS sanitization). Sanitizes export filename/connkey at AJAX boundary and suppresses raw SQL error text in events ajax responses (XSS sanitization). Source: granite4.1:30b@2026-05-28-audit Confidence: low |
β |
| Security | High |
Validates FilterTerm operators, intval's monitor IDs, restricts getFormChanges column keys, and dbEscapes MIME fields (SQL injection fixes). Validates FilterTerm operators, intval's monitor IDs, restricts getFormChanges column keys, and dbEscapes MIME fields (SQL injection fixes). Source: granite4.1:30b@2026-05-28-audit Confidence: low |
β |
| Breaking | High |
Makes C++ User class roleβaware, consulting Role_Monitors_Permissions and matching PHP visibleMonitor() logic (roleβbased stream access). Makes C++ User class roleβaware, consulting Role_Monitors_Permissions and matching PHP visibleMonitor() logic (roleβbased stream access). Source: llm_adapter@2026-05-28 Confidence: high |
β |
| Feature | Medium |
Adds CLOSE_DURATION event close mode handling (previously silently fell back to CLOSE_IDLE). Adds CLOSE_DURATION event close mode handling (previously silently fell back to CLOSE_IDLE). Source: llm_adapter@2026-05-28 Confidence: high |
β |
| Feature | Medium |
Defaults ffmpeg decoder thread_count to 2, roughly halving software 1080p H.264 decode time (performance improvement). Defaults ffmpeg decoder thread_count to 2, roughly halving software 1080p H.264 decode time (performance improvement). Source: llm_adapter@2026-05-28 Confidence: low |
β |
| Feature | Low |
Stops NotAuthorized loop by cleaning up ONVIF subscription before reβSubscribe (subscription cleanup). Stops NotAuthorized loop by cleaning up ONVIF subscription before reβSubscribe (subscription cleanup). Source: granite4.1:30b@2026-05-28-audit Confidence: low |
β |
| Feature | Low |
Adds credential fallback chain: ONVIF_Username/Password β Monitor User/Pass when ControlAddress lacks auth. Adds credential fallback chain: ONVIF_Username/Password β Monitor User/Pass when ControlAddress lacks auth. Source: granite4.1:30b@2026-05-28-audit Confidence: low |
β |
| Feature | Low |
Triggers reconnect when ffmpegCamera detects >10β―s DTS rollback, ending warning storms after stream restarts (DTS backward jump detection). Triggers reconnect when ffmpegCamera detects >10β―s DTS rollback, ending warning storms after stream restarts (DTS backward jump detection). Source: granite4.1:30b@2026-05-28-audit Confidence: low |
β |
| Feature | Low |
Adds missing dash separator to ContentβRange header. Adds missing dash separator to ContentβRange header. Source: granite4.1:30b@2026-05-28-audit Confidence: low |
β |
| Dependency | Medium |
Bumps `firebase/php-jwt` from 6.0.0 to 7.0.0 (runtime dependency update). Bumps `firebase/php-jwt` from 6.0.0 to 7.0.0 (runtime dependency update). Source: llm_adapter@2026-05-28 Confidence: high |
β |
| Bugfix | High |
Fixes VideoStore useβafterβfree by holding filename by value and adding null guard (refs #4757). Fixes VideoStore useβafterβfree by holding filename by value and adding null guard (refs #4757). Source: llm_adapter@2026-05-28 Confidence: high |
β |
| Bugfix | Medium |
Derives Event end time from StartDateTime + Length when EndDateTime is missing, preventing montage review crashes. Derives Event end time from StartDateTime + Length when EndDateTime is missing, preventing montage review crashes. Source: llm_adapter@2026-05-28 Confidence: high |
β |
| Bugfix | Medium |
Restricts image.php proxy URL scheme to http/https only, preventing SSRF. Restricts image.php proxy URL scheme to http/https only, preventing SSRF. Source: granite4.1:30b@2026-05-28-audit Confidence: low |
β |
| Bugfix | Medium |
Hardens onvifprobe.php, zmvideo.pl invocation, MonitorsController zmu calls, HostController du, event export, and download/export pipelines with escapeshellarg() and input sanitization (command injection fixes). Hardens onvifprobe.php, zmvideo.pl invocation, MonitorsController zmu calls, HostController du, event export, and download/export pipelines with escapeshellarg() and input sanitization (command injection fixes). Source: granite4.1:30b@2026-05-28-audit Confidence: low |
β |
| Bugfix | Medium |
Adds monitor mutex to block sharedβmemory access during loadMonitor() remap; bails early when monitor fails to load, preventing MonitorStream segfault. Adds monitor mutex to block sharedβmemory access during loadMonitor() remap; bails early when monitor fails to load, preventing MonitorStream segfault. Source: granite4.1:30b@2026-05-28-audit Confidence: low |
β |
| Bugfix | Medium |
Fixes MonitorLink fileβdescriptor leak by calling disconnect() before connect(), avoiding "Too many open files" errors. Fixes MonitorLink fileβdescriptor leak by calling disconnect() before connect(), avoiding "Too many open files" errors. Source: granite4.1:30b@2026-05-28-audit Confidence: low |
β |
| Bugfix | Medium |
Redirects stdin/stdout/stderr to /dev/null during daemonization instead of closing them, avoiding memory corruption from libx264 writing into reused FDs. Redirects stdin/stdout/stderr to /dev/null during daemonization instead of closing them, avoiding memory corruption from libx264 writing into reused FDs. Source: granite4.1:30b@2026-05-28-audit Confidence: low |
β |
| Bugfix | Medium |
Removes writeβindex guard that caused rapid Pause/Play cycling and ~2 empty events per second in ONDEMAND mode. Removes writeβindex guard that caused rapid Pause/Play cycling and ~2 empty events per second in ONDEMAND mode. Source: granite4.1:30b@2026-05-28-audit Confidence: low |
β |
| Bugfix | Medium |
Replaces SOAP_STRINGS[] array with a switch covering known gsoap codes, fixing OOB read on negative codes (GHSA-4842). Replaces SOAP_STRINGS[] array with a switch covering known gsoap codes, fixing OOB read on negative codes (GHSA-4842). Source: granite4.1:30b@2026-05-28-audit Confidence: low |
β |
| Bugfix | Medium |
Synthesizes monotonic DTS for AV_NOPTS_VALUE in VideoStore, preventing reorder queue and audio firstβDTS comparison issues (AV_NOPTS_VALUE handling). Synthesizes monotonic DTS for AV_NOPTS_VALUE in VideoStore, preventing reorder queue and audio firstβDTS comparison issues (AV_NOPTS_VALUE handling). Source: granite4.1:30b@2026-05-28-audit Confidence: low |
β |
| Bugfix | Medium |
Loads incomplete.mp4 files in C++ handler, view_video.php, and image.php; fixes mp4 export endβtimestamp for multiβevent downloads (closes #4767, #4774). Loads incomplete.mp4 files in C++ handler, view_video.php, and image.php; fixes mp4 export endβtimestamp for multiβevent downloads (closes #4767, #4774). Source: granite4.1:30b@2026-05-28-audit Confidence: low |
β |
| Bugfix | Low |
Prevents segfault when MPEG stream codec fails to open. Prevents segfault when MPEG stream codec fails to open. Source: granite4.1:30b@2026-05-28-audit Confidence: low |
β |
| Bugfix | Low |
Cleans up video_out_ctx, codec, and hw_device contexts on setup_hwaccel failure; skips flush_codecs when no frames were sent (memoryβleak fixes). Cleans up video_out_ctx, codec, and hw_device contexts on setup_hwaccel failure; skips flush_codecs when no frames were sent (memoryβleak fixes). Source: granite4.1:30b@2026-05-28-audit Confidence: low |
β |
| Bugfix | Low |
Adds nullβpointer guards for StorageId in Monitor::Load, ModelId in Monitor::Model(), evtStream element, monitor div in video-stream.js. Adds nullβpointer guards for StorageId in Monitor::Load, ModelId in Monitor::Model(), evtStream element, monitor div in video-stream.js. Source: granite4.1:30b@2026-05-28-audit Confidence: low |
β |
| Bugfix | Low |
Correctly parses HTTP Range header forms `bytes=start-end`, `bytes=start-`, and `bytes=-suffix`, fixing ERR_CONTENT_LENGTH_MISMATCH on HEVC playback (Range header parsing). Correctly parses HTTP Range header forms `bytes=start-end`, `bytes=start-`, and `bytes=-suffix`, fixing ERR_CONTENT_LENGTH_MISMATCH on HEVC playback (Range header parsing). Source: granite4.1:30b@2026-05-28-audit Confidence: low |
β |
Full changelog
ZoneMinder 1.38.3 Release Notes
This is a maintenance release that includes security fixes, crash and memory-safety fixes, and a wide range of bug fixes for ZoneMinder 1.38.
Note: 1.38.3 supersedes 1.38.2. The 1.38.2 tag was created but its
Debian package builds hit a cross-distroorig.tar.gzupload conflict
(each distro built its own non-deterministic upstream tarball; mini-dinstall
marked most distros as "incomplete"). Switching the Debian source format
to3.0 (native)for 1.38.3 eliminates the shared-orig requirement entirely.
Apart from the source format and a few CI fixes, the content is identical
to what 1.38.2 would have shipped.
Key Highlights
π Security & Hardening
- API privilege escalation (RCE) - Added System=Edit RBAC checks to ConfigsController edit/delete and hardened ffmpeg path handling in Event.php
- GHSA-g66m-77fq-79v9 - Sanitized monitor Device path to prevent command injection
- GHSA-745h-vg7c-73cg - Escaped URLs in camera probe wget() to prevent command injection
- eval()-based RCE in filters - Replaced eval() in FilterTerm SystemLoad/DiskPercent/DiskBlocks evaluation with a safe compare() method and operator allowlist
- Command injection - Hardened onvifprobe.php, zmvideo.pl invocation, MonitorsController zmu calls, HostController du, event export, and download/export pipelines with escapeshellarg() and input sanitization
- SQL injection - Validated FilterTerm operators and collate, intval'd AlarmedZoneId/monitor IDs, restricted getFormChanges column keys, dbEscape'd MIME fields
- SSRF - Restricted image.php proxy URL scheme to http/https only
- XSS sanitization series - Removed reflected user input from add_monitors, device, event, events, log, and filterdebug AJAX sinks; sanitized export filename/connkey at the AJAX boundary; suppressed raw SQL error text in events ajax responses
- Auth hash bypass with reverse proxy - HTTP_X_FORWARDED_FOR is now used consistently in both PHP and C++ auth-hash validation when AUTH_HASH_IPS is enabled
- Reverse-proxy username handling - Auth relay now carries the username so zms validates against the indexed Username column instead of brute-iterating users
- Bumped
firebase/php-jwtfrom 6.0.0 to 7.0.0
π Crash & Memory Safety
- VideoStore use-after-free - filename is now held by value; destructor guards against null oc when open() bailed early (refs #4757)
- MonitorStream segfault - Added monitor mutex to block shared-memory access during loadMonitor() remap; bail early when monitor failed to load
- MPEG stream codec failure - Prevented segfault when the codec fails to open
- MonitorLink fd leak - connect() now calls disconnect() first, avoiding "Too many open files" under repeated reconnect attempts
- VideoStore fd/codec leaks - Free video_out_ctx after failed avcodec_open2; clean up codec/hw_device contexts on setup_hwaccel failure; skip flush_codecs when no frames were sent
- Daemon FD reuse memory corruption - Daemonization now redirects stdin/stdout/stderr to /dev/null instead of closing them, avoiding libx264 writing into a reused stderr FD
- Null pointer guards - StorageId in Monitor::Load, ModelId in Monitor::Model(), evtStream element, monitor div in video-stream.js
- Empty events in ONDEMAND mode - Removed write-index guard that caused rapid Pause/Play cycling and ~2 empty events per second
π― ONVIF Improvements
- Subscription cleanup before re-Subscribe - Stops the NotAuthorized loop caused by leaked pull-point slots on Hikvision/Reolink cameras
- OOB read on negative gsoap codes - Replaced SOAP_STRINGS[] array with a switch covering the codes seen in practice (SOAP_EOF, network/SSL block, SOAP_STOP) (fixes #4842)
- Credential fallback chain - Falls back to Monitor ONVIF_Username/Password then Monitor User/Pass when ControlAddress lacks auth
- 'Use ONVIF' badge - Only displayed on the console when the listener is actually enabled
π₯ Recording & Playback Correctness
- AV_NOPTS_VALUE handling in VideoStore - Synthesizes monotonic DTS for video passthrough; reorder queue and audio first-DTS no longer compare AV_NOPTS_VALUE sentinels
- DTS backward jump detection - FfmpegCamera now triggers reconnect on >10s DTS rollback, ending the minutes-long warning storm after stream restarts
- Event end time - Derived from StartDateTime + Length when EndDateTime is missing (crashed/killed zmc), so montage review no longer paints a bar across hours of down-time
- incomplete.mp4 playback - C++ handler, view_video.php, and image.php now load incomplete event files; mp4 export end-timestamp fixed for multi-event downloads (closes #4767, #4774)
- HTTP Range header parsing - Correctly handles
bytes=start-end,bytes=start-, andbytes=-suffix; fixes ERR_CONTENT_LENGTH_MISMATCH on HEVC mp4 playback in Chrome (fixes #4777) - Content-Range header - Added missing dash separator
- Event::delete deadlock retry - Wraps the delete transaction in READ COMMITTED with rollback + retry on errno 1213 instead of committing through the deadlock
- Polygon fill - Scan-line fill now steps active edges by pairs, fixing non-convex zones whose concave gaps were incorrectly marked inside the zone
- Polygon clamp - Percentage polygons clamp to width-1/height-1, stopping spurious "polygon hi_x >= image width" warnings
- Zone stats percentage - Convert Area from percentage coordinate space (0-10000) to pixel area before calculating percentages
- alarm_frame_count in ready_count - Stops "Hit end of packetqueue before satisfying pre_event_count" warnings when pre_event_count is 0 but alarm_frame_count is set
π Authentication & Permissions
- Role-based stream access - The C++ User class is now role-aware and consults Role_Monitors_Permissions, Role_Groups_Permissions, and User_Roles base permissions, matching the PHP visibleMonitor() logic
- Stale auth hash on long-running montage - MonitorStream.js refreshes the auth hash before restarting streams on tab visibility change and after the idle modal
- Auth relay - Username included in relay; empty auth_relay no longer produces double
&&in zms URLs; warns on user mismatch instead of silently falling back - Trigger reliability - zmTriggerEventOn now writes trigger_state last, fixing a ~1/3 trigger acceptance rate
ποΈ Build & PHP 8
- Debian source format β 3.0 (native) - The 1.38 line now ships native source packages instead of
3.0 (quilt). Eliminates the cross-distroorig.tar.gzhash conflict on the build farm; each distro produces a self-containedzoneminder_<VERSION>-<DISTRO>.tar.gz. Invisible to apt/dpkg consumers β affects only the source package layout in the repository. - a2enmod rewrite - Debian/Ubuntu postinst now enables mod_rewrite (was incorrectly calling
a2enmod cgi), fixing install failures - PHP 7 polyfill - str_starts_with/str_ends_with/str_contains polyfilled at the top of functions.php so PHP 7 installs don't fatal on event.php
- PHP 8 GD handling - imagedestroy() now called conditionally; GDImage memory release forced on PHP >= 8.0
- www-data video group - Debian/Ubuntu postinst adds www-data to video and dialout groups so zmc can open /dev/video* on fresh installs (refs #4642)
- FreeBSD support - Top command parsing fixed for FreeBSD 13.5; /proc/meminfo presence check; removed unnecessary kFreeBSD arch checks; FreeBSD arm build fixes
- ZM_NO_CURL=ON build - Added HAVE_LIBCURL preprocessor guards throughout zm_monitor.h/cpp and zmc.cpp
Detailed Changes
Core Engine
- Default ffmpeg decoder thread_count to 2 (roughly halves software 1080p H.264 decode time)
- Flush decoder_queue on decoder thread exit to avoid stale latency offset across reconnect
- Reset last_write_index in Pause() to restore DECODING_ONDEMAND bootstrap
- Added CLOSE_DURATION event close mode handling (was silently falling back to CLOSE_IDLE)
- Event-id latch on linked monitor score detection so brief alarm cycles between analysis ticks are no longer missed
- Reduced linked monitor reconnect throttle from 60s to 1s
- Used
+1instead of+last_durationfor equal-DTS fixup
Camera Support
- FFmpeg: Use CxxUrl for credential injection (replaces fragile substr-based string manipulation)
- Reolink: Handle HTTP-to-HTTPS 302 redirect during login (LWP::UserAgent does not follow redirects on POST)
- V4L2: Treat ENOTTY like EINVAL when querying JPEG compression options (some drivers return ENOTTY)
- Added SSL certificate verification fallback to the base Control class β retries with verification disabled on SSL errors, applies to get/put/post
Web Interface & API
- pushState URL state management on the events page so filter state is shareable and browser back/forward restores it
- Mobile layout fixes for monitor config and watch views (CSS specificity on
:first-child) - Don't blank the screen between events when animations are off
- Alarm/idle border applied only to
.imageFeed, not nested img/video elements β fixes extra borders and streams jumping around - Stream URL state: include port in Server URL methods for port-forwarded setups (fixes #4675); honor explicit port argument in urlToApi single-server case; urlToApi falls back to location.host
- Thumbnail overlay scale calculated from actual monitor dimensions instead of hardcoded scale=75
- Montage review playback smoothness, fractional-seconds preserved through mmove/setSpeed, video seek overshoot fix on initial AVSEEK_FLAG_FRAME
- montagereview cookie stores speed value instead of index; changeFilters guards against NaN from invalid date input
- getTracksFromStream moved to skin.js so it can also be used on recorded events; added Go2RTC variant; restart MSE thread on any appendMseBuffer error (not just QuotaExceededError)
- VolumeSlider: noUiSlider properly destroyed when switching player or monitor;
#volumeControlsnow always includes the monitor ID - Event page: VID vs MJPEG playClicked/pauseClicked separation; toggleZones listener assigned after Event page loads
- MSE addSourceBuffer guarded against detached MediaSource when WebRTC wins the race in video-rtc.js
- RTSP2Web RTC errors restart the stream instead of killing it
- z-index ordering for zones SVG overlay corrected (cannot exceed .zonePoint index)
- Sort events by Tags column alias rather than T.Name (which is out of scope in the aggregated query)
- navbar_type now saved in cookies
- Move tag-related commands to canView(Events) instead of canEdit(Events); add Create to canEdit
- Filter debug modal: strip SKIP LOCKED from EXPLAIN so MySQL accepts the query
- Don't add postLoginQuery to the URL when empty
- Fixed image.php
.$fileconcatenation error - Silenced noisy
isJSON()parse-failure console.warn β every getCookie() call for a plain-string cookie ('visible', 'hidden', etc.) was logging an "Unexpected token" SyntaxError to the browser console
Database & Filters
- Filter::Sql() now clears accumulated state (PostSQLConditions, HasDiskPercent, HasDiskBlocks, HasSystemLoad) before rebuilding β previously grew unboundedly
- Filter::Execute uses
prepareinstead ofprepare_cachedsince the SQL changes every cycle (the cache never hit; entries leaked one per distinct substituted value) - zmfilter uses the minimum per-filter delay instead of the last filter's delay, so no filter oversleeps its ExecuteInterval; overdue warning now uses the unclamped delay and includes the filter name and ExecuteInterval value
- Fixed
Filter <name> is taking N seconds longer than execute intervalwarning printing huge bogus numbers (~56 years) on a filter's first iteration βelapsedwas computed against epoch 0 instead of now - Handle PostSQLConditions being an empty array; don't Fatal on SQL prepare errors
- zmDbDo error logging substitutes all SQL placeholders (was only substituting the first)
- Log bind params correctly when SQL contains literal
%characters
Configuration & Logging
- Increased potential config line size β HTML snippets can easily exceed 256 bytes
- Enriched zms auth-failure warning with diagnostic fields to distinguish stale hash, missing auth, disabled user, and IP mismatch
- Removed Warn() in favour of Warning() (fixes #4724)
- Log commands used when updating the database
Scripts & Tools
- zmcontrol/Control.pm: Base class SSL fallback applied across get/put/post
- zmtelemetry/zmu: Daniel Caujolle-Bert refactors using ZoneMinder::Config, ZM_PATH_UNAME, lc()/chomp()/qx, eq instead of ==
- a2enmod: Postinst fix from
cgitorewrite
- QP-encode plain-text email body so URLs with
%EP%/%EPS%/%EPI%substitution tags survive transit (mail clients had been QP-decoding=NNdigit pairs)
Miscellaneous
- Advanced RtspServer pin to a0715995 (correct RTP marker bit from frame.last; cmake_minimum_required to 3.10)
- Don't pass null as the first parameter to strtotime() (PHP 8.1 deprecation)
- Added ZoneMinder.spec from the OBS project
Platform-Specific Changes
FreeBSD
- Fixed top command parsing (tested on FreeBSD 13.5)
- Check for /proc/meminfo before reading (does not exist on FreeBSD)
- Removed unnecessary kFreeBSD arch checks (was amd64/i386 only)
- FreeBSD arm build fixes
CI/CD
- Switched Debian source format to
3.0 (native)(eliminates cross-distro orig.tar.gz upload conflicts) - Tag-push workflows now derive the rsync deploy target from the X.Y minor version (so 1.38.3 lands in the same
release-1.38/dist as future point releases) - Fixed bash-specific
[[ ]]syntax under containersh -eshells; use the locally-checked-outdo_debian_package.shinstead of curl fromrefs/heads/<tag>(404s on tag refs) - Updated deb and aarch64 deb package workflows for the release-1.38 branch
- Renamed proposed rsync target to proposed-1.38
- Use
-r=<tag>for release builds instead of-s=CURRENT - Dynamic branch and deploy targets in deb package workflows
- RPM workflows fire on release-1.38 and derive deploy target from ref
- Package workflows now also fire on tag pushes so stable repo deploys actually run
- ESLint workflow updated to v9 for flat config support
- ESLint config synced to ESLint 9 flat config format
- Bumped GitHub Actions: download-artifact v8, upload-artifact v7, crazy-max/ghaction-import-gpg v7
Upgrade Notes
- Reverse-proxy users with AUTH_HASH_IPS enabled: Authentication now consults HTTP_X_FORWARDED_FOR (falling back to REMOTE_ADDR), so the per-monitor auth hash matches across PHP and C++ when ZoneMinder sits behind a proxy. If you carried custom ZoneMinder-side workarounds for this (e.g. disabling AUTH_HASH_IPS, custom auth_relay code), those can now be removed. Apache/nginx-side RemoteIPHeader / proxy_set_header configuration should stay as-is.
- Role-based permissions: Users who receive camera permissions via Roles will now correctly get live stream access through zms β previously the C++ User class only checked direct user permissions.
- PHP 8 users: GDImage memory handling is now PHP 8-aware. No action needed, but resource usage should be lower.
- Debian/Ubuntu fresh installs: postinst now adds www-data to the
videogroup and runsa2enmod rewrite(notcgi). Existing installs may want to verify these manually. - ONVIF subscription leaks: If cameras were previously stuck in NotAuthorized loops after a few hours, this should now self-recover without a zmc restart.
Contributors
This release includes contributions from the ZoneMinder development team and community members who reported bugs, tested fixes, and provided feedback.
Full Changelog: https://github.com/ZoneMinder/zoneminder/compare/1.38.1...1.38.3
Security Fixes
- GHSA-g66m-77fq-79v9 β Sanitized monitor Device path to prevent command injection
- GHSA-745h-vg7c-73cg β Escaped URLs in camera probe wget() to prevent command injection
- API privilege escalation (RCE) β Added System=Edit RBAC checks to ConfigsController edit/delete and hardened ffmpeg path handling in Event.php
- eval()-based RCE in filters β Replaced eval() with safe compare() method and operator allowlist
- Multiple commandβinjection mitigations across onvifprobe.php, zmvideo.pl, MonitorsController zmu calls, HostController du, event export/download pipelines using escapeshellarg() and sanitization
- SQL injection fixes β Validated FilterTerm operators/collate, intval'd IDs, restricted getFormChanges keys, dbEscape'd MIME fields
- SSRF mitigation β Restricted image.php proxy URL scheme to http/https only
- XSS sanitization series β Removed reflected user input from several AJAX sinks and sanitized export filename/connkey at the boundary
Weekly OSS security release digest.
The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.
No spam, unsubscribe anytime.
Share this release
About zoneminder
ZoneMinder is a free, open source Closed-circuit television software application developed for Linux which supports IP, USB and Analog cameras.
Related context
Related tools
Earlier breaking changes
- v1.38.2 Makes the C++ User class roleβaware, consulting Role_Monitors_Permissions and related tables for liveβstream access.
Beta — feedback welcome: [email protected]