ATH-MaaS/Pixelle-Video · warning · HTTPException

Access denied: only directories are accessible

Error message

Access denied: only {', '.join(p.rstrip('/') for p in allowed_prefixes)} directories are accessible

What it means

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.

Solutions

  1. Request only files under the allowed directories (the detail lists them).
  2. If a new storage directory is legitimate, add it to allowed_prefixes in the handler config.
  3. Normalize/resolve the requested path client-side to stay within the allowed root.
  4. Check for symlinks in your output directories that resolve outside the project root.
  5. Never attempt traversal (../) — the server resolves and rejects it by design.

Example fix

# before
GET /api/files/../../etc/passwd
# after
GET /api/files/generated/frame_0001.mp4  # stays under output/
Defensive patterns

Strategy: validation

Validate before calling

const normalized = path.posix.normalize(filePath).replace(/^\.\./, '');
if (normalized.startsWith('..') || path.isAbsolute(normalized)) throw new Error('Path must be relative and within allowed directories');
const allowedPrefixes = ['output/', 'uploads/'];
if (!allowedPrefixes.some(p => normalized.startsWith(p))) throw new Error(`Only ${allowedPrefixes.join(', ')} paths are servable`);

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of ATH-MaaS/Pixelle-Video@848b054e4f (2026-08-30). Data as JSON: /api/errors/7de3cd17be4b52ea. Report an issue: GitHub.

Appendix: source

Thrown at api/routers/files.py:92

        
        abs_path = Path.cwd() / full_path
        
        if not abs_path.exists():
            raise HTTPException(status_code=404, detail=f"File not found: {file_path}")
        
        if not abs_path.is_file():
            raise HTTPException(status_code=400, detail=f"Path is not a file: {file_path}")
        
        # Security: only allow access to specified directories
        try:
            rel_path = abs_path.relative_to(Path.cwd())
            rel_path_str = str(rel_path)
            
            # Check if path starts with any allowed prefix
            is_allowed = any(rel_path_str.startswith(prefix.rstrip('/')) for prefix in allowed_prefixes)
            
            if not is_allowed:
                raise HTTPException(
                    status_code=403, 
                    detail=f"Access denied: only {', '.join(p.rstrip('/') for p in allowed_prefixes)} directories are accessible"
                )
        except ValueError:
            raise HTTPException(status_code=403, detail="Access denied")
        
        # Determine media type
        suffix = abs_path.suffix.lower()
        media_types = {
            '.mp4': 'video/mp4',
            '.mp3': 'audio/mpeg',
            '.wav': 'audio/wav',
            '.png': 'image/png',
            '.jpg': 'image/jpeg',
            '.jpeg': 'image/jpeg',
            '.gif': 'image/gif',
            '.html': 'text/html',
            '.json': 'application/json',

View on GitHub (pinned to 848b054e4f)