Skip to content

Sentry Vulnerability Corpus

This page renders the structured benchmark corpus from packages/docs/src/data/benchmarking/*.json. Add another corpus by dropping a new JSON file in that directory.

Only validated security vulnerabilities whose vulnerable code lives in the public getsentry/sentry repository belong here. Private repository findings, candidate findings, and unrelated product bugs are out of scope.

Each finding carries a Sentry repository SHA and links to the referenced file at that revision. The current SHA values are inferred from capture timestamps. As we backfill from the original tickets, fix commits, or raw run logs, replace them with the most recent SHA known to still contain the vulnerability.

86 findings

sentry-vuln-001

POST /accept-invite lets authenticated users delete arbitrary org members without validating the invite token.

getsentry/sentry@788ba30f1aa4View source

accept_organization_invite.py:265-275
data={"details": "unable to accept organization invite"},
)
elif helper.member_already_exists:
response = Response(
status=status.HTTP_400_BAD_REQUEST, data={"details": "member already exists"}
)
elif not helper.valid_request:
return Response(
status=status.HTTP_400_BAD_REQUEST,
data={"details": "unable to accept organization invite"},
)

sentry-vuln-004

OAuth /userinfo returns PII for tokens tied to inactive users or disabled OAuth apps.

getsentry/sentry@2d929588e20bView source

oauth_userinfo.py:61-71
@control_silo_endpoint
class OAuthUserInfoEndpoint(Endpoint):
publish_status = {
"GET": ApiPublishStatus.PRIVATE,
}
owner = ApiOwner.ENTERPRISE
authentication_classes = ()
permission_classes = ()

sentry-vuln-005

OAuth /userinfo looks up plaintext token values, bypassing the hashed-token path.

getsentry/sentry@2d929588e20bView source

oauth_userinfo.py:81-86
access_token = auth_header[1].decode("utf-8")
try:
token_details = ApiToken.objects.get(token=access_token)
except ApiToken.DoesNotExist:
raise BearerTokenInvalid()

sentry-vuln-006

Plugin deprecation info enumerates project rules and groups without per-project access checks.

getsentry/sentry@2d929588e20bView source

organization_plugin_deprecation_info.py:20-30
owner = ApiOwner.ECOSYSTEM
def get(self, request, organization, plugin_slug):
"""
Returns a list of objects that are affected by a plugin deprecation. Objects could be issues or alert rules or both
pparam: organization, plugin_slug
"""
# Plugins in the db are stored in lowercase but there is not guarantee that's how the customer will call the API
plugin = plugin_slug.lower()
plugin_projects = Project.objects.filter(
status=ObjectStatus.ACTIVE,

sentry-vuln-007

Release threshold index returns every org's rows when projects_list resolves empty.

getsentry/sentry@2d929588e20bView source

release_threshold_index.py:38-48
}
def get(self, request: Request, organization: Organization) -> HttpResponse:
validator = ReleaseThresholdIndexGETValidator(
data=request.query_params,
)
if not validator.is_valid():
return Response(validator.errors, status=400)
environments_list = self.get_environments(request, organization)
projects_list = self.get_projects(request, organization)

sentry-vuln-008

SYSTEM_OPTIONS_ALLOWLIST behaves as a substring match because of a missing comma.

getsentry/sentry@2d929588e20bView source

system_options.py:18-30
SYSTEM_OPTIONS_ALLOWLIST = (
# Used during setup before the superadmin role with the options.admin permission is authed
"system.admin-email"
)
@all_silo_endpoint
class SystemOptionsEndpoint(Endpoint):
publish_status = {
"GET": ApiPublishStatus.PRIVATE,
"PUT": ApiPublishStatus.PRIVATE,
}

sentry-vuln-009

Unescaped transaction name in root-cause analysis enables Sentry search filter injection.

getsentry/sentry@fbecd17d210cView source

organization_events_root_cause_analysis.py:51-55
snuba_params=snuba_params,
selected_columns=selected_columns,
equations=[],
query=f'event.type:transaction transaction:"{transaction}"',
limit=limit,

sentry-vuln-010

PUT /system/options/ logs cleartext option values, including credentials.

getsentry/sentry@fbecd17d210cView source

system_options.py:107-117
else:
options.set(k, v, channel=options.UpdateChannel.APPLICATION)
logger.info(
"options.update",
extra={
"ip_address": request.META["REMOTE_ADDR"],
"user_id": request.user.id,
"option_key": k,
"option_value": v,
},

sentry-vuln-011

Jira install webhook does not bind verified JWT iss to body clientKey; partial fix left residual replay risk.

getsentry/sentry@9fc06de579fbView source

installed.py:34-44
def post(self, request: Request, *args, **kwargs) -> Response:
with IntegrationPipelineViewEvent(
interaction_type=IntegrationPipelineViewType.VERIFY_INSTALLATION,
domain=IntegrationDomain.PROJECT_MANAGEMENT,
provider_key=self.provider,
).capture() as lifecycle:
token = self.get_token(request)
state = request.data
if not state:
lifecycle.record_failure(ProjectManagementFailuresReason.INSTALLATION_STATE_MISSING)

sentry-vuln-012

MS Teams action submission does not scope the target group to the integration organization.

getsentry/sentry@9fc06de579fbView source

webhook.py:543-553
return response
def _handle_action_submitted(self, request: Request) -> Response:
# pull out parameters
data = request.data
channel_data = data["channelData"]
tenant_id = channel_data["tenant"]["id"]
payload = data["value"]["payload"]
group_id = payload["groupId"]
integration_id = payload["integrationId"]
user_id = data["from"]["id"]

sentry-vuln-013

PerforceIntegration.get_config_data exposes the Perforce password to any org member with org:read.

getsentry/sentry@9fc06de579fbView source

integration.py:451-463
def get_config_data(self) -> Mapping[str, Any]:
"""
Get current configuration values for the integration.
This is called by the serializer to populate the form fields with existing values.
Since we store credentials in integration.metadata (not org_integration.config),
we override the base implementation to read from metadata.
Returns:
Dictionary of current configuration values that will be used to populate
the form fields defined in get_organization_config()
"""

sentry-vuln-014

SlackOptionsLoadEndpoint discloses any project's teams and members across tenants.

getsentry/sentry@9fc06de579fbView source

options_load.py:27-37
@cell_silo_endpoint
class SlackOptionsLoadEndpoint(Endpoint):
owner = ApiOwner.ECOSYSTEM
publish_status = {
"POST": ApiPublishStatus.PRIVATE,
}
authentication_classes = ()
permission_classes = ()
slack_request_class = SlackOptionsLoadRequest

sentry-vuln-015

Replays data_export_notifications lets any authenticated user trigger arbitrary GCS transfer jobs.

getsentry/sentry@9fc06de579fbView source

data_export_notifications.py:15-26
@control_silo_endpoint
class DataExportNotificationsEndpoint(Endpoint):
"""PubSub notifications endpoint."""
owner = ApiOwner.DATA_BROWSING
publish_status = {"POST": ApiPublishStatus.PRIVATE}
permission_classes = (SentryIsAuthenticated,)
def post(self, request: Request) -> Response:
retry_transfer_job_run(request.data, request_run_transfer_job)
return Response("", status=200)

sentry-vuln-016

Replay DELETE accepts project:read, letting read-only members delete replays.

getsentry/sentry@9fc06de579fbView source

project_replay_details.py:20-28
class ReplayDetailsPermission(ProjectPermission):
scope_map = {
"GET": ["project:read", "project:write", "project:admin"],
"POST": ["project:write", "project:admin"],
"PUT": ["project:write", "project:admin"],
"DELETE": ["project:read", "project:write", "project:admin"],
}

sentry-vuln-017

Preprod snapshot GET/DELETE skips has_project_access, enabling cross-team read and destroy.

getsentry/sentry@9fc06de579fbView source

preprod_artifact_snapshot.py:129-141
def delete(self, request: Request, organization: Organization, snapshot_id: str) -> Response:
if not settings.IS_DEV and not features.has(
"organizations:preprod-snapshots", organization, actor=request.user
):
return Response({"detail": "Feature not enabled"}, status=403)
try:
artifact = PreprodArtifact.objects.select_related("project").get(
id=snapshot_id, project__organization_id=organization.id
)
except (PreprodArtifact.DoesNotExist, ValueError):
return Response({"detail": "Snapshot not found"}, status=404)

sentry-vuln-018

Pinned-search PUT overwrites another user's GroupSearchView when caller starred it at position 0.

getsentry/sentry@9fc06de579fbView source

organization_pinned_searches.py:60-70
)
# This entire endpoint will be removed once custom views are GA'd
first_starred_view = GroupSearchViewStarred.objects.filter(
organization=organization, user_id=request.user.id, position=0
).first()
if first_starred_view:
default_view = first_starred_view.group_search_view
default_view.query = result["query"]
default_view.query_sort = result["sort"]

sentry-vuln-019

ControlAccessService.can_override_sso_as_owner excludes by the wrong primary key, creating a narrow SSO bypass risk.

getsentry/sentry@9fc06de579fbView source

impl.py:48-58
"""If an owner is trying to gain access, allow bypassing SSO if there are no
other owners with SSO enabled.
"""
# get member role
try:
member_role = OrganizationMemberMapping.objects.get(
organizationmember_id=member.id, organization_id=member.organization_id
).role
except OrganizationMemberMapping.DoesNotExist:
return False

sentry-vuln-020

Account-merge endpoint never enforces verification-code expiry or single-use.

getsentry/sentry@9fc06de579fbView source

user_merge_verification_code.py:34-46
token = models.CharField(max_length=64, default=generate_token)
expires_at = models.DateTimeField(default=generate_expires_at)
class Meta:
app_label = "sentry"
db_table = "sentry_user_verification_codes_temp"
__repr__ = sane_repr("user_id", "token")
def regenerate_token(self) -> None:
self.token = generate_token()
self.refresh_expires_at()
self.save()

sentry-vuln-021

Codecov repository token regeneration accepts org:read for destructive token rotation.

getsentry/sentry@9fc06de579fbView source

repository_token_regenerate.py:18-24
class RepositoryTokenRegeneratePermission(OrganizationPermission):
scope_map = {
"GET": ["org:read", "org:write", "org:admin"],
"POST": ["org:read", "org:write", "org:admin"],
}

sentry-vuln-022

ExploreSavedQueryVisitEndpoint.post skips check_object_permissions.

getsentry/sentry@9fc06de579fbView source

explore_saved_query_detail.py:165-177
@cell_silo_endpoint
class ExploreSavedQueryVisitEndpoint(ExploreSavedQueryBase):
publish_status = {
"POST": ApiPublishStatus.PRIVATE,
}
def has_feature(self, organization, request):
return features.has(
"organizations:visibility-explore-view", organization, actor=request.user
)
def post(self, request: Request, organization, query) -> Response:
"""

sentry-vuln-023

Flag webhook signing-secret POST allows org:read members to plant first-time secrets.

getsentry/sentry@9fc06de579fbView source

secrets.py:81-91
)
def post(self, request: Request, organization: Organization) -> Response:
validator = FlagWebhookSigningSecretValidator(data=request.data)
if not validator.is_valid():
return self.respond(validator.errors, status=400)
# these scopes can always update or post secrets
has_permission = request.access.has_scope("org:write") or request.access.has_scope(
"org:admin"
)

sentry-vuln-024

Sentry App alert-rule trigger dispatch does not verify the installation belongs to the caller's org.

getsentry/sentry@9fc06de579fbView source

project_rules.py:1018-1024
return Response(uuid_context, status=202)
try:
created_alert_rule_ui_component = trigger_sentry_app_action_creators_for_issues(
kwargs["actions"]
)
except SentryAppBaseError as e:

sentry-vuln-025

ExternalTeamDetailsEndpoint scopes only by org, allowing cross-team modify, delete, and reparent.

getsentry/sentry@9fc06de579fbView source

external_team_details.py:35-45
owner = ApiOwner.ENTERPRISE
def convert_args(
self,
request: Request,
organization_id_or_slug: int | str,
team_id_or_slug: int | str,
external_team_id: int,
*args: Any,
**kwargs: Any,
) -> tuple[Any, Any]:

sentry-vuln-026

UnlinkIdentityView deletes identities by external_id without proving caller ownership.

getsentry/sentry@9fc06de579fbView source

linkage.py:289-299
class UnlinkIdentityView(IdentityLinkageView, ABC):
@property
def confirmation_template(self) -> str:
return "sentry/auth-unlink-identity.html"
@property
def no_identity_template(self) -> str | None:
"""Optional page to show if identities were not found."""
return None

sentry-vuln-027

Slack action handler get_rule fetches Rule by ID without org scoping; exploitability is narrowed to rule-ID enumeration.

getsentry/sentry@9fc06de579fbView source

action.py:131-141
def get_rule(
slack_request: SlackActionRequest, organization: Organization, group_type: int
) -> Rule | None:
from sentry.notifications.notification_action.utils import should_fire_workflow_actions
"""Get the rule that fired"""
rule_id = slack_request.callback_data.get("rule")
if not rule_id:
return None

sentry-vuln-028

get_shared_for_org can bypass the target org's disable_shared_issues flag through slug confusion.

getsentry/sentry@9fc06de579fbView source

accept_organization_invite.py:265-275
data={"details": "unable to accept organization invite"},
)
elif helper.member_already_exists:
response = Response(
status=status.HTTP_400_BAD_REQUEST, data={"details": "member already exists"}
)
elif not helper.valid_request:
return Response(
status=status.HTTP_400_BAD_REQUEST,
data={"details": "unable to accept organization invite"},
)

sentry-vuln-029

Metric-alert team-target lookup is unscoped while user-target lookup is scoped.

getsentry/sentry@9fc06de579fbView source

metric_alert_registry_handler.py:77-87
result[action.id] = None
if user_actions:
dcgas = DataConditionGroupAction.objects.filter(
action__in=[a.id for a in user_actions]
).select_related("condition_group")
org_by_action_id = {
dcga.action_id: dcga.condition_group.organization_id for dcga in dcgas
}
org_members = OrganizationMember.objects.filter(

sentry-vuln-030

OrganizationPreprodArtifactApprove is missing has_project_access.

getsentry/sentry@9fc06de579fbView source

preprod_artifact_approve.py:37-49
@cell_silo_endpoint
class OrganizationPreprodArtifactApproveEndpoint(OrganizationEndpoint):
owner = ApiOwner.EMERGE_TOOLS
publish_status = {
"POST": ApiPublishStatus.EXPERIMENTAL,
}
permission_classes = (OrganizationReleasePermission,)
def post(self, request: Request, organization: Organization, artifact_id: str) -> Response:
feature_type_str = request.data.get("feature_type")
if feature_type_str not in FEATURE_TYPE_MAP:
return Response(
{"detail": f"feature_type must be one of: {', '.join(FEATURE_TYPE_MAP.keys())}"},

sentry-vuln-031

Public preprod size analysis misses has_project_access on head and base artifacts.

getsentry/sentry@9fc06de579fbView source

organization_preprod_size_analysis.py:107-119
"""
Retrieve size analysis results for a given artifact.
Returns size metrics including download size, install size, and optional insights.
When a base artifact exists (either from commit comparison or via the `baseArtifactId` parameter),
comparison data showing size differences is included.
The response `state` field indicates the analysis status:
- `PENDING`: Analysis has not started yet.
- `PROCESSING`: Analysis is currently running.
- `FAILED` / `NOT_RAN`: Analysis did not complete; `errorCode` and `errorMessage` are included.
- `COMPLETED`: Analysis finished successfully with full size data.
"""

sentry-vuln-032

ProjectKey RPC service drops organization_id; a reachable AWS Lambda integration config path can leak cross-org DSN material.

getsentry/sentry@7f41cc502faaView source

impl.py:19-31
return None
def get_project_key(
self, organization_id: int, project_id: int, role: ProjectKeyRole
) -> RpcProjectKey | None:
return self._get_project_key(project_id=project_id, role=role)
def get_default_project_key(
self, *, organization_id: int, project_id: int
) -> RpcProjectKey | None:
try:
project = Project.objects.get_from_cache(id=project_id)

sentry-vuln-033

replay_counts issue.id branch overwrites snuba_params.projects, bypassing project access scoping.

getsentry/sentry@9fc06de579fbView source

replay_counts.py:115-125
if select_column == "replay_id":
# just return a mapping of replay_id:replay_id instead of hitting the dataset.
identity_map = {}
for replay_id in column_value:
# raises ValueError if invalid. Strips '-'
replay_id = uuid.UUID(hex=replay_id, version=4).hex
identity_map[replay_id] = [replay_id]
return identity_map
# The client may or may not have narrowed the request by project-id. We have a

sentry-vuln-034

Seer autofix run_id is not bound to group in handoff and continue paths.

getsentry/sentry@9fc06de579fbView source

autofix_agent.py:523-533
"""
if not group.organization.get_option(
"sentry:enable_seer_coding", default=ENABLE_SEER_CODING_DEFAULT
):
raise PermissionDenied("Code generation is disabled for this organization")
auto_create_pr = False
repo_definitions: list[SeerRepoDefinition] = []
if features.has("organizations:seer-project-settings-read-from-sentry", group.organization):
preference = read_preference_from_sentry_db(group.project)
repo_definitions = preference.repositories

sentry-vuln-035

Autofix automation settings GET bypasses get_projects, returning settings for inaccessible projects.

getsentry/sentry@9fc06de579fbView source

organization_autofix_automation_settings.py:222-234
def get(self, request: Request, organization: Organization) -> Response:
"""
List projects with their autofix automation settings.
:pparam string organization_id_or_slug: the id or slug of the organization.
:qparam string query: Optional search query to filter by project name or slug.
:auth: required
"""
serializer = SeerAutofixSettingGetResponseSerializer(
data={
"query": request.GET.get("query"),
}

sentry-vuln-036

Supergroups validates org but skips has_project_access on supplied group IDs.

getsentry/sentry@9fc06de579fbView source

organization_supergroups_by_group.py:34-44
permission_classes = (OrganizationSupergroupsByGroupPermission,)
def get(self, request: Request, organization: Organization) -> Response:
if not features.has("organizations:top-issues-ui", organization, actor=request.user):
return Response({"detail": "Feature not available"}, status=403)
raw_group_ids = request.GET.getlist("group_id")
try:
group_ids = [int(gid) for gid in raw_group_ids]
except ValueError:
return Response(

sentry-vuln-037

Sentry App cell service makes user optional, dropping has_project_access for live callers.

getsentry/sentry@9fc06de579fbView source

impl.py:39-49
class DatabaseBackedSentryAppCellService(SentryAppCellService):
def get_select_options(
self,
*,
organization_id: int,
installation: RpcSentryAppInstallation,
uri: str,
user: RpcUser | None = None,
project_id: int | None = None,
query: str | None = None,

sentry-vuln-038

GroupEventJsonView checks org scope but not project access before returning event JSON.

getsentry/sentry@9fc06de579fbView source

installation_external_issue_actions.py:22-24
@control_silo_endpoint
class SentryAppInstallationExternalIssueActionsEndpoint(SentryAppInstallationBaseEndpoint):

sentry-vuln-039

Open periods endpoint resolves detector/group with org-only scope and no has_project_access.

getsentry/sentry@9fc06de579fbView source

organization_open_periods.py:42-52
permission_classes = (OrganizationDetectorPermission,)
def get_group_from_detector_id(
self, detector_id: str, organization: Organization
) -> Group | None:
validated_detector_id = to_valid_int_id("detectorId", detector_id)
try:
detector = (
Detector.objects.with_type_filters()
.select_related("project")
.get(id=validated_detector_id)

sentry-vuln-040

Workflow detector disconnect skips per-project permission checks on removed connections.

getsentry/sentry@9fc06de579fbView source

utils.py:113-122
def can_edit_detector_workflow_connections(detector: Detector, request: Request) -> bool:
"""
Anyone with alert write access to the project can connect/disconnect detectors of any type,
which is slightly different from full edit access which differs by detector type.
"""
return request.access.has_any_project_scope(
detector.project, USER_CREATED_DETECTOR_REQUIRED_SCOPES
)

sentry-vuln-041

DiscoverSavedQueryVisitEndpoint.post skips check_object_permissions.

getsentry/sentry@9fc06de579fbView source

discover_saved_query_detail.py:170-182
@cell_silo_endpoint
class DiscoverSavedQueryVisitEndpoint(DiscoverSavedQueryBase):
publish_status = {
"POST": ApiPublishStatus.PRIVATE,
}
def has_feature(self, organization, request):
return features.has("organizations:discover-query", organization, actor=request.user)
def post(self, request: Request, organization, query) -> Response:
"""
Update last_visited and increment visits counter
"""

sentry-vuln-042

InsightsStarredSegment stores user-supplied project_id without org or project access validation.

getsentry/sentry@9fc06de579fbView source

action.py:131-141
def get_rule(
slack_request: SlackActionRequest, organization: Organization, group_type: int
) -> Rule | None:
from sentry.notifications.notification_action.utils import should_fire_workflow_actions
"""Get the rule that fired"""
rule_id = slack_request.callback_data.get("rule")
if not rule_id:
return None

sentry-vuln-043

InternalRegisteredTemplatesEndpoint is reachable by any authenticated user instead of superuser only.

getsentry/sentry@9fc06de579fbView source

internal_registered_templates.py:22-32
@control_silo_endpoint
class InternalRegisteredTemplatesEndpoint(Endpoint):
owner = ApiOwner.ECOSYSTEM
permission_classes = (SentryIsAuthenticated,)
publish_status = {"GET": ApiPublishStatus.PRIVATE}
def get(self, request: Request) -> Response:
response: dict[str, list[dict[str, Any]]] = defaultdict(list)
for source, template_cls in template_registry.registrations.items():

sentry-vuln-044

AuthIndexEndpoint.put fail-opens superuser reauth when SaaS runs with SUPERUSER_ORG_ID=None.

getsentry/sentry@6993246259d0View source

auth_index.py:258-273
validator = AuthVerifyValidator(data=request.data)
if not (request.user.is_superuser and request.data.get("isSuperuserModal")):
try:
validator.is_valid(raise_exception=True)
except ValidationError:
return Response({"detail": {"code": MISSING_PASSWORD_OR_U2F_CODE}}, status=400)
authenticated = self._verify_user_via_inputs(validator, request)
else:
verify_authenticator = False
if not DISABLE_SSO_CHECK_FOR_LOCAL_DEV and not is_self_hosted():
if SUPERUSER_ORG_ID:
verify_authenticator = organization_service.check_organization_by_id(
id=SUPERUSER_ORG_ID, only_visible=False

sentry-vuln-045

Public preprod install-details resolves artifact by org and returns metadata plus install URLs without project access.

getsentry/sentry@7f41cc502faaView source

organization_seer_rpc.py:216-218
# Check if this is an org-level method
if method_name in public_org_seer_method_registry:

sentry-vuln-046

Pull-request size-analysis download resolves artifact by org and streams raw size-analysis JSON without project access.

getsentry/sentry@7f41cc502faaView source

organization_pullrequest_size_analysis_download.py:59-71
artifact = PreprodArtifact.objects.get(
id=int(artifact_id),
project__organization_id=organization.id,
)
except (PreprodArtifact.DoesNotExist, ValueError):
raise PreprodArtifactResourceDoesNotExist
cutoff = get_size_retention_cutoff(organization)
if artifact.date_added < cutoff:
return Response({"detail": "This build's size data has expired."}, status=404)
all_size_metrics = list(artifact.get_size_metrics())

sentry-vuln-047

WorkflowEngineRuleEndpoint authorizes URL project but resolves workflow-backed rules by org and rule or workflow ID.

getsentry/sentry@7f41cc502faaView source

project_rule_details.py:101-103
@extend_schema(tags=["Alerts"])
@cell_silo_endpoint
class ProjectRuleDetailsEndpoint(WorkflowEngineRuleEndpoint):

sentry-vuln-048

Project size-analysis comparison download authorizes URL project but resolves comparisons by org and metric IDs only.

getsentry/sentry@7f41cc502faaView source

project_preprod_size_analysis_compare_download.py:67-79
comparison_obj = PreprodArtifactSizeComparison.objects.select_related(
"head_size_analysis__preprod_artifact",
"base_size_analysis__preprod_artifact",
).get(
head_size_analysis_id=head_size_metric_id,
base_size_analysis_id=base_size_metric_id,
organization_id=project.organization_id,
)
except PreprodArtifactSizeComparison.DoesNotExist:
logger.info(
"preprod.size_analysis.compare.api.download.no_comparison_obj",
extra={
"head_size_metric_id": head_size_metric_id,

sentry-vuln-049

GitHub install flow accepts unknown installation IDs before trusted webhook sender validation.

getsentry/sentry@7f41cc502faaView source

organization_pipeline.py:140-142
# has data (e.g. installation_id from a GitHub redirect) that needs
# to be available to pipeline steps.
serializer_cls = pipeline.provider.get_initial_data_serializer_cls()

sentry-vuln-050

CODEOWNERS code-mapping GET resolves config by org and returns raw CODEOWNERS without checking config.project.

getsentry/sentry@7f41cc502faaView source

projectcodeowners.py:80-86
def serialize(self, obj, attrs, user, **kwargs):
from sentry.api.validators.project_codeowners import build_codeowners_associations
data = {
"id": str(obj.id),
"raw": obj.raw,
"dateCreated": obj.date_added,

sentry-vuln-053

Sentry App external issue actions accept org:integrations without the event scope used by sibling endpoints.

getsentry/sentry@7f41cc502faaView source

installation_external_issue_actions.py:22-24
@control_silo_endpoint
class SentryAppInstallationExternalIssueActionsEndpoint(SentryAppInstallationBaseEndpoint):

sentry-vuln-055

Public org-level Seer RPC methods can query project-backed data without applying the caller's project access.

getsentry/sentry@7f41cc502faaView source

organization_seer_rpc.py:216-218
# Check if this is an org-level method
if method_name in public_org_seer_method_registry:

sentry-vuln-056

API authorization listing can expose a fresh OAuth app clientSecret to non-owner grantees during the reveal window.

getsentry/sentry@7f41cc502faaView source

apiapplication.py:9-11
@register(ApiApplication)
class ApiApplicationSerializer(Serializer):
def serialize(self, obj, attrs, user, **kwargs):

sentry-vuln-058

Detector anomaly-data endpoint resolves detectors or alert rules by org and returns Seer data without project access.

getsentry/sentry@7f41cc502faaView source

organization_detector_anomaly_data.py:30-32
@extend_schema(tags=["Workflows"])
@cell_silo_endpoint
class OrganizationDetectorAnomalyDataEndpoint(OrganizationEndpoint):

sentry-vuln-059

AlertRuleDetector lookup returns detector, alert-rule, and rule mappings without filtering by accessible projects.

getsentry/sentry@7f41cc502faaView source

organization_alertrule_detector_index.py:35-37
}
owner = ApiOwner.ISSUES
permission_classes = (OrganizationDetectorPermission,)

sentry-vuln-060

Newline-capable PR filenames can inject or override $GITHUB_OUTPUT values forwarded to getsentry workflow dispatch.

getsentry/sentry@7f41cc502faaView source

getsentry-dispatch.yml:54-56
GH_TOKEN: ${{ github.token }}
run: |
gh api repos/${{ github.repository }}/pulls/${{ github.event.number }}/files \

sentry-vuln-061

Branch name is shell-interpolated in scripts/analyze-styled.ts history analysis commands.

getsentry/sentry@7f41cc502faaView source

analyze-styled.ts:1372-1374
logger.debug('Script not found in commit, copying from current version...');
// Get the current script content and write it temporarily
child_process.execSync(

sentry-vuln-069

Atlassian install JWT verification accepts the algorithm from the unverified token header.

getsentry/sentry@7f41cc502faaView source

atlassian_connect.py:123-125
if token is None:
raise AtlassianConnectValidationError("No token parameter")
headers = jwt.peek_header(token)

sentry-vuln-075

Mailgun timestamp and nonce are signed but never freshness- or reuse-checked.

getsentry/sentry@7f41cc502faaView source

mailgun_inbound_webhook.py:24-26
@control_silo_view
class MailgunInboundWebhookView(View):
def verify(self, api_key, token, timestamp, signature):

sentry-vuln-082

ECharts tooltip interpolates feature flag name and action as HTML.

getsentry/sentry@7f41cc502faaView source

useFlagSeries.tsx:61-63
'Feature Flag'
)}</strong></span></div>`,
`<span class="tooltip-label-align-start"><code class="tooltip-code-no-margin">${data.name}</code>${data.label.formatter()}</span>`,

sentry-vuln-084

ECharts tooltip renders mobile build seriesName from artifact metadata as HTML.

getsentry/sentry@7f41cc502faaView source

mobileBuildsChart.tsx:247-249
const value = (param.value as number[])[1]!;
const marker = typeof param.marker === 'string' ? param.marker : '';
return `<div><span class="tooltip-label">${marker}<strong>${param.seriesName}</strong></span> ${formatBytesBase10(value)}</div>`;

sentry-vuln-085

ECharts treemap tooltip renders uploaded artifact path and name as HTML.

getsentry/sentry@7f41cc502faaView source

appSizeTreemap.tsx:424-426
const percent = ((value / totalSize) * 100).toFixed(2);
const pathHtml = params.data?.path
? `<div style="font-size: 12px; color: ${theme.tokens.content.secondary}; line-height: 1.2;">${params.data.path}</div>`
  • Backfill exact vulnerable SHAs from original tickets, fix commits, or raw run logs.
  • Add excluded candidate or latent findings only after they are confirmed as exploitable vulnerabilities in getsentry/sentry.