Finding a $100 Race Condition: How Two Simultaneous Sign-Ups Broke Email Uniqueness
A beginner-friendly breakdown of how a simple race condition during sign-up led to duplicate accounts sharing the same email, what caused it, and how to prevent such issues in web applications.
Disclaimer:
This article is for educational and defensive purposes only. It explains how race conditions can cause logic flaws in web applications. Always perform testing on systems you own or are authorized to assess.
1 - Introduction
Sometimes, the most impactful vulnerabilities aren’t found through automation or fancy tools - they come from curiosity and timing.
This case study dissects a $100 bug bounty earned through a race condition that allowed two user accounts to be created with the same email address.
While the payout was modest, the underlying issue was serious and educational - a perfect example for new bug hunters and developers learning about concurrency and atomic operations in web applications.

2 - Understanding the vulnerability: Race conditions in authentication flows
A race condition occurs when multiple actions or requests execute in parallel, and the system’s outcome depends on the timing or order of those actions.
When applied to authentication and registration flows, this can result in two major problems:
- Duplicate entries being created for supposedly unique identifiers (e.g., email, username, phone).
- Validation bypasses, where simultaneous requests pass validation before the system enforces a constraint.
In this case, the target was a social marketplace platform - think of something like Fiverr or Etsy - where users can register with an email and then verify it.
3 - The attacker’s perspective: discovering the bug through curiosity
The researcher didn’t use Burp Suite or advanced interceptors. Instead, they asked a simple question:
“What happens if I try to create two accounts with the same email, at almost exactly the same time?”
At first glance, that seems impossible. Every sane system checks whether an email already exists before allowing another registration.
However, when two registration requests arrive milliseconds apart, both may pass the “email not found” check before either is written to the database - resulting in two accounts being created with the same email.
4 - Steps to reproduce (safe demonstration)
The logic flaw can be safely reproduced in a controlled environment like a local test app.
Here’s how the condition was triggered:
- Open the registration page in two separate browsers (or two tabs).
- Fill out all required fields, using the same email address in both.
- Click “Sign Up” in both browsers at nearly the same time (or within a very small time window).
- Check your email inbox - two verification messages may arrive.
- Click both verification links; each one activates a different account, both tied to the same email.
That’s it - no code injection, no fuzzing, just timing and observation.
5 - What caused this vulnerability (technical breakdown)
The vulnerability stemmed from a lack of atomicity and proper locking during account creation.
Here’s what likely happened at a backend level:
-
Request A and Request B arrive nearly simultaneously.
-
Each performs a check:
Both queries return zero results because neither has been written yet.
-
Both insert statements execute successfully:
-
Each request generates a verification token and sends a unique link to the same inbox.
-
The user (or attacker) verifies both accounts, ending with two active accounts for one email.
This scenario happens when applications rely solely on application-level validation and skip database-level uniqueness enforcement.

6 - Example race timeline
| Time | Request A | Request B |
|---|---|---|
| T0 | Validation query runs - no record found | Validation query runs - no record found |
| T1 | Insert new user record | Insert new user record |
| T2 | Commit successful | Commit successful |
| T3 | Send verification email | Send verification email |
| T4 | Both users verified | Two accounts with one email |
7 - Business impact analysis
From a business and security perspective, this flaw can cause:
- Authentication confusion: Password resets may behave inconsistently.
- Account takeover potential: If one of the accounts is privileged or linked to sensitive actions, it could be hijacked.
- Billing errors: Duplicate user profiles could disrupt subscriptions or purchases.
- Compliance failures: Violations of account uniqueness policies or data integrity laws.
- User trust erosion: Confusing sign-in experiences for legitimate users.
For a real platform handling payments or identity verification, this could lead to data integrity corruption - a severe, hard-to-detect class of bug.
8 - How to fix it (defensive measures)
8.1 Enforce unique constraints at the database layer
Add a UNIQUE index on the email column.
This ensures that even if concurrent requests slip through validation, one insert will fail atomically.
8.2 Use transactions or locks
When performing multi-step operations (validation → insert → email verification), wrap the logic in a transaction or use pessimistic locking.
8.3 Handle duplicate insert exceptions safely
If two requests race, one will trigger a duplicate-key error - handle it gracefully by returning a standard “account already exists” message.
8.4 Debounce or rate-limit account creation
Block multiple sign-up attempts from the same IP/email within a short time window.
8.5 Add idempotency to registration endpoints
Idempotency ensures that multiple identical requests produce the same outcome - one account per unique email.

9 - Lessons learned (for both developers and hunters)
For developers:
- Always assume users (or concurrent systems) can send parallel requests.
- Don’t rely solely on front-end checks - the backend is the real source of truth.
- Design with concurrency and database isolation in mind.
For bug bounty hunters:
- You don’t always need advanced tools; manual timing tests can uncover logic flaws.
- Look for non-obvious vulnerabilities - think about what happens when actions overlap.
- Write clear, respectful reports with step-by-step reproduction and risk analysis.
Even small race conditions can reveal deeper architectural issues.
10 - Broader implications and real-world parallels
Similar race conditions have appeared in major platforms:
- E-commerce platforms accidentally duplicated orders when users clicked "Buy" twice.
- Payment systems processed refunds and debits twice under heavy load.
- Identity providers occasionally generated multiple tokens for the same session.
These issues stem from the same root cause - non-atomic operations under concurrent requests.
11 - Developer checklist: Preventing race conditions in sign-up and login systems
| Category | Defensive Practice |
|---|---|
| Data Integrity | Enforce unique constraints at DB level |
| Application Logic | Wrap sign-up flow in transactions |
| Session Management | Rate-limit and debounce requests |
| API Design | Implement idempotency keys |
| Error Handling | Gracefully handle duplicate insert exceptions |
| Testing | Add concurrent request tests in QA pipelines |
Tip: Use tools like JMeter, Burp Intruder, or custom Python scripts to simulate concurrent requests safely in staging environments.

12 - Why this bug still matters today
Even in 2025, many applications - especially startups - still lack atomicity in account management.
They often rely on frontend checks or ORM-level uniqueness without realizing how easily parallel HTTP requests can break those assumptions.
Race conditions don’t just cause bugs - they expose design-level weaknesses that can lead to privilege escalation, inconsistent data, or even full account takeovers.
13 - Key takeaways
- Keep it simple. Big rewards often come from simple ideas executed thoughtfully.
- Think like a system. Understand how different layers (frontend, backend, DB) interact under concurrency.
- Test timing. Small delays or overlaps can expose race flaws.
- Document everything. A clear report helps triagers, developers, and bounty reviewers.
- Stay ethical. The goal is to protect users and strengthen security, not exploit systems.
14 - Final thoughts
This $100 race condition bug is a perfect reminder that creativity, timing, and understanding system behavior often matter more than brute-force automation.
For developers, it’s a lesson in atomic operations and data consistency.
For bug bounty hunters, it’s a motivation to look beyond traditional injection flaws - the next payout might just be hiding in a few milliseconds of timing difference.
“Bug hunting isn’t about breaking - it’s about understanding.”
References & Further Reading
- OWASP: Race Condition Exploitation & Prevention
- PortSwigger Web Security Academy: Logic Flaws
- PostgreSQL Concurrency Control Docs
- HackerOne Reports tagged #race-condition
Published on herish.me - advancing ethical hacking education, one case study at a time.