Summary
The ProjectAssetEndpoint.patch() method in apps/api/plane/app/views/asset/v2.py (lines 579–593) performs a global asset lookup using only the asset ID (pk) via FileAsset.objects.get(id=pk), without verifying that the asset belongs to the workspace and project specified in the URL path. This allows any authenticated user (including those with the GUEST role) to modify the attributes and is_uploaded status of assets belonging to any workspace or project in the entire Plane instance by guessing or enumerating asset UUIDs.
Root Cause
The patch() method uses FileAsset.objects.get(id=pk), which performs a global lookup across all workspaces and projects. In contrast, the delete() and get() methods in the same class properly scope their queries with workspace__slug=slug, project_id=project_id. This inconsistency is a clear indicator of a missing authorization check.
Impact
- Cross-workspace/cross-project asset modification — Any authenticated user can modify the metadata (
attributes JSON field) of any asset in the entire Plane instance, regardless of workspace or project boundaries.
- Data corruption — The
attributes field stores file metadata such as filename, size, and type. Overwriting it can cause broken file downloads, incorrect file-type rendering, and confusion in document workflows.
- Status manipulation — The
is_uploaded flag is unconditionally set to True, potentially marking incomplete uploads as complete.
- Authorization boundary violation — GUEST users in one workspace can affect assets in entirely different workspaces, violating multi-tenant isolation.
Summary
The
ProjectAssetEndpoint.patch()method inapps/api/plane/app/views/asset/v2.py(lines 579–593) performs a global asset lookup using only the asset ID (pk) viaFileAsset.objects.get(id=pk), without verifying that the asset belongs to the workspace and project specified in the URL path. This allows any authenticated user (including those with the GUEST role) to modify theattributesandis_uploadedstatus of assets belonging to any workspace or project in the entire Plane instance by guessing or enumerating asset UUIDs.Root Cause
The
patch()method usesFileAsset.objects.get(id=pk), which performs a global lookup across all workspaces and projects. In contrast, thedelete()andget()methods in the same class properly scope their queries withworkspace__slug=slug, project_id=project_id. This inconsistency is a clear indicator of a missing authorization check.Impact
attributesJSON field) of any asset in the entire Plane instance, regardless of workspace or project boundaries.attributesfield stores file metadata such as filename, size, and type. Overwriting it can cause broken file downloads, incorrect file-type rendering, and confusion in document workflows.is_uploadedflag is unconditionally set toTrue, potentially marking incomplete uploads as complete.