{"id":"PYSEC-2026-2667","summary":"motionEye's Absolute Path Traversal in Media File Handlers Allows Arbitrary File Read","details":"### Summary\n\nmEye contains an absolute path traversal vulnerability in multiple media file handlers that allows an attacker to read arbitrary files from the filesystem.\n\nThe affected 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 application then bypasses Tornado's built-in path validation by overriding the relevant safety checks.\n\nAs a result, an attacker can access files outside of the configured camera media directory, subject to the permissions of the motionEye process.\n\n### Details\n\nThe issue exists in the media playback and download functionality.\n\nThe filename parameter is passed to `mediafiles.get_media_path()`:\n\n```python\ndef get_media_path(camera_config, path, media_type):\n    target_dir = camera_config.get('target_dir')\n    full_path = os.path.join(target_dir, path)\n    return full_path\n```\n\nWhen path is an absolute path (e.g. `/etc/motioneye/motion.conf`), Python's `os.path.join()` discards `target_dir` entirely and returns the absolute path as-is. This would normally be caught by Tornado's StaticFileHandler path validation, but MoviePlaybackHandler explicitly overrides both safety checks (`movie_playback.py` lines 111-115):\n\n```\ndef get_absolute_path(self, root, path):\n    return path\n\ndef validate_absolute_path(self, root, absolute_path):\n    return absolute_path\n```\nThis allows reading any file on the filesystem that the motionEye process can access.\n\nThe same path traversal exists in the movie download, picture download, and picture preview handlers:\n\n- GET /movie/\u003ccamera_id\u003e/download/\u003cfilename\u003e\n- GET /picture/\u003ccamera_id\u003e/download/\u003cfilename\u003e\n- GET /picture/\u003ccamera_id\u003e/preview/\u003cfilename\u003e\n\n# PoC\n\n```\nGET /movie/1/playback//etc/motioneye/motion.conf HTTP/1.1\nHost: target:8765\n```\n\n# Fix\n\nDo not allow absolute paths supplied by user input.\n\nValidate that the fully resolved canonical path remains within the configured camera media directory before serving a file.\n\nAdditionally, Tornado’s built-in path validation should not be bypassed unless equivalent validation is performed by motionEye.","aliases":["CVE-2026-55488","GHSA-rw9q-97r9-8gvh"],"modified":"2026-07-13T16:32:39.624038240Z","published":"2026-07-13T15:46:23.499449Z","references":[{"type":"WEB","url":"https://github.com/motioneye-project/motioneye/security/advisories/GHSA-rw9q-97r9-8gvh"},{"type":"PACKAGE","url":"https://github.com/motioneye-project/motioneye"},{"type":"PACKAGE","url":"https://pypi.org/project/motioneye"},{"type":"ADVISORY","url":"https://github.com/advisories/GHSA-rw9q-97r9-8gvh"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-55488"}],"affected":[{"package":{"name":"motioneye","ecosystem":"PyPI","purl":"pkg:pypi/motioneye"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"0.44.0"}]}],"versions":["0.27","0.27.1","0.27.2","0.28","0.28.1","0.28.2","0.28.3","0.29","0.29.1","0.29rc1","0.29rc2","0.30","0.30rc1","0.30rc2","0.31","0.31.1","0.31.2","0.31.3","0.31.4","0.31.5","0.32","0.32.1","0.32.2","0.33","0.33.1","0.33.2","0.33.3","0.33.4","0.34","0.34.1","0.34rc1","0.35","0.35.1","0.35.2","0.35rc1","0.36","0.36.1","0.37","0.37.1","0.37rc1","0.38","0.38.1","0.39","0.39.1","0.39.2","0.39.3","0.40","0.40rc1","0.40rc2","0.40rc3","0.40rc4","0.40rc5","0.41","0.41rc1","0.42","0.42.1","0.43.1","0.43.1b1","0.43.1b2","0.43.1b3","0.43.1b4","0.43.1b5","0.44.0b1","0.44.0b2","0.44.0b3"],"database_specific":{"source":"https://github.com/pypa/advisory-database/blob/main/vulns/motioneye/PYSEC-2026-2667.yaml"}}],"schema_version":"1.7.5"}