PT-2026-59314 · Pypi · Motioneye
Published
2026-07-13
·
Updated
2026-07-13
CVSS v3.1
5.3
Medium
| Vector | AV: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.py — ActionHandler.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 MediumVulnerable 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 scriptsCompare with other handlers that correctly require authentication:
python
@BaseHandler.auth(admin=True) # ← properly protected
async def delete(self, camera id, filename):
...Steps to Reproduce
- Deploy motionEye with at least one camera configured
- Send unauthenticated POST:
POST /action/1/snapshot HTTP/1.1
Host: motioneye-host:8765
Content-Length: 0- 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:8765Impact
- 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
Affected Products
Motioneye