{"record":{"id":"d9945a4fbd67d6ba","repo":"ATH-MaaS/Pixelle-Video","slug":"access-denied","errorCode":null,"errorMessage":"Access denied","messagePattern":"Access denied","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"warning","filePath":"api/routers/files.py","lineNumber":97,"sourceCode":"        \n        if not abs_path.is_file():\n            raise HTTPException(status_code=400, detail=f\"Path is not a file: {file_path}\")\n        \n        # Security: only allow access to specified directories\n        try:\n            rel_path = abs_path.relative_to(Path.cwd())\n            rel_path_str = str(rel_path)\n            \n            # Check if path starts with any allowed prefix\n            is_allowed = any(rel_path_str.startswith(prefix.rstrip('/')) for prefix in allowed_prefixes)\n            \n            if not is_allowed:\n                raise HTTPException(\n                    status_code=403, \n                    detail=f\"Access denied: only {', '.join(p.rstrip('/') for p in allowed_prefixes)} directories are accessible\"\n                )\n        except ValueError:\n            raise HTTPException(status_code=403, detail=\"Access denied\")\n        \n        # Determine media type\n        suffix = abs_path.suffix.lower()\n        media_types = {\n            '.mp4': 'video/mp4',\n            '.mp3': 'audio/mpeg',\n            '.wav': 'audio/wav',\n            '.png': 'image/png',\n            '.jpg': 'image/jpeg',\n            '.jpeg': 'image/jpeg',\n            '.gif': 'image/gif',\n            '.html': 'text/html',\n            '.json': 'application/json',\n        }\n        media_type = media_types.get(suffix, 'application/octet-stream')\n        \n        # Use inline disposition for browser preview\n        return FileResponse(","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/ATH-MaaS/Pixelle-Video/blob/848b054e4fae40dabc62ec58e960b573e83793ac/api/routers/files.py#L79-L115","documentation":"If abs_path.relative_to(Path.cwd()) raises ValueError — meaning the resolved path is not under the server's working directory at all (e.g. an absolute path elsewhere on the system) — the handler returns a bare 403 'Access denied'. It is the fallback branch of the same traversal protection as the prefix whitelist.","triggerScenarios":"GET to the files endpoint with a file_path/full_path that resolves outside Path.cwd() entirely — absolute paths like /etc/..., or full_path overrides pointing to other locations — so relative_to() raises ValueError.","commonSituations":"Configuring full_path to an absolute directory outside the project; running the server from a different CWD than expected so legit paths appear 'outside'; attempting to serve files from another mount point without adjusting the handler.","solutions":["Use paths within the server's working directory (e.g. output/...).","Start the server from the project root so Path.cwd() matches expectations.","If an external directory must be served, extend the handler to allowlist it explicitly (not by bypassing the check).","Inspect how full_path is configured/defaulted for your deployment."],"exampleFix":"# before\nfull_path = \"/var/data/media/video.mp4\"   # outside server CWD\n# after\nfull_path = \"output/video.mp4\"            # resolved under Path.cwd()","handlingStrategy":"validation","validationCode":"import path from 'path';\nconst abs = path.resolve(fullPath ?? path.join('output', filePath));\nconst cwd = process.cwd();\nif (!abs.startsWith(cwd + path.sep)) throw new Error('Requested file resolves outside the server working directory');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Serve only files under the server's working directory.","Run the server from a fixed, documented working directory.","Do not configure full_path to absolute locations outside the project.","Resolve and log the final path client-side during development to catch mismatches early."],"tags":["http-403","security","path-traversal"],"backgroundTag":"path-traversal-blocked","analyzedSha":"848b054e4fae40dabc62ec58e960b573e83793ac","analyzedAt":"2026-08-30T03:24:41.468Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}