{"record":{"id":"7de3cd17be4b52ea","repo":"ATH-MaaS/Pixelle-Video","slug":"access-denied-only-join-p-rstrip-for-p","errorCode":null,"errorMessage":"Access denied: only {', '.join(p.rstrip('/') for p in allowed_prefixes)} directories are accessible","messagePattern":"Access denied: only (.+?) directories are accessible","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"warning","filePath":"api/routers/files.py","lineNumber":92,"sourceCode":"        \n        abs_path = Path.cwd() / full_path\n        \n        if not abs_path.exists():\n            raise HTTPException(status_code=404, detail=f\"File not found: {file_path}\")\n        \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',","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/ATH-MaaS/Pixelle-Video/blob/848b054e4fae40dabc62ec58e960b573e83793ac/api/routers/files.py#L74-L110","documentation":"The handler enforces a path-traversal whitelist: the resolved relative path must start with one of the allowed prefixes (e.g. output/, uploads/). If the file resolves outside those directories it returns 403 with the list of allowed directories. This blocks access to arbitrary server files.","triggerScenarios":"GET to the files endpoint where the resolved path escapes the allowed roots — absolute paths outside CWD, '../' traversal sequences, symlinks pointing outside allowed directories, or requesting files from a directory not in allowed_prefixes.","commonSituations":"Trying to read config/secrets via path traversal (correctly blocked); legitimate files stored in a new directory that was never added to allowed_prefixes; symlinked output directories resolving outside CWD in dev setups.","solutions":["Request only files under the allowed directories (the detail lists them).","If a new storage directory is legitimate, add it to allowed_prefixes in the handler config.","Normalize/resolve the requested path client-side to stay within the allowed root.","Check for symlinks in your output directories that resolve outside the project root.","Never attempt traversal (../) — the server resolves and rejects it by design."],"exampleFix":"# before\nGET /api/files/../../etc/passwd\n# after\nGET /api/files/generated/frame_0001.mp4  # stays under output/","handlingStrategy":"validation","validationCode":"const normalized = path.posix.normalize(filePath).replace(/^\\.\\./, '');\nif (normalized.startsWith('..') || path.isAbsolute(normalized)) throw new Error('Path must be relative and within allowed directories');\nconst allowedPrefixes = ['output/', 'uploads/'];\nif (!allowedPrefixes.some(p => normalized.startsWith(p))) throw new Error(`Only ${allowedPrefixes.join(', ')} paths are servable`);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep generated artifacts inside the server's allowed directories.","Never send traversal sequences or absolute paths to file endpoints.","Avoid symlinks in output directories that point outside the project root.","When adding new storage locations, update the server's allowed_prefixes list."],"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"}