Skip to content

Conversation

@vgrozdanic
Copy link
Member

@vgrozdanic vgrozdanic commented Nov 12, 2025

Cleans up identity.prevent-link-identity-for-demo-users.enabled option which was introduce to stop the leak for the #inc-1373

The proper fix has been implemented in the mean time, and this quick fix is no longer required.

Part of TET-1350

@vgrozdanic vgrozdanic requested a review from a team as a code owner November 12, 2025 11:08
@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Nov 12, 2025
@linear
Copy link

linear bot commented Nov 12, 2025

@vgrozdanic vgrozdanic requested a review from a team November 12, 2025 11:09
Comment on lines 89 to 94
the case where the user is linked to a different identity or the
identity is linked to a different user.
"""
# NOTE(vgrozdanic): temporary fix for #inc-1373 to stop the bleed
if is_demo_user(user) and options.get(
"identity.prevent-link-identity-for-demo-users.enabled"
):
logger.warning(
"Preventing link identity for demo user",
extra={"user_id": user.id, "idp_id": idp.id, "external_id": external_id},
stack_info=True,
)
return None

from sentry.integrations.slack.analytics import SlackIntegrationIdentityLinked

defaults = {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Demo users can link identities via non-SSO paths due to insufficient is_demo_user checks.
Severity: CRITICAL | Confidence: 0.95

🔍 Detailed Analysis

The removal of the identity.prevent-link-identity-for-demo-users.enabled check allows demo users to link identities through non-SSO code paths. The new check in _handle_membership() only protects the SSO auth flow, leaving Identity Pipeline and Integration Pipeline vulnerable. These pipelines directly call Identity.objects.link_identity() or Identity.objects.update_external_id_and_defaults() without checking if the user is a demo user, potentially reintroducing the leak mentioned in issue #inc-1373.

💡 Suggested Fix

Re-implement a comprehensive is_demo_user check across all identity linking code paths, specifically in Identity Pipeline and Integration Pipeline, to prevent demo users from linking identities.

🤖 Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: src/sentry/users/models/identity.py#L89-L94

Potential issue: The removal of the
`identity.prevent-link-identity-for-demo-users.enabled` check allows demo users to link
identities through non-SSO code paths. The new check in `_handle_membership()` only
protects the SSO auth flow, leaving `Identity Pipeline` and `Integration Pipeline`
vulnerable. These pipelines directly call `Identity.objects.link_identity()` or
`Identity.objects.update_external_id_and_defaults()` without checking if the user is a
demo user, potentially reintroducing the leak mentioned in [issue
#inc-1373](https://sentry.sentry.io/issues/inc-1373).

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Demo Users Bypass Identity Link Protection

Removing demo user checks from link_identity, create_identity, reattach, and update_external_id_and_defaults exposes unprotected identity linking flows. While the proper fix in auth/helper.py prevents demo users from joining organizations via SSO auth providers, these Identity manager methods are also called from integration pipelines, social auth pipelines, and messaging integration linking flows that don't go through auth/helper.py. Demo users can now link identities through these alternative paths.

src/sentry/users/models/identity.py#L81-L119

user: User | RpcUser,
idp: IdentityProvider | RpcIdentityProvider,
external_id: str,
should_reattach: bool = True,
defaults: Mapping[str, Any | None] | None = None,
) -> Identity | None:
"""
Link the user with the identity. If `should_reattach` is passed, handle
the case where the user is linked to a different identity or the
identity is linked to a different user.
"""
from sentry.integrations.slack.analytics import SlackIntegrationIdentityLinked
defaults = {
**(defaults or {}),
"status": IdentityStatus.VALID,
"date_verified": timezone.now(),
}
try:
identity, created = self.get_or_create(
idp_id=idp.id, user_id=user.id, external_id=external_id, defaults=defaults
)
if not created:
identity.update(**defaults)
except IntegrityError:
if not should_reattach:
raise
return self.reattach(idp, external_id, user, defaults)
analytics.record(
SlackIntegrationIdentityLinked(
provider=IntegrationProviderSlug.SLACK.value,
# Note that prior to circa March 2023 this was user.actor_id. It changed
# when actor ids were no longer stable between regions for the same user
actor_id=user.id,
actor_type="user",
)
)
return identity

Fix in Cursor Fix in Web


@vgrozdanic vgrozdanic merged commit 06235b4 into master Nov 12, 2025
69 checks passed
@vgrozdanic vgrozdanic deleted the vg/clean-up-identity-link-option branch November 12, 2025 14:36
Jesse-Box pushed a commit that referenced this pull request Nov 12, 2025
Cleans up `identity.prevent-link-identity-for-demo-users.enabled` option
which was introduce to stop the leak for the #inc-1373

The proper fix has been implemented in the mean time, and this quick fix
is no longer required.

Part of TET-1350
andrewshie-sentry pushed a commit that referenced this pull request Nov 13, 2025
Cleans up `identity.prevent-link-identity-for-demo-users.enabled` option
which was introduce to stop the leak for the #inc-1373

The proper fix has been implemented in the mean time, and this quick fix
is no longer required.

Part of TET-1350
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Backend Automatically applied to PRs that change backend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants