Skip to content

Bug: GitHub login flow can silently merge accounts via email reuse without verifying ownership of pre-existing local account #568

@hariom888

Description

@hariom888

In apps/backend/src/routes/auth.ts, the GitHub OAuth callback (and the equivalent Google callback) handles the "no userIdentity found" case by looking up existingAccount by email and, if found, attaches the new provider identity to that account:

const existingAccount = await app.prisma.user.findUnique({ where: { email } });

if (existingAccount) {
  await app.prisma.userIdentity.create({
    data: { userId: existingAccount.id, provider: 'github', providerId: githubUser.id.toString() }
  });
  user = existingAccount;
}

For GitHub, email is derived from githubUser.email or, if null, the first primary && verified entry from /user/emails. The verified-email check on GitHub's side is trusted implicitly. However, there's a deeper issue: this account-linking happens with no re-authentication or confirmation step from the existing account owner. Any user who can get GitHub to report a given verified email (e.g. via GitHub's email-visibility settings, or a GitHub account where they've added/verified an email that matches a DevCard user's email — GitHub allows adding emails and they become "verified" once the GitHub-side confirmation email is clicked, which an attacker can do for emails they control or, in cases of stale/abandoned email addresses, emails they've taken over) can have their userIdentity silently attached to an arbitrary pre-existing DevCard account matching that email.

Once linked, that GitHub account becomes a permanent additional login method for the victim's DevCard account (issuing fresh accessToken/refreshToken cookies for existingAccount.id), with no notification email, no audit log entry distinguishable from normal login, and no requirement that the user prove control of the DevCard account being linked (e.g. by being logged in already, or confirming via the original auth method).

This is an account-takeover-via-identity-linking pattern: the trust boundary between "I proved I own this email on GitHub right now" and "therefore I should be granted standing access to whatever DevCard account already used that email" is not validated against the current session state of the DevCard account.

Affected: apps/backend/src/routes/auth.ts — both github/callback and google/callback handlers, in the else branch following the if (identity) check (the existingAccount lookup-and-link block).

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions