# Login response time differs for valid vs invalid usernames enabling user enumeration

- **ID:** `security/timing-attack-user-enumeration-login`
- **Domain:** security
- **Category:** auth_error
- **Verification:** ai_generated
- **Fix Rate:** 85%

## Root Cause

The authentication logic performs a password hash comparison only after a database lookup confirms the user exists, causing a measurable time difference between requests for existing and non-existing usernames.

## Version Compatibility

| Version | Status | Introduced | Deprecated |
|---------|--------|------------|------------|
| Node.js 20 | active | — | — |
| Python 3.11 | active | — | — |
| Java 17 | active | — | — |

## Workarounds

1. **Always perform a dummy password hash comparison, even when the user does not exist. In Node.js with bcrypt: const hash = user ? user.hash : DUMMY_HASH; await bcrypt.compare(password, hash);** (90% success)
   ```
   Always perform a dummy password hash comparison, even when the user does not exist. In Node.js with bcrypt: const hash = user ? user.hash : DUMMY_HASH; await bcrypt.compare(password, hash);
   ```
2. **Use a constant-time comparison function like crypto.timingSafeEqual for all password checks, and ensure the same code path executes regardless of user existence.** (85% success)
   ```
   Use a constant-time comparison function like crypto.timingSafeEqual for all password checks, and ensure the same code path executes regardless of user existence.
   ```
3. **Implement a generic error message for both invalid username and invalid password, and log the specific reason server-side only.** (80% success)
   ```
   Implement a generic error message for both invalid username and invalid password, and log the specific reason server-side only.
   ```

## Dead Ends

- **** — Adding artificial delays to all responses increases latency for legitimate users and may not fully mask the timing difference if the delay is predictable. (50% fail)
- **** — Removing the user existence check entirely breaks the authentication flow and may allow login with any password for non-existent users unless handled carefully. (60% fail)
- **** — Using a simple sleep() function after a failed login is easily bypassed by attackers who can sample multiple requests and average out the delay. (40% fail)
