Skip to content

oauth.py: GitHub email-fetch silently picks first primary, doesn't filter to verified #28

Description

@drapre
if provider.name == "github":
    email = None
    email_resp = await client.get(
        "https://api.github.com/user/emails", headers=headers
    )
    if email_resp.status_code == 200:
        emails = email_resp.json()
        primary = next((e for e in emails if e.get("primary")), None)
        email = primary["email"] if primary else None

(src/fim_one/web/oauth.py:172-183)

GitHub's /user/emails returns each email with both primary and verified flags. The current code only filters by primary — a user can have an unverified primary email (e.g., they changed their primary and haven't confirmed the new one yet). Accepting an unverified email opens an account-takeover surface:

  1. Attacker creates a GitHub account with target's email as a "secondary, unverified" entry.
  2. Marks it primary (GitHub allows this without verification in some flows).
  3. Logs into the fim-one app via GitHub OAuth.
  4. Now controls the target's fim-one account.

GitHub's docs explicitly recommend filtering on verified=True as well. Fix:

primary = next((e for e in emails if e.get("primary") and e.get("verified")), None)

Severity

High — account-takeover-class issue, even if the exploit path is narrow.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions