Skip to content

Commit dab8fb4

Browse files
Add project access to check to OrganizationDetectorDetailsEndpoint (#105941)
Currently we allow org members to view detector details for projects they don't have access to. Added a project access check in convert_args() to ensure the requestor has permissions when open membership is disabled.
1 parent a3f13e9 commit dab8fb4

File tree

2 files changed

+65
-0
lines changed

2 files changed

+65
-0
lines changed

src/sentry/workflow_engine/endpoints/organization_detector_details.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ def convert_args(self, request: Request, detector_id, *args, **kwargs):
7979
except Detector.DoesNotExist:
8080
raise ResourceDoesNotExist
8181

82+
# Verify user has access to the detector's project (respects Open Membership setting)
83+
if not request.access.has_project_access(detector.project):
84+
raise PermissionDenied
85+
8286
return args, kwargs
8387

8488
publish_status = {

tests/sentry/workflow_engine/endpoints/test_organization_detector_details.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,67 @@ def test_simple(self) -> None:
104104
def test_does_not_exist(self) -> None:
105105
self.get_error_response(self.organization.slug, 3, status_code=404)
106106

107+
def test_permission_denied_when_open_membership_disabled(self) -> None:
108+
"""
109+
Test that members cannot access detectors for projects they don't have team access to
110+
when Open Membership is disabled. This is a regression test for an IDOR vulnerability.
111+
"""
112+
# Disable Open Membership
113+
self.organization.flags.allow_joinleave = False
114+
self.organization.save()
115+
116+
# Create a user who is a member of the org but NOT a member of any team
117+
user_no_team = self.create_user(is_superuser=False)
118+
self.create_member(
119+
user=user_no_team, organization=self.organization, role="member", teams=[]
120+
)
121+
self.login_as(user_no_team)
122+
123+
# Should get 403 Forbidden since user has no access to the project
124+
self.get_error_response(self.organization.slug, self.detector.id, status_code=403)
125+
126+
def test_permission_allowed_when_open_membership_enabled(self) -> None:
127+
"""
128+
Test that members CAN access detectors for any project when Open Membership is enabled.
129+
"""
130+
# Enable Open Membership (default)
131+
self.organization.flags.allow_joinleave = True
132+
self.organization.save()
133+
134+
# Create a user who is a member of the org but NOT a member of any team
135+
user_no_team = self.create_user(is_superuser=False)
136+
self.create_member(
137+
user=user_no_team, organization=self.organization, role="member", teams=[]
138+
)
139+
self.login_as(user_no_team)
140+
141+
# Should succeed since Open Membership allows access to all projects
142+
response = self.get_success_response(self.organization.slug, self.detector.id)
143+
assert response.data == serialize(self.detector)
144+
145+
def test_permission_allowed_when_user_has_team_membership(self) -> None:
146+
"""
147+
Test that members CAN access detectors for projects they have team access to
148+
even when Open Membership is disabled.
149+
"""
150+
# Disable Open Membership
151+
self.organization.flags.allow_joinleave = False
152+
self.organization.save()
153+
154+
# Create a user who is a member of the project's team
155+
user_with_team = self.create_user(is_superuser=False)
156+
self.create_member(
157+
user=user_with_team,
158+
organization=self.organization,
159+
role="member",
160+
teams=[self.team],
161+
)
162+
self.login_as(user_with_team)
163+
164+
# Should succeed since user has team access to the project
165+
response = self.get_success_response(self.organization.slug, self.detector.id)
166+
assert response.data == serialize(self.detector)
167+
107168
def test_malformed_id(self) -> None:
108169
from django.urls import reverse
109170

0 commit comments

Comments
 (0)