Critical severity9.1GHSA Advisory· Published May 8, 2026· Updated May 13, 2026
CVE-2026-42354
CVE-2026-42354
Description
Sentry is an error tracking and performance monitoring tool. From version 21.12.0 to before version 26.4.1, a critical vulnerability was discovered in the SAML SSO implementation of Sentry. The vulnerability allows an attacker to take over any user account by using a malicious SAML Identity Provider and another organization on the same Sentry instance. The victim email address must be known in order to exploit this vulnerability. This issue has been patched in version 26.4.1.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
sentryPyPI | >= 21.12.0, < 26.4.1 | 26.4.1 |
Affected products
1Patches
10c67558ae7fefix(auth): Pin SSO setup identity link to the authenticated session (#113720)
2 files changed · +94 −1
src/sentry/auth/helper.py+5 −1 modified@@ -1017,7 +1017,11 @@ def _finish_setup_pipeline(self, identity: Mapping[str, Any]) -> HttpResponseRed organization_id=self.organization.id, provider=self.provider.key, config=config ) - self.auth_handler(identity).handle_attach_identity(om) + # The setup flow should always link the identity to the admin who is + # performing setup, so override the email to ensure resolve_email_to_user + # returns the authenticated user rather than whoever the IdP asserted. + setup_identity = {**identity, "email": request.user.email} + self.auth_handler(setup_identity).handle_attach_identity(om) auth.mark_sso_complete(request, self.organization.id)
tests/sentry/auth/test_helper.py+89 −0 modified@@ -6,6 +6,7 @@ from django.contrib.auth.models import AnonymousUser from django.db import IntegrityError, models, router, transaction from django.http import HttpResponseRedirect +from django.http.response import HttpResponseBase from django.test import Client, RequestFactory from sentry import audit_log @@ -829,6 +830,94 @@ def test_no_provider_key_continues_normally(self, mock_messages: mock.MagicMock) assert "SSO" not in str(call) +@control_silo_test +class SetupPipelineIdentityLinkingTest(TestCase, HybridCloudTestMixin): + """Tests that the SSO setup pipeline always links the identity to the authenticated admin.""" + + def setUp(self) -> None: + super().setUp() + self.provider = "dummy" + self.admin_user = self.create_user(email="admin@example.com") + self.create_member(organization=self.organization, user=self.admin_user, role="owner") + + self.auth_key = "test_auth_key" + self.request = _set_up_request() + self.request.user = self.admin_user + self.request.session["auth_key"] = self.auth_key + + def _run_setup_pipeline_with_identity_email(self, identity_email: str) -> HttpResponseBase: + """Run the setup pipeline with a given email in the IdP assertion.""" + initial_state = { + "org_id": self.organization.id, + "flow": FLOW_SETUP_PROVIDER, + "provider_model_id": None, + "provider_key": self.provider, + "referrer": None, + } + local_client = clusters.get("default").get_local_client_for_key(self.auth_key) + local_client.set(self.auth_key, json.dumps(initial_state)) + + helper = AuthHelper.get_for_request(self.request) + assert helper is not None + helper.initialize() + + helper.bind_state("email", identity_email) + helper.bind_state("email_verified", True) + + helper.state.step_index = len(helper.pipeline_views) + result = helper.current_step() + return result + + @mock.patch("sentry.auth.helper.messages") + def test_setup_links_to_admin_when_assertion_email_differs( + self, mock_messages: mock.MagicMock + ) -> None: + """When the IdP assertion email belongs to a different org member, + the identity is still linked to the admin performing setup.""" + other_user = self.create_user(email="other@example.com") + self.create_member(organization=self.organization, user=other_user) + + result = self._run_setup_pipeline_with_identity_email("other@example.com") + + assert result.status_code == 302 + + auth_provider = AuthProvider.objects.get( + organization_id=self.organization.id, provider=self.provider + ) + auth_identity = AuthIdentity.objects.get(auth_provider=auth_provider) + assert auth_identity.user_id == self.admin_user.id + assert not AuthIdentity.objects.filter(user_id=other_user.id).exists() + + @mock.patch("sentry.auth.helper.messages") + def test_setup_links_to_admin_when_emails_match(self, mock_messages: mock.MagicMock) -> None: + """Setup succeeds normally when the IdP assertion email matches the admin.""" + result = self._run_setup_pipeline_with_identity_email("admin@example.com") + + assert result.status_code == 302 + + auth_provider = AuthProvider.objects.get( + organization_id=self.organization.id, provider=self.provider + ) + auth_identity = AuthIdentity.objects.get(auth_provider=auth_provider) + assert auth_identity.user_id == self.admin_user.id + + @mock.patch("sentry.auth.helper.messages") + def test_setup_links_to_admin_when_email_matches_no_user( + self, mock_messages: mock.MagicMock + ) -> None: + """When the IdP returns an email that doesn't match any Sentry user, + the identity is still linked to the admin.""" + result = self._run_setup_pipeline_with_identity_email("unknown@nowhere.com") + + assert result.status_code == 302 + + auth_provider = AuthProvider.objects.get( + organization_id=self.organization.id, provider=self.provider + ) + auth_identity = AuthIdentity.objects.get(auth_provider=auth_provider) + assert auth_identity.user_id == self.admin_user.id + + @control_silo_test class InactiveUserIdentityTest(AuthIdentityHandlerTest): """Tests that inactive-user AuthIdentity always routes through handle_unknown_identity."""
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-rcmw-7mc7-3rj7ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-42354ghsaADVISORY
- github.com/getsentry/sentry/commit/0c67558ae7fe08738912d4c5233b53ead048da3bnvdWEB
- github.com/getsentry/sentry/pull/113720nvdWEB
- github.com/getsentry/sentry/releases/tag/26.4.1nvdWEB
- github.com/getsentry/sentry/security/advisories/GHSA-rcmw-7mc7-3rj7nvdWEB
News mentions
1- The AI engineering stack we built internally — on the platform we shipCloudflare Blog · Apr 20, 2026