T05 · Unauthorized Access and Privilege Escalation
- Location
frontend/server.py:194- Finding
Workspace Path Traversal Enables Arbitrary Local File Disclosure
- Content
View full analysis
str: path = Path(value).expanduser() if path.is_absolute(): try: return str(path.resolve().relative_to(ROOT)) except ValueError as error: raise FileNotFoundError("Only paths inside the workspace are allowed.") from error return str(path) def resolve_workspace_path(value: str) -> Path: relative = ensure_relative_path(value) path = (ROOT / relative).resolve() if not path.exists(): raise FileNotFoundError(f"Path not found: {relative}") return path ``` The resolver is exposed through the asset API: ```python if path == "/api/assets": self.serve_asset(str(query.get("path", [""])[0])) return ``` The resolved path is subsequently returned without another containment check: ```python def serve_asset(self, relative_path: str) -> None: clean_path = str(relative_path or "").strip() if not clean_path: self.send_error_json("Missing asset path.", status=HTTPStatus.BAD_REQUEST) return try: asset_path = resolve_workspace_path(clean_path) except FileNotFoundError as error: self.send_error_json(str(error), status=HTTPStatus.NOT_FOUND) return if not asset_path.is_file(): self.send_error_json("Asset path is not a file.", status=HTTPStatus.BAD_REQUEST) return content_type, _encoding = mimetypes.guess_type(str(asset_path)) body = asset_path.read_bytes() self.send_response(HTTPStatus.OK) self.send_header("Content-Type", content_type or "application/octet-stream") self.send_header("Content-Length", str(len(body))) self.end_headers() self.wfile.write(body) ``` ...[truncated 1649 chars]- Remediation
View remediation
Path: root = ROOT.resolve() candidate = (root / value).resolve(strict=True) try: candidate.relative_to(root) except ValueError as error: raise FileNotFoundError("Path escapes the workspace.") from error return candidate ``` 2. Reject absolute paths and paths containing traversal components before resolution. 3. Restrict `/api/assets` to explicit asset directories instead of the entire workspace. 4. Account for symlink escapes by checking the fully resolved path. 5. Require an unpredictable session token or equivalent authorization for all local API endpoints. 6. Add tests for raw, percent-encoded, double-encoded, mixed-separator, and symlink traversal attempts. 7. Return generic errors that do not reveal resolved filesystem paths. ]]>
