mirror of
https://github.com/makeplane/plane.git
synced 2026-07-09 20:10:06 +02:00
[WEB-7769] fix(security): scope EstimatePoint create/destroy to workspace and project (#9286)
GHSA-933r-rxg8-f3h2 — EstimatePointEndpoint.create trusted the estimate_id URL parameter without verifying it belonged to the caller's workspace and project. An authenticated user in project A could inject estimate points into any other workspace's estimate by supplying a foreign estimate_id. Fix: added a workspace+project scoped Estimate ownership check before EstimatePoint.objects.create(). GHSA-933r-rxg8-f3h2 (destroy) — old_estimate_point was fetched with pk only (unscoped), allowing cross-tenant key disclosure and manipulation during the key-rearrangement step. Fix: scoped the old_estimate_point lookup to estimate_id + project_id + workspace__slug; added 404 guard for missing/foreign points. Note: BulkEstimatePointEndpoint.partial_update (GHSA-vm3j-5j49-gwrf) was already correctly scoped at lines 116 and 125-130 — no change needed. Co-authored-by: Plane AI <noreply@plane.so>
This commit is contained in:
@@ -159,6 +159,17 @@ class EstimatePointEndpoint(BaseViewSet):
|
||||
{"error": "Key and value are required"},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
# Verify the estimate belongs to this workspace and project before creating a point
|
||||
estimate = Estimate.objects.filter(
|
||||
pk=estimate_id,
|
||||
workspace__slug=slug,
|
||||
project_id=project_id,
|
||||
).first()
|
||||
if not estimate:
|
||||
return Response(
|
||||
{"error": "Estimate not found"},
|
||||
status=status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
key = request.data.get("key", 0)
|
||||
value = request.data.get("value", "")
|
||||
estimate_point = EstimatePoint.objects.create(
|
||||
@@ -227,8 +238,18 @@ class EstimatePointEndpoint(BaseViewSet):
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
|
||||
# delete the estimate point
|
||||
old_estimate_point = EstimatePoint.objects.filter(pk=estimate_point_id).first()
|
||||
# delete the estimate point — scope to this estimate/project/workspace to prevent cross-tenant key manipulation
|
||||
old_estimate_point = EstimatePoint.objects.filter(
|
||||
pk=estimate_point_id,
|
||||
estimate_id=estimate_id,
|
||||
project_id=project_id,
|
||||
workspace__slug=slug,
|
||||
).first()
|
||||
if not old_estimate_point:
|
||||
return Response(
|
||||
{"error": "Estimate point not found"},
|
||||
status=status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
|
||||
# rearrange the estimate points
|
||||
updated_estimate_points = []
|
||||
|
||||
Reference in New Issue
Block a user