diff --git a/semantica/server.py b/semantica/server.py index c5497d02..627d7191 100644 --- a/semantica/server.py +++ b/semantica/server.py @@ -188,12 +188,19 @@ async def serve_spa(full_path: str): if full_path.startswith("api/"): raise HTTPException(status_code=404, detail="API route not found") - requested_rel_path = Path(full_path) - if requested_rel_path.is_absolute() or ".." in requested_rel_path.parts: + normalized_path = os.path.normpath(full_path) + if ( + normalized_path in ("", ".") + or os.path.isabs(normalized_path) + or normalized_path == ".." + or normalized_path.startswith(".." + os.sep) + ): raise HTTPException(status_code=400, detail="Invalid path") + # Ensure join remains relative to STATIC_DIR even if input includes leading separators + safe_rel_path = normalized_path.lstrip("/\\") static_dir_resolved = STATIC_DIR.resolve() - requested_file = static_dir_resolved.joinpath(requested_rel_path).resolve(strict=False) + requested_file = (static_dir_resolved / safe_rel_path).resolve(strict=False) # Prevent path traversal: reject any path that escapes STATIC_DIR if not requested_file.is_relative_to(static_dir_resolved):