PT-2026-59314 · Pypi · Motioneye

Published

2026-07-13

·

Updated

2026-07-13

CVSS v3.1

5.3

Medium

VectorAV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N

Summary

The ActionHandler.post() method in motionEye has no authentication decorator, allowing any unauthenticated attacker to trigger camera actions including snapshots, recording start/stop, and configured action scripts (PTZ controls, alarm triggers, etc.).

Vulnerability Details

File: motioneye/handlers/action.pyActionHandler.post() line 36 CWE: CWE-862 — Missing Authorization CVSS: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N = 5.3 Medium

Vulnerable Code

python
class ActionHandler(BaseHandler):
  async def post(self, camera id, action):  # ← NO @BaseHandler.auth() decorator
    camera id = int(camera id)
    if camera id not in config.get camera ids():
      raise HTTPError(404, 'no such camera')
    ...
    if action == 'snapshot':
      await self.snapshot(camera id)  # executed without auth
      return
    elif action == 'record start':
      return self.record start(camera id)
    elif action == 'record stop':
      return self.record stop(camera id)

    action commands = config.get action commands(local config)
    command = action commands.get(action)
    ...
    self.run command bg(command)  # executes predefined shell scripts
Compare with other handlers that correctly require authentication:
python
@BaseHandler.auth(admin=True)  # ← properly protected
async def delete(self, camera id, filename):
  ...

Steps to Reproduce

  1. Deploy motionEye with at least one camera configured
  2. Send unauthenticated POST:
POST /action/1/snapshot HTTP/1.1
Host: motioneye-host:8765
Content-Length: 0
  1. Observe {} (HTTP 200) response — snapshot triggered without any credentials
For action scripts (lock, unlock, alarm on, alarm off, light on, etc.):
POST /action/1/alarm on HTTP/1.1
Host: motioneye-host:8765

Impact

  • Unauthenticated attacker can trigger camera snapshots on demand
  • Unauthenticated attacker can start/stop video recording
  • If action scripts are configured by admin: attacker can trigger PTZ movement, alarm control, lighting changes — physical security bypass
  • Via remote cameras: SSRF by triggering action on a remote motionEye server

Verification

Dynamically confirmed on v0.43.1 in Docker lab — POST /action/2/snapshot with no credentials returns HTTP 200 {}. Server log shows the action was processed (failed only because motion daemon was not running for the test camera, not due to an auth rejection).

Recommended Fix

python
class ActionHandler(BaseHandler):
  @BaseHandler.auth()  # add authentication requirement
  async def post(self, camera id, action):
    ...

Fix

Found an issue in the description? Have something to add? Feel free to write us 👾

Related Identifiers

PYSEC-2026-2665

Affected Products

Motioneye