fix(security): add read:user scope to Gitea; fail-closed on absent Google verified_email

Gitea's /api/v1/user/emails endpoint requires the read:user granular
scope — openid+email+profile alone is insufficient and __get_email()
would return a 401/403. Add read:user to the scope string.

Google: change default from True to fail-closed (is not True) so a
userinfo response that omits verified_email is rejected rather than
trusted. The service-account justification was incorrect — service
accounts do not go through the interactive OAuth2 callback flow.

Co-authored-by: Plane AI <noreply@plane.so>
This commit is contained in:
Manish Gupta
2026-06-24 12:47:16 +05:30
parent 36cef21b05
commit 3daec9476b
2 changed files with 4 additions and 4 deletions

View File

@@ -19,7 +19,7 @@ from plane.authentication.adapter.error import (
class GiteaOAuthProvider(OauthAdapter):
provider = "gitea"
scope = "openid email profile"
scope = "openid email profile read:user"
def __init__(self, request, code=None, state=None, callback=None):
(GITEA_CLIENT_ID, GITEA_CLIENT_SECRET, GITEA_HOST) = get_configuration_value(

View File

@@ -103,9 +103,9 @@ class GoogleOAuthProvider(OauthAdapter):
def set_user_data(self):
user_info_response = self.get_user_response()
# Reject unverified emails — an attacker-controlled provider could otherwise assert
# any email to match an existing account (GHSA-7j95-vh8g-f365). Default True so
# service accounts that omit the field are not broken.
if not user_info_response.get("verified_email", True):
# any email to match an existing account (GHSA-7j95-vh8g-f365). Fail closed: treat
# an absent verified_email claim the same as verified_email=false.
if user_info_response.get("verified_email") is not True:
raise AuthenticationException(
error_code=AUTHENTICATION_ERROR_CODES["OAUTH_PROVIDER_UNVERIFIED_EMAIL"],
error_message="OAUTH_PROVIDER_UNVERIFIED_EMAIL",