Overview

an event media authz bug in zoneminder

June 13, 2026
3 min read

TL;DR

I also got CVE-2026-54258 in ZoneMinder.

This one was a clean authorization bug around direct event media endpoints.

A low-privileged authenticated user with coarse Events=View and/or Snapshots=View permissions could directly fetch media for events belonging to monitors they were explicitly denied access to.

The normal UI hid the restricted monitor and its events correctly.

The direct media endpoints did not.

The bug

The vulnerable pattern here was simple:

  • the user had enough coarse permission to view event-related features in general
  • the user did not have access to a specific victim monitor
  • normal console and event views respected that restriction
  • direct media endpoints accepted an attacker-controlled eid and streamed the event media anyway

So the app got the high-level permission boundary right, but skipped the actual object-level authorization at the point where the media was fetched.

That is why this one matters.

It was not just “you can see a hidden link in the UI.” It was a backend path returning real media for an event that belonged to a monitor the caller should not have been able to access.

Affected endpoints

The advisory lists these direct media paths:

Stable 1.38.3 and master:

GET /zm/index.php?view=image&eid=<event_id>&fid=snapshot
GET /zm/index.php?view=image&eid=<event_id>&fid=<frame_id>&show=capture
GET /zm/index.php?view=view_video&eid=<event_id>

And on current master:

GET /zm/index.php?view=view_hls&eid=<event_id>

Root cause

According to the advisory, the direct media handlers checked only coarse area permissions like:

  • canView('Events')
  • canView('Snapshots')

After that, they resolved the supplied event ID and streamed media from the event path without enforcing the per-event or per-monitor ACL through the event object itself.

That is the whole issue.

The codebase already had monitor/event-level ACL semantics, and the normal UI respected them. These direct media endpoints just bypassed that layer.

What the attacker gets

The confirmed exposed content included:

  • event snapshots
  • captured frames
  • recorded MP4 video
  • HLS playlists on master

So this was a straightforward confidentiality problem affecting surveillance footage.

That is why this one feels stronger than a lot of ordinary UI-only leaks. The returned data was not metadata or a label. It was the actual underlying media.

What made it good evidence

I liked the negative control here.

The advisory explicitly confirmed that the restricted user could not see the victim monitor or its events through the intended UI. That matters, because it shows the app already knew the user was not supposed to have access.

Then the direct media requests still returned:

  • JPEG snapshots
  • JPEG captured frames
  • MP4 video
  • and on master, a real HLS playlist

That kind of contrast is always solid:

  • intended UI says no
  • direct object fetch says yes

Severity and versions

The public advisory lists:

  • CVE: CVE-2026-54258
  • Severity: Moderate
  • CVSS: 6.5
  • Affected:
    • versions before 1.36.39
    • >= 1.37.0, < 1.38.4
    • >= 1.39.0, < 1.39.11
  • Patched:
    • 1.36.39
    • 1.38.4
    • 1.39.11

The advisory also notes validation on:

  • 1.38.3
  • current master

Why I liked it

This one was nice because it was not noisy.

The permission model was already there. The monitor deny rule existed. The UI did the right thing.

The bug was that one family of direct media views still treated the event ID as enough to serve the media once the user had coarse area permissions.

That makes it a classic object-level authorization failure, and a pretty good one.

Reference

Thanks for reading this blog post all the way to the end