From 5b37cac58bf06dc3ab58c3ba86e7ce2c4f48c4bb Mon Sep 17 00:00:00 2001 From: sriramveeraghanta Date: Tue, 16 Jun 2026 16:49:11 +0530 Subject: [PATCH 1/2] fix(api): enforce FILE_SIZE_LIMIT on published Space asset upload The public Space asset upload endpoint (POST /api/public/assets/v2/anchor/{anchor}/) trusted the client-supplied `size` value end-to-end: it was stored on the FileAsset and passed straight to generate_presigned_post(), which uses it as the S3/MinIO policy bound (["content-length-range", 1, file_size]). This let an authenticated user obtain a signed upload policy exceeding the instance's FILE_SIZE_LIMIT. Cap the value with `size_limit = min(size, settings.FILE_SIZE_LIMIT)` and use it consistently for the stored asset metadata and the presigned POST policy, matching every other asset upload endpoint. --- apps/api/plane/space/views/asset.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/api/plane/space/views/asset.py b/apps/api/plane/space/views/asset.py index bc20724ca80..040da3840c2 100644 --- a/apps/api/plane/space/views/asset.py +++ b/apps/api/plane/space/views/asset.py @@ -80,6 +80,10 @@ def post(self, request, anchor): entity_type = request.data.get("entity_type", "") entity_identifier = request.data.get("entity_identifier") + # Cap the client-provided size to the instance limit so the signed + # upload policy cannot exceed settings.FILE_SIZE_LIMIT + size_limit = min(size, settings.FILE_SIZE_LIMIT) + # Check if the entity type is allowed if entity_type not in FileAsset.EntityTypeContext.values: return Response( @@ -109,9 +113,9 @@ def post(self, request, anchor): # Create a File Asset asset = FileAsset.objects.create( - attributes={"name": name, "type": type, "size": size}, + attributes={"name": name, "type": type, "size": size_limit}, asset=asset_key, - size=size, + size=size_limit, workspace=deploy_board.workspace, created_by=request.user, entity_type=entity_type, @@ -122,7 +126,7 @@ def post(self, request, anchor): # Get the presigned URL storage = S3Storage(request=request) # Generate a presigned URL to share an S3 object - presigned_url = storage.generate_presigned_post(object_name=asset_key, file_type=type, file_size=size) + presigned_url = storage.generate_presigned_post(object_name=asset_key, file_type=type, file_size=size_limit) # Return the presigned URL return Response( { From f8a918e995bf3b78298043ad7249d35294170522 Mon Sep 17 00:00:00 2001 From: sriramveeraghanta Date: Tue, 16 Jun 2026 17:03:03 +0530 Subject: [PATCH 2/2] fix(api): clamp Space asset size to a valid lower bound Address review feedback: reject malformed (non-integer) `size` with 400 and clamp the value to [1, FILE_SIZE_LIMIT] via max(1, min(...)) so the presigned content-length-range is always valid and no non-positive size is persisted. --- apps/api/plane/space/views/asset.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/api/plane/space/views/asset.py b/apps/api/plane/space/views/asset.py index 040da3840c2..7ecfc8d2afb 100644 --- a/apps/api/plane/space/views/asset.py +++ b/apps/api/plane/space/views/asset.py @@ -76,13 +76,20 @@ def post(self, request, anchor): # Get the asset name = sanitize_filename(request.data.get("name")) or "unnamed" type = request.data.get("type", "image/jpeg") - size = int(request.data.get("size", settings.FILE_SIZE_LIMIT)) + try: + size = int(request.data.get("size", settings.FILE_SIZE_LIMIT)) + except (TypeError, ValueError): + return Response( + {"error": "Invalid size.", "status": False}, + status=status.HTTP_400_BAD_REQUEST, + ) entity_type = request.data.get("entity_type", "") entity_identifier = request.data.get("entity_identifier") - # Cap the client-provided size to the instance limit so the signed - # upload policy cannot exceed settings.FILE_SIZE_LIMIT - size_limit = min(size, settings.FILE_SIZE_LIMIT) + # Clamp the client-provided size to [1, FILE_SIZE_LIMIT] so the signed + # upload policy cannot exceed the instance limit and always carries a + # valid content-length-range bound + size_limit = max(1, min(size, settings.FILE_SIZE_LIMIT)) # Check if the entity type is allowed if entity_type not in FileAsset.EntityTypeContext.values: