Trello — Email Verification Bypass via OAuth Leading to Pre-Account Takeover

DP
Deev Pal
Oct 31, 2024 10 min read
Duplicate finding. This vulnerability was independently discovered and reported, but had already been submitted by another researcher in August 2020. No bounty was awarded. This writeup is published for educational purposes — it covers a well-known vulnerability class (Pre-Account Takeover) that affects many applications beyond Trello.

TL;DR

Trello supports two ways to create an account: email/password signup (requires email verification) and Google OAuth (no verification needed — Google already verified the email). The vulnerability exploits the gap between these two paths.

An attacker creates a Trello account using the victim's email address via the email/password path, but never verifies the email — they just stop at the verification prompt. The account exists in Trello's database, linked to the victim's email, in an unverified state. Later, when the victim signs up using Google OAuth with the same email, Trello links the OAuth login to the existing unverified account instead of creating a new one. Now both the attacker (via password) and the victim (via OAuth) have access to the same account — full account takeover.

This is a Pre-Account Takeover — the attacker compromises the account before the victim even creates it. All the attacker needs is the victim's email address. No phishing, no credential theft, no social engineering. Just register first and wait.

Background — How Signup and OAuth Work

Most modern web applications offer multiple ways to create an account. Understanding how each path works is key to understanding why this vulnerability exists.

Path 1: Email/Password Signup

The traditional signup flow:

  1. User enters an email address and password
  2. Application creates an account in the database (status: unverified)
  3. Application sends a verification email with a confirmation link
  4. User clicks the link in their email
  5. Account status changes to verified
Why is verification needed? When you sign up with an email, anyone can type any email address — there's no proof you actually own it. The verification step proves ownership: only the real owner of the email can click the confirmation link. Without this step, I could create an account using your email and impersonate you.

Path 2: Google OAuth Signup

The "Continue with Google" flow:

  1. User clicks "Continue with Google"
  2. User is redirected to Google's login page
  3. User enters their Google credentials and grants consent
  4. Google sends the user's verified email back to Trello
  5. Trello creates (or links to) an account using that email — no separate verification needed
Why no verification? With OAuth, the email verification is delegated to Google. Google already verified that you own the email when you created your Google account. So when Google tells Trello "this user owns alice@gmail.com," Trello trusts Google's word and skips its own verification. This is standard and correct — as long as the application handles the edge cases properly.

The Edge Case

The problem arises when both paths are used for the same email address. Specifically:

  1. Someone creates an account via email/password with alice@gmail.com but never verifies
  2. Later, the real alice@gmail.com signs up via Google OAuth

What should Trello do? There are two correct options:

  • Option A: Reject the OAuth signup because an unverified account already exists with that email — tell Alice "an account with this email already exists, please verify it or use password login"
  • Option B: Delete or disconnect the unverified account and create a fresh one linked to the OAuth identity

What Trello actually did: Option C (vulnerable) — link the OAuth login to the existing unverified account, giving both the original registrant (attacker) and the OAuth user (victim) access to the same account.

The Flaw — When Two Signup Paths Collide

Here's the core logic error, visualized:

Account State Diagram
Timeline:
─────────────────────────────────────────────────────────────────

T1: Attacker registers with alice@gmail.com via email/password
    └── Account created: { email: alice@gmail.com, verified: false }
    └── Password set by attacker: hunter2
    └── Verification email sent (attacker can't click it — not their email)
    └── Attacker stops here. Account exists but is unverified.

T2: Real Alice signs up via Google OAuth
    └── Google confirms: "alice@gmail.com is verified"
    └── Trello checks: "Does an account with alice@gmail.com exist?"
    └── Answer: YES (the unverified one from T1)
    └── Trello links OAuth to the EXISTING account
    └── Account updated: { email: alice@gmail.com, verified: true, oauth: google }
    └── Alice is logged in. She thinks this is her new account.

T3: Attacker logs in with alice@gmail.com + hunter2
    └── Trello checks: password matches? YES
    └── Attacker is logged into Alice's account
    └── Full access to everything Alice has done since T2

Result: BOTH the attacker and Alice have active sessions on the SAME account.
The fundamental problem: Trello treated the unverified account as a legitimate placeholder. When Alice arrived via OAuth, Trello merged her identity into the attacker's pre-registered account instead of treating the unverified account as suspicious. The attacker's password was never invalidated, so both authentication methods (password and OAuth) now work on the same account.

Exploitation — Step by Step

Attacker's Side

The attacker only needs to know (or guess) the victim's email address. This is trivial — email addresses are often publicly available from LinkedIn profiles, company directories, GitHub profiles, conference talks, etc.

Attacker's Steps
1. Go to trello.com
2. Click "Create an account"
3. Enter the victim's email: alice@company.com
4. Set a password the attacker controls: P@ssw0rd123
5. Click "Create account"
6. See the "Verify your email" prompt
7. STOP. Do nothing. Close the browser.
   └── The account now exists in Trello's database
   └── Linked to alice@company.com
   └── Password: P@ssw0rd123
   └── Status: unverified
   └── The attacker just waits...

That's it for the attacker. Total effort: 30 seconds. Now they wait — hours, days, weeks, months — for the victim to sign up.

The patience game: This is a "plant now, harvest later" attack. The attacker can pre-register accounts for hundreds of email addresses and just wait. There's no cost to the attacker for accounts that never get claimed — they just sit in Trello's database as unverified. The attack only "activates" when the victim signs up via OAuth.

Victim's Side

The victim does nothing unusual. They simply decide to try Trello for the first time:

Victim's Steps (Completely Normal Behavior)
1. Go to trello.com
2. Click "Continue with Google"
3. Log in with their Google account (alice@company.com)
4. Grant Trello access to their Google profile
5. Get redirected to Trello — logged in, account ready to use
   └── The victim sees a normal, fresh-looking Trello account
   └── They start creating boards, inviting team members, adding data
   └── They have no idea the attacker also has access

Attacker's Return

At any point after the victim signs up, the attacker comes back:

Attacker Returns
1. Go to trello.com
2. Click "Log in"
3. Enter: alice@company.com / P@ssw0rd123
4. Successfully logged in — to the VICTIM'S account
   └── Can see all boards, cards, and conversations
   └── Can see workspace memberships and team data
   └── Can change the password (locking victim out)
   └── Can change the email (fully hijacking the account)
   └── Can export or delete all data
The victim never knows. There's no notification that someone else has access. There's no alert that the account was pre-registered. The victim's OAuth login worked perfectly. From their perspective, everything is normal — they have no reason to suspect the account was compromised before they even created it.

Video PoC — Full Attack Demo

The entire attack from start to finish — attacker registers with the victim's email, skips verification, victim signs up via Google OAuth, and the attacker logs into the victim's account:

Full PoC: Email verification bypass via OAuth leading to pre-account takeover on Trello. The attacker pre-registers with the victim's email, never verifies, and gains full access once the victim signs up via Google OAuth.

Why It Works — The Verification Gap

The vulnerability exists because of a mismatch in how Trello handles email verification across its two signup paths:

Pseudocode — OAuth Login Handler
function handleOAuthLogin(oauthEmail) {
    // Google has verified this email ✓

    const existingAccount = findAccountByEmail(oauthEmail);

    if (existingAccount) {
        // Account already exists — link OAuth to it
        existingAccount.linkOAuth("google");
        existingAccount.verified = true;    // ← Upgrades unverified to verified
        loginUser(existingAccount);          // ← Victim is logged in

        // ✗ Missing: check if existingAccount was verified
        // ✗ Missing: invalidate/reset the existing password
        // ✗ Missing: alert the user that an account already existed
        // ✗ Missing: delete the unverified account and create fresh
    } else {
        // No account exists — create new one
        createAccount(oauthEmail, oauth: "google", verified: true);
        loginUser(newAccount);
    }
}

The critical line is the if (existingAccount) branch. When an account already exists with the OAuth email, Trello blindly links the OAuth identity to it — even if that account was never verified. The existing password (set by the attacker) remains valid. The attacker's session isn't invalidated. The account just gets "upgraded" to verified status.

What should happen instead: When an OAuth login matches an unverified account, the application should treat the unverified account as suspicious. The safest option is to delete the unverified account entirely and create a fresh one linked only to the OAuth identity. Alternatively, the application should at minimum invalidate the existing password and any active sessions, so the person who created the unverified account (the attacker) can no longer access it.

Impact

Severity: P2 (High) — Account Takeover

  • Confidentiality: Critical — full access to the victim's account, boards, cards, conversations, attached files, and workspace data
  • Integrity: Critical — attacker can modify, delete, or export all data; can change account credentials to lock the victim out permanently
  • Availability: High — attacker can lock the victim out by changing password and email

What makes this attack dangerous:

  • Zero interaction from victim. The victim doesn't need to click a link, visit a malicious site, or do anything unusual. They just sign up for Trello normally via Google OAuth.
  • Scalable. An attacker can pre-register hundreds of email addresses. Every future OAuth signup with a matching email is automatically compromised.
  • Invisible. No alerts, no notifications, no indicators that the account was pre-compromised. The victim's OAuth login appears to work perfectly.
  • Low skill required. No tools, no Burp Suite, no API knowledge. Just a web browser and the victim's email address.
  • High-value targets. Trello is used by teams at large organizations. If an attacker pre-registers the email of a CTO, engineering lead, or project manager before they sign up for Trello, the attacker gains access to potentially sensitive project boards, roadmaps, and internal discussions.
Pre-ATO vs traditional ATO: In a traditional account takeover, the attacker compromises an existing account (through password theft, session hijacking, etc.). In a pre-account takeover, the attacker compromises the account before it's even fully created. The attacker is already inside when the victim arrives. This makes detection much harder because there's no "break-in" event — the attacker had access from the beginning.

Remediation

The standard fix for this vulnerability class involves one or more of these approaches:

  1. Don't link OAuth to unverified accounts. When an OAuth login matches an existing account, check the account's verification status. If the account is unverified, treat it as an abandoned/suspicious registration — delete it and create a fresh account linked to the OAuth identity.
  2. Invalidate credentials on OAuth linking. If you choose to link OAuth to an existing account, invalidate all existing authentication methods (password, active sessions, API tokens) on that account. The attacker's password should stop working the moment the victim links their OAuth.
  3. Expire unverified accounts. Unverified accounts should have a short TTL (e.g., 24-48 hours). If the email isn't verified within that window, delete the account. This reduces the attack window significantly.
  4. Alert on OAuth linking. When an OAuth login is linked to an existing account (verified or not), send a notification to the email: "Your Trello account was just linked to Google OAuth. If you didn't do this, contact support." This doesn't prevent the attack but makes it detectable.
The lesson for developers: When your application supports multiple signup paths, map out every possible state collision: What happens when path A and path B both try to create an account with the same email? What happens if path A creates an unverified account and path B arrives with a verified identity? Every combination needs to be explicitly handled. The default behavior of "merge them" is almost always wrong when one path involves unverified state.

Timeline

  • 2020-08-31 — Original submission by another researcher ("Account Takeover via Google Oauth misconfiguration")
  • 2024-10-31 — Independent rediscovery and submission by me (TechyCodec08)
  • 2024-11-05 — Marked as duplicate of the August 2020 submission
  • No bounty awarded — duplicate with "Not applicable" status
A four-year-old duplicate: The original report was submitted in August 2020 — over four years before I independently found it. This is one of the most well-known vulnerability classes in bug bounty (pre-ATO via OAuth), and it's been found on dozens of platforms. The fact that it keeps being rediscovered independently tells you two things: (1) it's a fundamental design flaw that many applications share, and (2) it's a great addition to your testing checklist for any new target.

Takeaways

  1. Always test signup path collisions. When an application supports multiple signup methods (email, Google OAuth, Apple, GitHub, SSO), systematically test what happens when different paths target the same email. Create an unverified account via path A, then sign up via path B. Does path B inherit path A's credentials? Does it create a separate account? Does it alert anyone? The answer reveals whether the application is vulnerable to pre-ATO.
  2. Pre-ATO is a checklist item, not a discovery. This vulnerability class is well-documented. It appears on OWASP lists, in bug bounty writeups, and in security research papers. If you're testing a new target, "test pre-ATO via OAuth" should be one of the first things you try — before diving into more complex attack surfaces. It takes 60 seconds to test and can yield a P2.
  3. Unverified state is dangerous state. Any resource in an "unverified" or "pending" state is a potential attack vector. Can an attacker create unverified resources that later get implicitly trusted when a legitimate user arrives? This pattern extends beyond accounts — think unverified email addresses on existing accounts, pending invitations, unconfirmed role changes.
  4. OAuth trust is not transitive. Google verified Alice's email. But that doesn't mean Trello should trust everything that was previously associated with that email in its own database. An unverified Trello account created with Alice's email isn't trustworthy just because Google later confirms Alice owns the email. The OAuth verification applies to the OAuth identity, not to the pre-existing unverified state in Trello's database.
  5. Duplicate or not, understand the pattern. I didn't earn money from this finding. But I learned a vulnerability pattern that I now test on every single target. Pre-ATO via OAuth is still present on many applications — the fundamentals don't change even as platforms evolve. Sometimes the best ROI from a duplicate is the pattern it adds to your permanent checklist.