VYPR
Medium severityNVD Advisory· Published Jun 23, 2026

motionEye's missing authentication on ActionHandler allows unauthenticated camera action execution

CVE-2026-55863

Description

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

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

  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

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

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
motioneyePyPI
< 0.44.00.44.0

Affected products

1

Patches

Vulnerability mechanics

Root cause

"The `ActionHandler.post()` method in `motioneye/handlers/action.py` is missing the `@BaseHandler.auth()` authentication decorator, allowing unauthenticated execution of camera actions."

Attack vector

An unauthenticated attacker sends an HTTP POST request to the `/action/<camera_id>/<action>` endpoint (e.g., `/action/1/snapshot`) without any credentials. The `ActionHandler.post()` method lacks the `@BaseHandler.auth()` decorator, so it processes the request without verifying the user's identity [ref_id=2]. This allows the attacker to trigger camera snapshots, start/stop recording, and execute any configured action scripts such as PTZ movement or alarm controls [CWE-862]. The attack is network-accessible, requires no authentication, and can be performed with a simple HTTP request from any client that can reach the motionEye server.

What the fix does

The patch adds the `@BaseHandler.auth()` decorator to the `ActionHandler.post()` method, which enforces authentication before any action is processed [ref_id=2]. This mirrors the protection already present on other handlers like `delete()`, which uses `@BaseHandler.auth(admin=True)`. Without this decorator, the method would accept requests from any unauthenticated client; with it, the framework checks for a valid session or credentials before allowing the camera action to execute.

Preconditions

  • networkThe motionEye server must be reachable over the network on port 8765 (default).
  • configAt least one camera must be configured on the motionEye instance.

Reproduction

1. Deploy motionEye with at least one camera configured. 2. Send an unauthenticated POST request: ``` POST /action/1/snapshot HTTP/1.1 Host: motioneye-host:8765 Content-Length: 0 ``` 3. Observe the HTTP 200 `{}` response — the snapshot is triggered without any credentials. 4. For action scripts, send: ``` POST /action/1/alarm_on HTTP/1.1 Host: motioneye-host:8765 ```

Generated on Jun 23, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

2

News mentions

0

No linked articles in our index yet.