{"record":{"id":"8becf8aabdfb1d21","repo":"hiyouga/LlamaFactory","slug":"file-access-is-restricted-to-the-safe-media-direct","errorCode":null,"errorMessage":"File access is restricted to the safe media directory.","messagePattern":"File access is restricted to the safe media directory\\.","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"error","filePath":"src/llamafactory/api/common.py","lineNumber":63,"sourceCode":"def jsonify(data: \"BaseModel\") -> str:\n    try:  # pydantic v2\n        return json.dumps(data.model_dump(exclude_unset=True), ensure_ascii=False)\n    except AttributeError:  # pydantic v1\n        return data.json(exclude_unset=True, ensure_ascii=False)\n\n\ndef check_lfi_path(path: str) -> None:\n    \"\"\"Checks if a given path is vulnerable to LFI. Raises HTTPException if unsafe.\"\"\"\n    if not ALLOW_LOCAL_FILES:\n        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=\"Local file access is disabled.\")\n\n    try:\n        os.makedirs(SAFE_MEDIA_PATH, exist_ok=True)\n        real_path = os.path.realpath(path)\n        safe_path = os.path.realpath(SAFE_MEDIA_PATH)\n\n        if not real_path.startswith(safe_path):\n            raise HTTPException(\n                status_code=status.HTTP_403_FORBIDDEN, detail=\"File access is restricted to the safe media directory.\"\n            )\n    except Exception:\n        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=\"Invalid or inaccessible file path.\")\n\n\ndef check_ssrf_url(url: str) -> None:\n    \"\"\"Checks if a given URL is vulnerable to SSRF. Raises HTTPException if unsafe.\"\"\"\n    try:\n        parsed_url = urlparse(url)\n        if parsed_url.scheme not in [\"http\", \"https\"]:\n            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=\"Only HTTP/HTTPS URLs are allowed.\")\n\n        hostname = parsed_url.hostname\n        if not hostname:\n            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=\"Invalid URL hostname.\")\n\n        ip_info = socket.getaddrinfo(hostname, parsed_url.port)","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/hiyouga/LlamaFactory/blob/f28afaf6355af515454dfb16c97d728307c93897/src/llamafactory/api/common.py#L45-L81","documentation":"Raised as HTTP 403 by check_lfi_path when local files ARE allowed but os.path.realpath(path) does not fall under the realpath of SAFE_MEDIA_PATH. Even with ALLOW_LOCAL_FILES=true, media access is sandboxed to a single designated directory, blocking ../../ escapes and absolute paths elsewhere on disk.","triggerScenarios":"Local file enabled, but the path is /etc/passwd, /tmp/img.png, or any path whose canonicalized location is outside SAFE_MEDIA_PATH; symlinks inside the safe dir pointing outside (realpath resolves them, so they are rejected too).","commonSituations":"Enabling local files expecting the old unrestricted behavior; media stored next to the dataset rather than copied into the safe directory; symlinked model datasets.","solutions":["Copy or move the media files under the configured SAFE_MEDIA_PATH directory.","Set SAFE_MEDIA_PATH (env/flag at startup) to the directory that already contains your media.","Do not rely on ../ traversal or symlinks — realpath() canonicalizes both.","Prefer data: URLs or an HTTP file server for one-off files."],"exampleFix":"# before\nSAFE_MEDIA_PATH=/data/safe ...  # request path: /datasets/img.png -> 403\n# after (either copy media or repoint)\ncp /datasets/img.png /data/safe/   # then request /data/safe/img.png","handlingStrategy":"validation","validationCode":"import os\ndef inside_safe_media(path, safe_root):\n    return os.path.realpath(path).startswith(os.path.realpath(safe_root) + os.sep)\n\nassert inside_safe_media(media_path, SAFE_MEDIA_PATH)","typeGuard":"const insideSafe = (p, root) => path.resolve(p).startsWith(path.resolve(root) + path.sep);","tryCatchPattern":"catch (e) { if (e.status === 403 && e.detail.includes('safe media directory')) { copyIntoSafeDir(mediaPath); retry; } else throw e; }","preventionTips":["Stage all request media into SAFE_MEDIA_PATH as part of payload preparation.","Never use ../ relative traversal or symlinks — realpath() defeats both.","Automate a preflight check of every media path against the safe root."],"tags":["security","lfi","path-traversal","http-403","multimodal"],"backgroundTag":null,"analyzedSha":"f28afaf6355af515454dfb16c97d728307c93897","analyzedAt":"2026-08-14T21:57:28.298Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}