Find a vulnerability
Search criteria
Related vulnerabilities
GHSA-J67X-Q29F-QCVV
Vulnerability from github – Published: 2026-06-23 18:37 – Updated: 2026-06-23 18:37Summary
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 Medium
Vulnerable Code
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:
@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: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
class ActionHandler(BaseHandler):
@BaseHandler.auth() # add authentication requirement
async def post(self, camera_id, action):
...
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "motioneye"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.44.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-55863"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-23T18:37:51Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "## Summary\n\nThe `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.).\n\n## Vulnerability Details\n\n**File**: `motioneye/handlers/action.py` \u2014 `ActionHandler.post()` line 36\n**CWE**: CWE-862 \u2014 Missing Authorization\n**CVSS**: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N = 5.3 Medium\n\n### Vulnerable Code\n\n```python\nclass ActionHandler(BaseHandler):\n async def post(self, camera_id, action): # \u2190 NO @BaseHandler.auth() decorator\n camera_id = int(camera_id)\n if camera_id not in config.get_camera_ids():\n raise HTTPError(404, \u0027no such camera\u0027)\n ...\n if action == \u0027snapshot\u0027:\n await self.snapshot(camera_id) # executed without auth\n return\n elif action == \u0027record_start\u0027:\n return self.record_start(camera_id)\n elif action == \u0027record_stop\u0027:\n return self.record_stop(camera_id)\n\n action_commands = config.get_action_commands(local_config)\n command = action_commands.get(action)\n ...\n self.run_command_bg(command) # executes predefined shell scripts\n```\n\nCompare with other handlers that correctly require authentication:\n\n```python\n@BaseHandler.auth(admin=True) # \u2190 properly protected\nasync def delete(self, camera_id, filename):\n ...\n```\n\n## Steps to Reproduce\n\n1. Deploy motionEye with at least one camera configured\n2. Send unauthenticated POST:\n\n```\nPOST /action/1/snapshot HTTP/1.1\nHost: motioneye-host:8765\nContent-Length: 0\n```\n\n3. Observe `{}` (HTTP 200) response \u2014 snapshot triggered without any credentials\n\nFor action scripts (`lock`, `unlock`, `alarm_on`, `alarm_off`, `light_on`, etc.):\n```\nPOST /action/1/alarm_on HTTP/1.1\nHost: motioneye-host:8765\n```\n\n## Impact\n\n- Unauthenticated attacker can trigger camera snapshots on demand\n- Unauthenticated attacker can start/stop video recording\n- If action scripts are configured by admin: attacker can trigger PTZ movement, alarm control, lighting changes \u2014 physical security bypass\n- Via remote cameras: SSRF by triggering action on a remote motionEye server\n\n## Verification\n\nDynamically confirmed on v0.43.1 in Docker lab \u2014 `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).\n\n## Recommended Fix\n\n```python\nclass ActionHandler(BaseHandler):\n @BaseHandler.auth() # add authentication requirement\n async def post(self, camera_id, action):\n ...\n```",
"id": "GHSA-j67x-q29f-qcvv",
"modified": "2026-06-23T18:37:51Z",
"published": "2026-06-23T18:37:51Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/motioneye-project/motioneye/security/advisories/GHSA-j67x-q29f-qcvv"
},
{
"type": "PACKAGE",
"url": "https://github.com/motioneye-project/motioneye"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "motionEye\u0027s missing authentication on ActionHandler allows unauthenticated camera action execution"
}