(Concurrency Abuse That Developers Almost Never Test – Educational Case Study)
Disclaimer
This article is written strictly for educational and defensive purposes.
All applications, endpoints, identifiers, timings, and data are fully anonymized.
No real-world system was harmed.
This write-up demonstrates how lack of concurrency control leads to critical exploitation.
Why Race Conditions Are a Hacker’s Dream
Most vulnerabilities are about bad input.
Race conditions are about bad timing.
And timing bugs are deadly because:
- They don’t show in normal testing
- They disappear when logged
- They only appear under pressure
- Developers almost never simulate them
⏱️ If two requests arrive “at the same time” — who wins?
Attackers make sure they do.
Target Overview (Anonymized)
- Type: SaaS web application
- Feature abused: Coupon redemption
- Auth: Logged-in user
- Constraints enforced by app:
- Coupon usable once per user
- Wallet credit applied after redemption
- Backend: REST API
- Database: Relational (transaction-based, but poorly used)
Phase 1: Understanding the Logic (Before Touching Tools)
The normal coupon flow:
- User applies coupon
- Backend checks:
- Is coupon valid?
- Is coupon already used?
- Backend credits wallet
- Coupon marked as used
That looks safe.
But here’s the real logic (simplified):
IF coupon_not_used:
credit_wallet()
mark_coupon_used()
🚩
These steps were not atomic.
Phase 2: Spotting the Race Opportunity
I watched the request:
POST /api/coupon/redeem
Content-Type: application/json
{
"code": "WELCOME100"
}
Response (normal):
{ "wallet": 100 }
Then I tried again.
Response:
{ "error": "Coupon already used" }
So far, so good.
But the real question is:
What happens if two requests arrive before the coupon is marked used?
Phase 3: Forcing Concurrency (The Key Step)
I didn’t brute-force.
I sent requests in parallel.
Tool Used:
- Burp Suite → Intruder
- Attack type: Pitchfork
- Threads: 10 simultaneous requests
All requests contained the same coupon code.
Phase 4: The Moment It Broke
Out of 10 requests:
- 7 returned success
- 3 returned “already used”
Wallet balance:
"wallet": 700
😐
Coupon supposed to give ₹100 once.
I got ₹700.
Phase 5: Why This Worked (Critical Insight)
The backend logic was:
if not coupon.used:
wallet += coupon.amount
coupon.used = True
But without:
- Database locks
- Transactions
- Atomic operations
Multiple threads passed the if check before the flag flipped.
This is a classic race condition.
Phase 6: Scaling the Exploit (Danger Zone)
I reduced delay.
Increased threads.
Timed it better.
Results:
- Wallet inflated repeatedly
- No alerts
- No errors
- Logs looked legitimate
This is the scariest kind of exploit.
Real-World Impact
Race conditions can allow:
- 💸 Unlimited wallet credit
- 🎟️ Multiple redemptions
- 🛒 Free purchases
- 🧾 Duplicate refunds
- 🔓 Double spending
Severity:
Critical – Financial Abuse
Where Race Conditions Commonly Exist
Developers almost always miss them in:
- Coupon redemption
- OTP verification
- Password reset tokens
- Inventory stock
- Voting / likes
- Rate-limited actions
Anywhere with:
“Only once” logic
How I Systematically Hunt Race Conditions
This is my exact method:
1️⃣ Find state-changing endpoints
- Redeem
- Apply
- Verify
- Confirm
2️⃣ Check order of operations
- Validation
- Action
- State update
3️⃣ Send parallel requests
- Same payload
- Same session
- Same time
4️⃣ Watch for partial success
- Multiple OKs
- Inconsistent state
One success is enough.
Tools Used
| Tool | Purpose |
|---|---|
| Burp Suite Intruder | Parallel requests |
| Repeater | Baseline behavior |
| Timing | Exploit window |
| Brain | Always |
Root Cause Analysis
❌ Developer Mistakes
- No transaction locking
- No atomic updates
- Business logic split across steps
- Assumed single-threaded behavior
Web apps are never single-threaded.
✅ Proper Fix (Non-Negotiable)
- Database transactions
- Atomic operations
SELECT ... FOR UPDATE- Idempotency keys
- Server-side locking
Anything less is vulnerable.
Why These Bugs Are Rare but Severe
Because:
- Hard to reproduce
- Hard to test
- Hard to explain
- Easy to exploit once found
That’s why companies fear them.
Final Thoughts
Race condition bugs are not about skill.
They’re about thinking like time itself.
And time is on the attacker’s side.
