| Title | music-assistant server <=2.10.4 Relative Path Traversal |
|---|
| Description | GET /imageproxy reads the image source directly from the path query parameter and, after only a URL percent-decode, forwards it into the thumbnail pipeline. The only path-safety check, is_safe_path() (music_assistant/helpers/security.py), only blocks relative traversal (../../etc/passwd) — it does not reject absolute paths:
def is_safe_path(path: str) -> bool:
norm_path = os.path.normpath(path)
return not (norm_path.startswith("..") or "/../" in norm_path or "\\..\\" in norm_path)
An absolute path like /etc/passwd normalizes to itself, never starts with .., and passes. Two sinks are then reachable in get_image_data():
Raw read (images.py:171-176): if the path ends in .jpg/.png/.jpeg/.svg (any case) and is_safe_path() passes, aiofiles.open(path, "rb") returns the raw file bytes directly.
ffmpeg fallback (images.py:178 → tags.py:get_embedded_image): any other path is placed directly into ffmpeg -i <path> ... -f mjpeg - argv.
The provider param defaults to "builtin" (always registered), making the handler's only authorization-adjacent check a no-op. No check ties the path to the actual media library. |
|---|
| Source | ⚠️ https://github.com/zast-ai/vulnerability-reports/blob/main/music-assistant/server/unauth_file_read.md |
|---|
| User | ZAST.AI (UID 87884) |
|---|
| Submission | 09/29/2026 06:19 (25 days ago) |
|---|
| Moderation | 10/20/2026 12:58 (21 days later) |
|---|
| Status | Accepted |
|---|
| VulDB entry | 422758 [music-assistant server up to 2.9.5 imageproxy security.py is_safe_path path traversal] |
|---|
| Points | 20 |
|---|