Commit Graph

506 Commits (master)

Author SHA1 Message Date
Isaac Connor ffe6362dc3 fix: harden web interface against injection and SSRF vulnerabilities
FilterTerm.php:
- Replace eval() with safe compare() method for SystemLoad, DiskPercent,
  and DiskBlocks filter conditions (RCE via crafted op/val)
- Validate operator against allowlist in constructor
- Sanitize collate field to alphanumeric/underscore only (SQLi)

onvifprobe.php:
- Use escapeshellarg() on interface, device_ep, soapversion, username,
  and password arguments passed to execONVIF() (command injection)

Event.php:
- Use escapeshellarg() on all arguments to zmvideo.pl instead of
  escapeshellcmd() on the whole command (command injection via format)
- Anchor scale regex with ^ and $ to prevent partial matches

image.php:
- Restrict proxy URL scheme to http/https only (SSRF via file:// etc)

filterdebug.php:
- Use already-sanitized $fid instead of raw $_REQUEST['fid'] (XSS)

MonitorsController.php:
- Use escapeshellarg() on token, username, password, and monitor id
  in zmu shell command instead of escapeshellcmd() on whole command

HostController.php:
- Use escapeshellarg() on path in du command (command injection via mid)
- Remove space from daemon name allowlist (argument injection)

EventsController.php:
- Remove single quotes from interval expression regex (SQLi)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 23:30:49 -04:00
Isaac Connor 419846c875 fix: sanitize monitor Device path to prevent command injection (GHSA-g66m-77fq-79v9)
The Device field from the Monitors table was interpolated directly into
shell commands (qx(), backticks, exec()) without sanitization, allowing
authenticated users with monitor-edit permissions to execute arbitrary
commands as www-data via the Device Path field.

Defense in depth:
- Input validation: reject Device values not matching /^\/dev\/[\w\/.\-]+$/
  at save time in both web UI and REST API
- Output sanitization: use escapeshellarg() in PHP and quote validated
  values in Perl at every shell execution point

Affected locations:
- scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm (control, zmcControl)
- scripts/zmpkg.pl.in (system startup)
- web/includes/Monitor.php (zmcControl)
- web/includes/functions.php (zmcStatus, zmcCheck, validDevicePath)
- web/includes/actions/monitor.php (save action)
- web/api/app/Model/Monitor.php (daemonControl, validation rules)
- web/api/app/Controller/MonitorsController.php (daemonStatus)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 13:19:03 -04:00
Pliable Pixels fea1c850ac fix: address Copilot review feedback on Notifications API refs #4684
- Revert accidental Users.RoleId FK change from CASCADE back to SET NULL
- Remove System != 'None' gate in beforeFilter; any authenticated user
  can manage their own notifications, per-row ownership checks suffice
- Add allowMethod('post', 'put') guard to edit() for consistent REST behavior
- Change PushState validation from allowEmpty to required=false

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 20:39:54 -05:00
Pliable Pixels 9c455cc29d fix: make UserId nullable for no-auth mode refs #4684
- UserId is now DEFAULT NULL instead of NOT NULL
- FK changed to ON DELETE SET NULL (keep token if user deleted)
- Removed auth guard from add() — no-auth mode stores NULL UserId
- No-auth mode already treated as admin by _isAdmin(), so scoping
  works correctly (sees all tokens)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 20:09:32 -05:00
Pliable Pixels c6effc12ab fix: add FK constraint, auth guard, and belongsTo for Notifications refs #4684
- Add FOREIGN KEY on UserId -> Users.Id with ON DELETE CASCADE
  (both in fresh schema and migration)
- Reject push token registration when auth is disabled
  (UserId would be null, violating NOT NULL constraint)
- Add $belongsTo association to User in Notification model

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 20:04:03 -05:00
Pliable Pixels de1f31c6e2 feat: add Notification model, controller, and route refs #4684
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 19:47:29 -05:00
Isaac Connor b036408a5b Fix RCE vulnerability via API config edit privilege escalation
Add RBAC checks to ConfigsController edit() and delete() requiring
System=Edit permission, matching the pattern used by other controllers.
Harden System/Readonly column checks with !empty() to handle missing
columns gracefully. Fix command injection in Event.php by using
ZM_PATH_FFMPEG constant with escapeshellarg() instead of hardcoded
unsanitized ffmpeg call. Add is_executable() validation at all exec()
sites using ZM_PATH_FFMPEG as defense-in-depth against poisoned config
values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 13:51:30 -05:00
Isaac Connor 84728cec6d Add Create to canEdit 2026-02-26 07:21:13 -05:00
Nic Boet d27b565a8d fix: correct App::uses package path in CameraModel
App::uses('AppModel', 'CameraModel') tells CakePHP to look for AppModel
in a non-existent 'CameraModel' package. The correct second argument is
'Model', which points to app/Model/AppModel.php where the base class
actually lives.

This was likely a copy-paste error — every other model in the codebase
correctly uses App::uses('AppModel', 'Model'). The bug may go unnoticed
when another model loads AppModel first via CakePHP's autoloader, but
causes a fatal error if CameraModel is the first model resolved in a
request (e.g. hitting the camera models API endpoint directly).
2026-02-15 15:38:08 -05:00
Isaac Connor 4a730d6934 fix: remove vulnerable phpunit dev dependency (CVE-2026-24765)
Remove phpunit/phpunit from require-dev in web/api/composer.json.
The pinned ^3.7 version is vulnerable to unsafe deserialization in
PHPT code coverage handling. Since ZoneMinder does not run CakePHP
unit tests in CI, the dependency is unused.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 21:59:03 -05:00
Isaac Connor 4e60cb96a7 feat: add User Roles feature for reusable permission templates
Add a User Roles system where roles define reusable permission templates.
When a user has a role assigned, the role provides fallback permissions
(user's direct permissions take precedence; role is used when user has 'None').

Database changes:
- Add User_Roles table with same permission fields as Users
- Add Role_Groups_Permissions table for per-role group overrides
- Add Role_Monitors_Permissions table for per-role monitor overrides
- Add RoleId foreign key to Users table

Permission resolution order:
1. User's direct Monitor/Group permissions (if not 'Inherit')
2. Role's Monitor/Group permissions (if user has role)
3. Role's base permission (if user's is 'None')
4. User's base permission (fallback)

Includes:
- PHP models: User_Role, Role_Group_Permission, Role_Monitor_Permission
- Role management UI in Options > Roles tab
- Role selector in user edit form
- REST API endpoints for roles CRUD
- Translation strings for en_gb

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 13:34:27 -05:00
Isaac Connor 70781753b9 Merge branch 'master' of github.com:ZoneMinder/zoneminder 2026-01-26 09:53:34 -05:00
Isaac Connor 8c3669a2c2 Fix out of date user->MonitorIds 2026-01-26 09:48:22 -05:00
Pliable Pixels be99efa959 fix: add event ID to tags response. ref #4569 2026-01-26 06:40:42 -05:00
Pliable Pixels 82e1f20cff API: Support multiple Event IDs in TagsController index
Allow comma-separated Event IDs when querying tags, e.g.:
/api/tags/index/Events.Id:123,456,789.json

This converts the comma-separated string to an integer array,
enabling a SQL IN clause for efficient multi-event tag retrieval.

Fixes #4567

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 14:00:46 -05:00
Isaac Connor ba0aa29cdb Merge branch 'master' of github.com:ZoneMinder/zoneminder 2026-01-16 14:55:33 -05:00
Isaac Connor 0ecb344723 Don't contain Tag so we don't include Tag and event_Tag in results. 2026-01-05 17:49:46 -05:00
Isaac Connor 93c81961ed Merge branch 'master' of github.com:ZoneMinder/zoneminder 2026-01-05 17:47:23 -05:00
Isaac Connor 44496e8430
Merge pull request #4519 from SteveGilvarry/EventTags2
Add Tags to event search and return tag data with events
2026-01-05 17:47:12 -05:00
Isaac Connor edb105bb32 Update bootstrap.php.in to use zm_config instead of zm_configvals 2026-01-05 11:14:21 -05:00
Steve Gilvarry 58a0e68731 Add Tags to event search and return tag data with events 2026-01-05 21:43:27 +11:00
Isaac Connor 68f91acf10 Remove zm_configvals. Just use zm_config. Move code into loadConfig. 2025-12-22 13:17:01 -05:00
Isaac Connor 1a1e2e7543 Don't add contains so that it doesn't load all associations for the Tag 2025-12-19 17:50:19 -05:00
Isaac Connor 9c79b1ad6e Make filtering by Tags.Id work 2025-12-19 17:50:10 -05:00
Isaac Connor f2b84e0a28 Make Filtering by Events.Id work 2025-12-19 17:50:01 -05:00
Isaac Connor 9f6d1053b0 Don't add a space if there is no operator 2025-12-19 17:49:22 -05:00
Isaac Connor adfcbd1d69 Add route for tags 2025-12-19 16:48:52 -05:00
Isaac Connor cdbeea439b Add named paramter filtering to Configs api index. Add updating returned config entry with values from zm_config which may have been overridden in /etc/zm/conf.d 2025-12-19 16:48:25 -05:00
Isaac Connor d8ccd1cdfa Fix Monitor=>Frame in associations 2025-12-19 16:48:15 -05:00
Isaac Connor 2e3faf4a01 Add fix for nginx api rewriting 2025-11-24 17:46:51 -05:00
Isaac Connor dff38af8af Filter out certain querystring parameters that are for pagination not filtering. Fixes all events not listing in zmNinja 2025-11-19 11:07:19 -05:00
Isaac Connor 9351835815 Update use of allowedmonitors 2025-11-19 09:24:46 -05:00
Isaac Connor 28e4fa4d7f Replace Function=>Capturing 2025-11-17 11:55:58 -05:00
Isaac Connor dbbe2cbcb8 Add EndDateTIme IS NULL condition when using DateTime 2025-10-30 13:53:28 -04:00
Isaac Connor 802ccdcaa9 Use event->can_view to restrict viewing event 2025-10-23 13:56:33 -04:00
Isaac Connor 65d51c7d0a Add support for DateTime as a filter, which means either StartDateTime OR EndDateTime. This allows montagereview to include video that starts BEFORE the requested time but ends after 2025-10-23 13:53:57 -04:00
Isaac Connor 2a11b14bce Remove Function reference 2025-09-06 11:34:09 -04:00
Isaac Connor 1dde898154 Add support for NOT using named params, using query string instead 2025-09-05 12:42:13 -04:00
Isaac Connor 6427511109 Add IN support to api 2025-07-22 16:49:23 -04:00
Isaac Connor d5e81d3c4a Fix incorrect use of eventObjas an array. 2025-07-19 18:29:22 -04:00
Isaac Connor 97877335db Add MaxScoreFrameId to the events table and automatically update it during event creation so we don't have to look it up later. Finding the frame with the max score is actually a very heavy query, so lets not do it. 2025-07-15 16:17:36 -04:00
Isaac Connor c3d4b12286 Do pagination if either page or limit is specified. Otherwise return all 2025-07-11 17:40:54 -04:00
Isaac Connor 5929ccce8d Fix the rename of configvals to zm_configvals 2025-07-09 17:24:19 -04:00
Isaac Connor 7a3a5ca58a If request includes pagination= then restore the old pagination code. 2025-07-09 17:24:02 -04:00
Isaac Connor 974e9fd0f2 When editing a monitor via api, if Capturing=None don't start zmc. Fixes #4348 2025-07-04 16:28:39 -04:00
Isaac Connor ce76f953dc Use limit if it is specified 2025-06-21 21:43:01 -04:00
Isaac Connor d97b37f83f Don't do pagination in events.This may break users of API but pagination should only happen if asked for 2025-06-11 14:57:54 -04:00
Isaac Connor 100a321cf9 Fix ISE when auth is turned off. 2024-10-01 10:13:38 -04:00
Isaac Connor 8264cd345c Spacing, remove commented out stuff 2024-04-10 07:15:09 -04:00
Isaac Connor 21183d332b Handle when auth is off, _getCredentials returns null so accessing it as an array is bad. 2024-03-27 12:57:12 -04:00