Account Enumeration
Also Known As
user enumeration
username enumeration
TL;DR
Differing application responses to valid vs. invalid usernames allow attackers to build a list of registered accounts.
Explanation
Account enumeration happens when an application reveals whether a username exists through different HTTP status codes, response bodies, response times, or error messages (e.g., 'This email is not registered' vs. 'Incorrect password'). Armed with a valid username list, attackers can run targeted credential-stuffing or brute-force attacks. Prevention: use generic error messages ('Invalid credentials'), ensure consistent response times with a dummy password-check for unknown users, and implement rate limiting.
Diagram
sequenceDiagram
participant ATK as Attacker
participant APP as Application
ATK->>APP: POST /login user=alice@ex.com pass=wrong
APP-->>ATK: Email not found - reveals alice does NOT exist
ATK->>APP: POST /login user=bob@ex.com pass=wrong
APP-->>ATK: Wrong password - reveals bob DOES exist
Note over ATK,APP: Attacker now knows valid accounts
Note over ATK,APP: Fix: always return same message
ATK->>APP: POST /login user=bob@ex.com pass=wrong
APP-->>ATK: Invalid credentials - no account info leaked
Common Misconception
✗ A generic "invalid credentials" message fully prevents enumeration. Timing differences, CAPTCHA behaviour, and password-reset flows can still reveal whether an account exists even when error messages are identical.
Why It Matters
Revealing which usernames exist lets attackers target brute-force and credential-stuffing attacks precisely, turning a failed login into a reconnaissance win.
Common Mistakes
- Returning 'user not found' vs 'wrong password' — both messages reveal account existence.
- Different response timing for valid vs invalid usernames leaks the same information as different messages.
- Password reset forms that say 'no account for that email' rather than a generic confirmation.
- Registration forms that reveal 'username already taken' without rate-limiting or CAPTCHA.
Avoid When
- Do not use distinct error messages per failure reason on auth endpoints — merge all failures into one generic response.
- Avoid varying response timing based on whether an account exists — constant-time comparisons prevent timing oracle attacks.
- Do not expose account existence through side-channels like redirect destinations or HTTP status codes.
When To Use
- Understanding this attack is essential when designing login, registration, and password-reset flows.
- Apply enumeration defences on any endpoint where attacker knowledge of a valid account provides value.
Code Examples
💡 Note
The bad example returns "No account found with that email" — an attacker can confirm which emails are registered; the fix returns the same message for wrong email and wrong password.
✗ Vulnerable
// Different messages reveal whether account exists
if (!\$user) {
return 'No account found with that email';
}
if (!password_verify(\$pw, \$user->password)) {
return 'Incorrect password'; // confirms account exists!
}
✓ Fixed
// Same message regardless of failure reason
function login(string \$email, string \$password): ?User {
\$user = User::where('email', \$email)->first();
// Always run password_verify — prevents timing-based enumeration too
\$hash = \$user?->password ?? '\$argon2id\$v=19\$m=65536,t=4,p=1\$dummy\$dummy';
\$valid = password_verify(\$password, \$hash);
if (!\$user || !\$valid) {
return null; // identical response for both failure cases
}
return \$user;
}
References
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
15 Mar 2026
Edited
31 Mar 2026
Views
41
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 0
No pings yet today
Amazonbot 14
Perplexity 10
Google 4
Ahrefs 3
Majestic 2
ChatGPT 1
Unknown AI 1
Also referenced
How they use it
crawler 34
crawler_json 1
Related categories
⚡
DEV INTEL
Tools & Severity
🟡 Medium
⚙ Fix effort: Low
⚡ Quick Fix
Return identical response time and message for 'user not found' and 'wrong password' — use hash_equals() and always run password_verify() even for non-existent users
📦 Applies To
PHP 5.0+
web
api
🔗 Prerequisites
🔍 Detection Hints
Login returning 'user not found' vs 'wrong password' separately; password reset revealing whether email exists
Auto-detectable:
✓ Yes
semgrep
owasp-zap
⚠ Related Problems
🤖 AI Agent
Confidence: Medium
False Positives: Medium
✗ Manual fix
Fix: Medium
Context: Function
Tests: Update
CWE-203
CWE-204