Skip to content

Conversation

@cursor
Copy link
Contributor

@cursor cursor bot commented Nov 19, 2025

This PR fixes an XSS vulnerability by hardening OAuth2 login and callback views to prevent the premature processing and rendering of untrusted error query parameters.

Previously, the presence of code, error, or state in the query parameters would immediately trigger callback logic, allowing a malicious error parameter to be rendered unescaped without proper OAuth state validation.

The changes ensure that:

  1. OAuth2LoginView and OAuth2CallbackView now strictly validate the state parameter against the stored pipeline state before processing any other callback parameters, including error.
  2. If the state is missing or mismatched, the pipeline immediately short-circuits with a generic validation error, preventing any untrusted error payloads from reaching the UI.
  3. Only after successful state validation will the error parameter from the OAuth provider be considered, ensuring that any displayed errors originate from a trusted source.

This prevents attackers from injecting and rendering arbitrary content via the error query parameter.

Legal Boilerplate

Look, I get it. The entity doing business as "Sentry" was incorporated in the State of Delaware in 2015 as Functional Software, Inc. and is gonna need some rights from me in order to utilize my contributions in this here PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Sentry can use, modify, copy, and redistribute my contributions, under Sentry's choice of terms.


Open in Cursor Open in Web

Co-authored-by: jenn.muengtaweepongsa <jenn.muengtaweepongsa@sentry.io>
@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Nov 19, 2025
@codecov
Copy link

codecov bot commented Nov 19, 2025

❌ 11 Tests Failed:

Tests completed Failed Passed Skipped
29875 11 29864 244
View the top 3 failed test(s) by shortest run time
tests.sentry.integrations.vercel.test_integration.VercelIntegrationTest::test_user_flow
Stack Traces | 1.93s run time
#x1B[1m#x1B[.../integrations/vercel/test_integration.py#x1B[0m:116: in test_user_flow
    self.assert_setup_flow(is_team=False)
#x1B[1m#x1B[.../integrations/vercel/test_integration.py#x1B[0m:79: in assert_setup_flow
    mock_request = responses.calls[0].request
#x1B[1m#x1B[31m.venv/lib/python3.13.../site-packages/responses/__init__.py#x1B[0m:242: in __getitem__
    return self._calls[idx]
#x1B[1m#x1B[31mE   IndexError: list index out of range#x1B[0m
tests.sentry.web.frontend.test_vercel_extension_configuration.VercelExtensionConfigurationTest::test_logged_in_one_org
Stack Traces | 1.99s run time
#x1B[1m#x1B[.../web/frontend/test_vercel_extension_configuration.py#x1B[0m:65: in test_logged_in_one_org
    mock_request = responses.calls[0].request
#x1B[1m#x1B[31m.venv/lib/python3.13.../site-packages/responses/__init__.py#x1B[0m:242: in __getitem__
    return self._calls[idx]
#x1B[1m#x1B[31mE   IndexError: list index out of range#x1B[0m
tests.sentry.web.frontend.test_vercel_extension_configuration.VercelExtensionConfigurationTest::test_logged_in_one_org_customer_domain
Stack Traces | 2.08s run time
#x1B[1m#x1B[.../web/frontend/test_vercel_extension_configuration.py#x1B[0m:165: in test_logged_in_one_org_customer_domain
    mock_request = responses.calls[0].request
#x1B[1m#x1B[31m.venv/lib/python3.13.../site-packages/responses/__init__.py#x1B[0m:242: in __getitem__
    return self._calls[idx]
#x1B[1m#x1B[31mE   IndexError: list index out of range#x1B[0m
tests.sentry.integrations.vercel.test_integration.VercelIntegrationTest::test_no_name
Stack Traces | 2.08s run time
#x1B[1m#x1B[.../integrations/vercel/test_integration.py#x1B[0m:120: in test_no_name
    self.assert_setup_flow(no_name=True)
#x1B[1m#x1B[.../integrations/vercel/test_integration.py#x1B[0m:79: in assert_setup_flow
    mock_request = responses.calls[0].request
#x1B[1m#x1B[31m.venv/lib/python3.13.../site-packages/responses/__init__.py#x1B[0m:242: in __getitem__
    return self._calls[idx]
#x1B[1m#x1B[31mE   IndexError: list index out of range#x1B[0m
tests.sentry.integrations.vercel.test_integration.VercelIntegrationTest::test_update_org_config_vars_exist
Stack Traces | 2.08s run time
#x1B[1m#x1B[.../integrations/vercel/test_integration.py#x1B[0m:253: in test_update_org_config_vars_exist
    self.assert_setup_flow()
#x1B[1m#x1B[.../integrations/vercel/test_integration.py#x1B[0m:79: in assert_setup_flow
    mock_request = responses.calls[0].request
#x1B[1m#x1B[31m.venv/lib/python3.13.../site-packages/responses/__init__.py#x1B[0m:242: in __getitem__
    return self._calls[idx]
#x1B[1m#x1B[31mE   IndexError: list index out of range#x1B[0m
tests.sentry.integrations.vercel.test_integration.VercelIntegrationTest::test_upgrade_org_config_no_dsn
Stack Traces | 2.1s run time
#x1B[1m#x1B[.../integrations/vercel/test_integration.py#x1B[0m:378: in test_upgrade_org_config_no_dsn
    self.assert_setup_flow()
#x1B[1m#x1B[.../integrations/vercel/test_integration.py#x1B[0m:79: in assert_setup_flow
    mock_request = responses.calls[0].request
#x1B[1m#x1B[31m.venv/lib/python3.13.../site-packages/responses/__init__.py#x1B[0m:242: in __getitem__
    return self._calls[idx]
#x1B[1m#x1B[31mE   IndexError: list index out of range#x1B[0m
tests.sentry.integrations.vercel.test_integration.VercelIntegrationTest::test_team_flow
Stack Traces | 2.12s run time
#x1B[1m#x1B[.../integrations/vercel/test_integration.py#x1B[0m:112: in test_team_flow
    self.assert_setup_flow(is_team=True)
#x1B[1m#x1B[.../integrations/vercel/test_integration.py#x1B[0m:79: in assert_setup_flow
    mock_request = responses.calls[0].request
#x1B[1m#x1B[31m.venv/lib/python3.13.../site-packages/responses/__init__.py#x1B[0m:242: in __getitem__
    return self._calls[idx]
#x1B[1m#x1B[31mE   IndexError: list index out of range#x1B[0m
tests.sentry.integrations.vercel.test_integration.VercelIntegrationTest::test_uninstall
Stack Traces | 2.13s run time
#x1B[1m#x1B[.../integrations/vercel/test_integration.py#x1B[0m:408: in test_uninstall
    self.assert_setup_flow()
#x1B[1m#x1B[.../integrations/vercel/test_integration.py#x1B[0m:79: in assert_setup_flow
    mock_request = responses.calls[0].request
#x1B[1m#x1B[31m.venv/lib/python3.13.../site-packages/responses/__init__.py#x1B[0m:242: in __getitem__
    return self._calls[idx]
#x1B[1m#x1B[31mE   IndexError: list index out of range#x1B[0m
tests.sentry.integrations.vercel.test_integration.VercelIntegrationTest::test_update_organization_config
Stack Traces | 2.27s run time
#x1B[1m#x1B[.../integrations/vercel/test_integration.py#x1B[0m:142: in test_update_organization_config
    self.assert_setup_flow()
#x1B[1m#x1B[.../integrations/vercel/test_integration.py#x1B[0m:79: in assert_setup_flow
    mock_request = responses.calls[0].request
#x1B[1m#x1B[31m.venv/lib/python3.13.../site-packages/responses/__init__.py#x1B[0m:242: in __getitem__
    return self._calls[idx]
#x1B[1m#x1B[31mE   IndexError: list index out of range#x1B[0m
tests.sentry.integrations.vercel.test_integration.VercelIntegrationTest::test_get_dynamic_display_information
Stack Traces | 2.36s run time
#x1B[1m#x1B[.../integrations/vercel/test_integration.py#x1B[0m:396: in test_get_dynamic_display_information
    self.assert_setup_flow()
#x1B[1m#x1B[.../integrations/vercel/test_integration.py#x1B[0m:79: in assert_setup_flow
    mock_request = responses.calls[0].request
#x1B[1m#x1B[31m.venv/lib/python3.13.../site-packages/responses/__init__.py#x1B[0m:242: in __getitem__
    return self._calls[idx]
#x1B[1m#x1B[31mE   IndexError: list index out of range#x1B[0m
tests.sentry.integrations.vercel.test_integration.VercelIntegrationTest::test_use_existing_installation
Stack Traces | 2.86s run time
#x1B[1m#x1B[.../integrations/vercel/test_integration.py#x1B[0m:135: in test_use_existing_installation
    self.assert_setup_flow(is_team=False)
#x1B[1m#x1B[.../integrations/vercel/test_integration.py#x1B[0m:79: in assert_setup_flow
    mock_request = responses.calls[0].request
#x1B[1m#x1B[31m.venv/lib/python3.13.../site-packages/responses/__init__.py#x1B[0m:242: in __getitem__
    return self._calls[idx]
#x1B[1m#x1B[31mE   IndexError: list index out of range#x1B[0m

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

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.

2 participants