diff --git a/backend/api/cloud/operations.py b/backend/api/cloud/operations.py index 9b33d5a..7048cb9 100644 --- a/backend/api/cloud/operations.py +++ b/backend/api/cloud/operations.py @@ -28,6 +28,7 @@ Admin users are blocked by get_regular_user (T-13-01). """ from __future__ import annotations +import urllib.parse import uuid from typing import Optional @@ -362,11 +363,13 @@ async def download_cloud_file( detail="Provider temporarily unavailable — please try again", ) - safe_filename = filename.replace('"', "'") + # RFC 6266 percent-encoding — prevents header injection via special characters + # (newlines, semicolons, etc.) that str.replace('"', "'") does not cover. + encoded_filename = urllib.parse.quote(filename, safe=" !#$&'()*+,-./:;<=>?@[]^_`{|}~") return Response( content=file_bytes, media_type=content_type, - headers={"Content-Disposition": f'attachment; filename="{safe_filename}"'}, + headers={"Content-Disposition": f"attachment; filename*=UTF-8''{encoded_filename}"}, )