From 7222abe244c80d41f690a438be35ea1381b91ee7 Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Tue, 19 Dec 2023 21:34:34 -0600 Subject: [PATCH] security: arbitrary file download by authenticated user (#2867) * restricts download tokens to data directory * block requests outside of the data dir --- mealie/routes/recipe/bulk_actions.py | 6 +++++- mealie/routes/utility_routes.py | 9 +++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/mealie/routes/recipe/bulk_actions.py b/mealie/routes/recipe/bulk_actions.py index 2682564ca02..678a157ccfb 100644 --- a/mealie/routes/recipe/bulk_actions.py +++ b/mealie/routes/recipe/bulk_actions.py @@ -1,7 +1,7 @@ from functools import cached_property from pathlib import Path -from fastapi import APIRouter, Depends +from fastapi import APIRouter, Depends, HTTPException from mealie.core.dependencies.dependencies import temporary_zip_path from mealie.core.security import create_file_token @@ -50,6 +50,10 @@ def bulk_export_recipes(self, export_recipes: ExportRecipes, temp_path=Depends(t @router.get("/export/download") def get_exported_data_token(self, path: Path): """Returns a token to download a file""" + path = Path(path).resolve() + + if not path.is_relative_to(self.folders.DATA_DIR): + raise HTTPException(400, "path must be relative to data directory") return {"fileToken": create_file_token(path)} diff --git a/mealie/routes/utility_routes.py b/mealie/routes/utility_routes.py index 21496b2e58f..cc67f348d37 100644 --- a/mealie/routes/utility_routes.py +++ b/mealie/routes/utility_routes.py @@ -3,6 +3,7 @@ from fastapi import APIRouter, Depends, HTTPException, status from starlette.responses import FileResponse +from mealie.core.config import get_app_dirs from mealie.core.dependencies import validate_file_token router = APIRouter(prefix="/api/utils", tags=["Utils"], include_in_schema=True) @@ -12,6 +13,14 @@ async def download_file(file_path: Path = Depends(validate_file_token)): """Uses a file token obtained by an active user to retrieve a file from the operating system.""" + + file_path = Path(file_path).resolve() + + dirs = get_app_dirs() + + if not file_path.is_relative_to(dirs.DATA_DIR): + raise HTTPException(status.HTTP_400_BAD_REQUEST) + if not file_path.is_file(): raise HTTPException(status.HTTP_400_BAD_REQUEST)