Duplicate Registration Vulnerability Guide

Duplicate Registration: A Guide to Account Takeover

In web security, complex attacks often get the most attention. However, simple features usually hide the biggest risks. One such risk is the Duplicate Registration vulnerability.

This flaw allows attackers to hijack accounts. Furthermore, it can lead to privilege escalation or lock out legitimate users. Therefore, understanding this bug is essential for bug hunters and developers alike.

Concept of Account Takeover via Registration Bug
User registration flows must be strictly validated to prevent account overwrites.

What Is Duplicate Registration?

User registration relies on one rule: Identifiers must be unique. Specifically, emails or usernames should belong to only one person.

Duplicate registration happens when an app breaks this rule. Consequently, an attacker can register with an identifier that already exists. This usually happens in three ways:

  1. Account Overwrite: The new registration updates the existing record. As a result, the attacker replaces the password and takes control.
  2. Shadow Accounts: Multiple accounts exist for the same email. The system might log the attacker into the victim’s profile randomly.
  3. Denial of Service: The registration corrupts the data. Thus, the victim can no longer log in.

Why Is This So Dangerous?

You might think a signup bug is minor. On the contrary, the impact can be severe.

  • Account Takeover (ATO): Attackers can target specific victims, like CEOs, to reset their passwords.
  • Privilege Escalation: If the first user is an admin by default, an attacker might wipe the database to become the new admin.
  • Bypassing 2FA: Overwriting credentials often bypasses Two-Factor Authentication checks.

Step-by-Step Testing Guide

Follow this simple methodology to find these bugs. You can use tools like Burp Suite or manual testing.

Step 1: Establish a Baseline

First, create a standard account. For example, use testuser@example.com.

  • Log in to verify it works.
  • Then, log out completely.
  • Note the User ID if it is visible in the URL (e.g., /profile/1001).

Step 2: Test Direct Duplicates

Next, try to register the exact same email again.

  • Expected: The site should show an error.
  • Vulnerable: Registration succeeds, and you cannot log in with the old password.

Intercepting a registration request in Burp Suite
Use a proxy tool to intercept and modify requests during testing.

Step 3: Test Case Sensitivity

This is the most common variant. Try registering with different capitalization.

  • TestUser@example.com
  • TESTUSER@EXAMPLE.COM

Tip: Use Burp Suite to intercept the POST request. Frontend validation might block unusual casing, but the backend might not.

Step 4: Test Whitespace

Check if the app trims spaces. Try these inputs:

  •  testuser@example.com (Leading space)
  • testuser@example.com  (Trailing space)

Step 5: Verify Authentication

Finally, try to log in. Use the original email and the new password. If you gain access to the victim’s account, you have found a critical vulnerability.

Anatomy of the Vulnerability

Why do developers miss this? Usually, it is a mismatch between code and the database.

1. Case Sensitivity Mismatches

Emails should be case-insensitive. However, databases often treat them as case-sensitive by default.

  • Registration: Attacker@site.com is treated as new.
  • Login: The app lowercases the input, causing a collision.

2. The “Upsert” Trap

Developers sometimes use “upsert” commands. These commands update data if it exists or create it if it does not. Unfortunately, this logic allows attackers to update anyone’s password.

For more on SQL logic errors, you can read the OWASP Testing Guide.

Real-World Example: Vine

This bug is not just theoretical. For instance, HackerOne report #187714 detailed a flaw in Vine.

Their Android app allowed users to register with existing emails by changing the casing (e.g., Test@Vine.com). As a result, attackers could lock out victims. This proves that even big companies are vulnerable to simple logic flaws.

Remediation: How to Fix It

Fixing this issue requires a defense-in-depth approach.

  1. Normalize Input: Always convert emails to lowercase before checking the database.
  2. Use Database Constraints: Add a UNIQUE index to the email column. This prevents duplicates even if code fails.
  3. Avoid Upsert: Registration should be “insert-only.” If the email exists, simply return an error.

Secure Code Example

def register_user(email, password):
    # 1. Normalize the email
    clean_email = email.strip().lower()

    # 2. Check if user exists
    if User.query.filter_by(email=clean_email).first():
        return abort(409, description="User already exists")

    # 3. Create the user
    # Ensure 'email' has a UNIQUE constraint in the DB
    user = User(email=clean_email, password=hash_password(password))
    db.session.add(user)
    db.session.commit()

Conclusion

Duplicate registration is a classic logic error. It is simple to test but devastating if exploited.

When auditing an application, ask yourself: What happens if I sign up as someone else? Often, this single question leads to critical findings. For more tips on finding bugs, check out our guide on vulnerability scanning.

Leave a Reply

Your email address will not be published. Required fields are marked *