User Enumeration

Attacker harvests a verified list of customer emails by reading different error bodies and response times from the login endpoint, then ship the unified error and constant-time stand-in.

What Is User Enumeration?

User enumeration is the application telling an attacker which emails or usernames exist. The hostile primitive is any difference in observable behaviour between the registered-user path and the unregistered-user path: a different error string, a different status code, a different response time, a different downstream side-effect. Once that signal exists, an attacker scripts it and walks a wordlist of candidate addresses, keeping only the registered subset. That subset is gold, it feeds credential stuffing, targeted phishing, and password-reset abuse, and it stays under most rate-limit thresholds because each probe is a single attempt that returns a clean 401. This exercise puts you on both sides. As Bob, preparing a credential-stuffing campaign, you send two probe requests to Larksong's sign-in endpoint: one with a definitely-unknown email, one with an email you believe is registered. The body changes ('No account found' vs 'Incorrect password') and the latency changes (bcrypt only runs when the user exists). Either channel is enough. As Alice, on the receiving end of a Security Operations enumeration alert, you open the handler, see the two-branch control flow, and apply the fix: a single check that returns one generic error body and always runs the bcrypt comparison, against a fixed dummy hash when no user exists, so both the error-body and the latency oracle are closed. The exercise closes with quiz questions on what enumeration is, why timing matters even after the body is unified, and where else the same shape appears (signup, password reset).

What You'll Learn in User Enumeration

User Enumeration — Training Steps

  1. A list that needs a filter

    Bob is holding a dump of email and password pairs from an unrelated breach. Most of those people have never heard of Larksong, so spraying the whole list at the sign-in page would be slow and noisy. First he wants to know which of those emails are actually Larksong accounts. He opens the Larksong sign-in page in his browser, with DevTools ready, to watch how it responds to a failed login.

  2. Try an email that isn't registered

    Bob starts with a baseline. He signs in with an address that almost certainly has no Larksong account and a throwaway password, and watches the response land in the Network panel.

  3. The baseline answer

    The form shows a sign-in error, and the real detail is in the Network panel: a 401 with a response body and a response time. This is what a failed login against an unregistered email looks like. Bob notes it as his baseline.

  4. Try an email he thinks is real

    Now Bob retries with an address from his dump that he believes belongs to a real listener, marcus.delgado@gmail.com, still with a throwaway password. If the endpoint treats the two cases the same, the response will match the baseline. If it does not, the difference is the whole prize.

  5. A different answer

    The answer changed. Same wrong password, but the response body is different. Bob never logged in, yet the sign-in endpoint just told him this email is a real Larksong account.

  6. Check the response times

    The wording is one tell. The Network panel holds a second, quieter one: how long each request took.

  7. Knowledge check

    Before Bob scales this up, be precise about why the real account was so much slower.

  8. Harvest the list

    Bob points a script at the sign-in endpoint and feeds it every email from his dump, one request each. Whenever the answer is the slow Incorrect password , that address goes on his confirmed list. Out of 50,000 candidates, 8,400 are real Larksong accounts. Now the credential-stuffing run that follows only targets addresses he knows exist, so it stays small, quiet, and well under the rate limits that would flag a blind spray.

  9. The security alert

    You own Larksong's sign-in service. Overnight, detection flagged a strange pattern against the login endpoint and emailed you the finding. Read what it caught, then open the code.

  10. Open the login handler

    The login route lives in the auth service. Open the handler and look at how it decides what to send back when a sign-in fails.