Phoenix

This merge is called Phoenix because Shinobi is being reborn with this massive number of fixes.

Security

  • #560 (reported by Sadık Ertürk, sadik.erturk): Child node connectivity vulnerability fix, plus follow-ups — childNodes.key now also accepts a single string (not just an array), and the security notice for a missing/default key only shows when child nodes are actually enabled.
  • #561 (reported by Matteo Panzeri, matte1782): OS command injection via monitor detector_command, plus a feature flag to fully disable the on-detect command.
  • #562 (reported by Youngjin Kong, 0jinkong): OS command injection via detector_command placeholders, and path traversal on the videos file route.
  • #563 (closed) (reported by Klaus Stock, ks17041968): RTSPS support / URL mangling fix.
  • #564 (reported by Abdullah Kareem, cyberkareemx): Cross-group bypass, missing PTZ permission check, and command injection on probe; also disallow editing privileged fields on the Users row.
  • #565 (reported by Sajjad Haqi, lri5r1js4h2k9nl): 10-vulnerability coordinated disclosure, fixed and re-tested across three rounds:
    • Round 1: unauthenticated DB write via socket ocv, detector-filter eval() RCE, Mount Manager command injection, ffprobe/ONVIF SSRF, isInternal localhost auth bypass, cross-tenant IDOR, account takeover via settings/edit, reflected XSS in embed host.
    • Round 2: stored XSS via matrix drawing on the UI (escapeHtml on all event fields).
    • Round 3: unauthenticated cross-tenant write via the r (recorder) socket handler, cross-tenant group join via the a (admin) socket handler, SSRF on monitor save/connect (new self/metadata-target filter, configurable via disableSSRFSelfTargetFilter), remaining settings/edit HTTP path and timelapse-build ke binding, and closing the remote-origin gap left in the embed page's host parameter fix.
    • Follow-up: the embed host origin check missed the server's own non-standard port (any deployment not on 80/443 would have its own assets rejected and silently downgraded to port 80); and a template comment containing a literal <%- %> broke EJS parsing on render. Both fixed.
  • #566 (reported by Abdullah Kareem, cyberkareemx): Default super-admin credential could be chained through module install to RCE; follow-up hardening on cyberkareemx's own re-test findings.
  • #559 (closed) (reported by Peter Srinivasan, petersrinivasan): Multiple allowed IPs not working as expected (was also a latent auth-check bug, not just a usability issue).
  • users_online info disclosure: The socket init handler broadcast the full server-side session cache to every client in a group — including each user's raw session auth token (as the object key) and their entire account details blob (which can hold cloud/notification credentials). Now sends a minimal, sanitized {uid, mail, sub} list instead.
  • ONVIF scanner SSRF guard: Reject internal/loopback/metadata targets and require an authenticated socket before initiating scans.

Bug fixes

"Dead until restart" class of bugs

  • !552 (merged) (Andrew Linkoln, elador13): Global webhook stopped sending after every process restart, only working again after re-saving Account Settings. Root cause: loadGroupApps() ran the load extensions before populating s.group[ke].init, so the webhook's allowedSend gate was evaluated against an empty config on every cold start.
  • cd68f22b (Andrew Linkoln, elador13): Motion events stopped firing after a monitor restart. motion_lock was cleared via clearTimeout on stop but the property itself was never deleted, so a stale truthy value permanently blocked new motion detections until the whole process restarted.

Media / recording

  • #492 (closed) (reported by v, spamosmail): Timelapse frame writer file-descriptor leak. The per-frame writer created a new WriteStream for every chunk of a frame due to an await between the null-check and assignment. Made stream creation synchronous so exactly one writer is created per frame.
  • #433 (closed) (reported by laviddichterman): stream_channels.forEach is not a function. Hardened buildMainStream and createPipeArray to work off a parsed array so a string value can't crash the build or mis-count stdio pipes.
  • #547 (closed) (reported by Dmitry Lunev, khyonox): Video merge issues; a separate follow-up fixed the copy codec used during video merge.
  • #563 (closed) (reported by Klaus Stock, ks17041968): RTSPS support / URL mangling fix.
  • #529 (closed) (reported by Matthew M. Dean, fireculex): Add RW timeout option.
  • #436 (reported by Meow, GrumpyMeow): Region points outside of canvas — Region Editor update.
  • #400 (closed) (reported by Caennanu, caennanu): Feed freeze on dashboard using substreams.
  • #484 (closed) (reported by It's a me, madri2): Events with null confidence — added percent/type checks in the motion detector path.
  • Fixed toggling substream on/off.
  • pipe4BufferPieces reset on data stream frame checks (buffer state could persist stale data across reconnects).
  • Monitor Stream Window cleanup pass.
  • Removed the unused "eventListWithPics" tab entirely (dead code, was never actually wired up).

Storage / disk accounting

  • #446 (closed) (reported by v, spamosmail): Over-limit purge could permanently wedge. The purge async.queue worker didn't always resolve its callback (e.g. group unloaded mid-purge), stalling all future purges until restart. Worker now always resolves, with a backstop timeout.
  • Cloud storage in-memory math: The "mount" uploader (and other cloud uploaders) could poison used-space counters with NaN/string values, disabling purge and showing NaN until restart. Centralized sanitization of deltas and counters; kilobyteToMegabyte now returns a Number. Rechecked and fixed again for uploader types not covered by the first pass.
  • Additional memory management for the B2, mount, and WebDAV uploaders.
  • Safeguards added to the mount.js orphan scanner.
  • Fixed the target type used for cloud deletion.
  • Google Drive uploader updated; the "moving things" tracker updated alongside it.

Cameras / nodes / PTZ

  • #485 (closed) (reported by imtiaz-nafiz): Child node monitor process not starting. The child read the command mode from the config object instead of the master's command (d.d.mode changed to d.mode).
  • #495 (closed) (reported by LeBizz333): Broader ONVIF event parsing. Handle numeric State (Axis VideoSource/MotionAlarm) alongside boolean styles, and guard against array/missing SimpleItems. Event handling later switched onto the shinobi-onvif module; ONVIF error codes normalized and moveResponse "ok" handling fixed.
  • #477 (closed) (reported by SirLouen, SirLouen): API for Activate Monitor States presets not working — updated s.activateMonitorStates.
  • #450 (closed) (reported by Alex Gilko, alex.gilko): Missing Jetson NVDEC hwaccel; added Jetson hwaccels and cleaned up base.js.
  • #515 (closed) (reported by Hesam Monfared, monfared.hesam): Disconnected monitors — updated Live Grid scrolledIntoView handling.
  • #559 (closed) (reported by Peter Srinivasan, petersrinivasan): Multiple allowed IPs not working as expected.
  • PTZ control now handles the "not configured or not available" case instead of erroring.
  • ONVIF scanner: surface 502/reset/timeout/unexpected responses as visible rows instead of silently dropping them; suppress only true dead-port noise. Tapo's ONVIF port added to the scanner. Additional QoL pass on top.

Notifications

  • #423 (closed) (reported by Dedy Martadinata Supriyadi, dedyms): Notification errors — added a safeguard on Telegram photo sends. Telegram bot module updated to a stable package and pinned in package.json; error notice improved.
  • Firebase Cloud Messaging (FCM) notifications added, later updated to route through push.shinobi.cloud; push tokens now save to their own table instead of being bolted onto an existing one.
  • Matrix notifications no longer depend on matrix-js-sdk.
  • Discord bot can now send to a specific User ID instead of only a channel.
  • Notification messages can include an app link; added the app-link-opener endpoint and auto-detection of the notification base URL when not explicitly configured.
  • Detector notify moved onto runExtensionsForArrayAwaited for onEventTrigger, with a try/catch error handler added around that extension runner so one bad extension can't take down the rest.

Container / platform

  • #461 (closed) (reported by Jack Pan, panxiaoqi): Zombie processes on podman/Docker. Run under tini as PID 1 so reparented ffmpeg orphans are reaped instead of accumulating.
  • #482 (closed) (reported by Florian Asche, florian-asche): Missing procps package in the Docker image — wrapped tree-kill so a missing ps binary doesn't break process management.
  • CPU/RAM health checks: Fixed for FreeBSD, OpenBSD, openSUSE, FreeNAS, and macOS (corrected inverted/misparsed values and broken vmstat flags).

UI / misc

  • Fixed capitalization on "Ignore Server Certificate".
  • Fixed a language.js bug.
  • Separated the Account Settings page layout out of base.js.
  • Removed a stray generated index.md file that had been committed by mistake.

Other issue fixes

Features & options

  • #564 (reported by Abdullah Kareem, cyberkareemx): Separate PTZ ("Can Control Monitor") permission.
  • #561 (reported by Matteo Panzeri, matte1782): Allow completely disabling the on-detect command.
  • #528 (closed) (reported by Pete Rawlings, pjr21121957): Discord notification module update.
  • Unicode support: Regex now matches Unicode letters/digits (incl. Cyrillic) via \p{L}\p{N} plus the u flag; completed Russian (ru.json) translation.
  • Icelandic translation (Sveinn í Felli, sveinki): initial translation, plus a !549 follow-up patch.
  • New config option: disableSSRFSelfTargetFilter (default false) — opt-out for the SSRF self/metadata-target filter on monitor save/connect and the probe endpoint, exposed in the Super Admin Config Editor.
  • Firebase Cloud Messaging (FCM) push notifications.
  • Detector event subscription over socket.io.
  • App-link support in notification messages.

Installers

  • macOS: Reworked to a touchless Docker-based install with Apple Silicon vs Intel image selection; clones into /Applications/Shinobi.
  • FreeBSD, OpenBSD, openSUSE, FreeNAS: Modernized to touchless installs (current package names, MariaDB setup, boot persistence); FreeNAS script further updated.
  • Arch Linux: New installer added.

Dependencies

  • #542 (closed) (reported by wangcw, redgreat): Default database driver to mysql2.
  • #497 (closed) (reported by Elad Bar, elad.bar): npm deprecation warnings — updated MQTT and LDAP modules to current packages.
  • npm audit fix; package.json / package-lock.json updates.

Merge request reports

Loading
Loading