Account enumeration occurs when someone can determine which accounts exist from the application's responses. Prevent it by reviewing the whole response contract across login, signup, and recovery, then removing disclosures the product does not intend to make public.
A generic error message is useful, but it is only one part of that contract. Status codes, redirects, response size, and processing time can still separate an existing account from a nonexistent one.
OWASP's account-enumeration testing guide also notes an important scope decision: some products deliberately make usernames public. Define what should remain private before calling every discoverable identifier a vulnerability.
Decide which facts the interface may disclose
Write down the intended behavior for an existing account, a nonexistent account, and an account that cannot currently sign in. Include email aliases and federated identities if they are supported.
A public profile directory may intentionally disclose a username while keeping its associated email private. A support-assisted workflow may disclose information after identity verification that the public recovery endpoint should not disclose.
Those are different policies. Do not attempt to solve them with one error string copied across every screen.
Compare the complete response
Use synthetic accounts in an environment you are authorized to test. Keep the request count low and avoid sending recovery messages to real users.
| Surface | Compare | Common review gap |
|---|---|---|
| Login | Body, status, and redirect | “Wrong password” differs from “unknown user” |
| Password reset | Acknowledgment and processing path | One response waits for a delivery provider |
| Signup | Duplicate-account handling | Email existence is disclosed without a product decision |
| Identity lookup | Public fields and response shape | A helper endpoint bypasses the main form's policy |
| Throttling | Behavior before and after limits | Limits reveal account state indirectly |
The table is a review method, not a checklist whose completion proves the absence of every side channel. Record what you actually compared.
Make timing less dependent on account existence
If one branch performs expensive work and the other immediately returns, identical visible text may conceal a predictable difference. Review the server-side path before adding arbitrary sleep delays.
For password recovery, OWASP recommends consistent responses and response times, with asynchronous processing among the available approaches. Keep that processing bounded: a uniform acknowledgment must not create an unlimited delivery queue.
Measure several synthetic requests under comparable conditions. One slow request is not a timing channel, and one fast test is not proof that the paths are equivalent. Capture the application version and observation point so another engineer can repeat the comparison.
Keep useful feedback behind a trusted boundary
People still need to recover access. A neutral acknowledgment can explain that instructions will be sent if the account is eligible, while providing a safe support route for people who cannot receive them.
Avoid changing account state simply to make public responses look consistent. The recovery service should not lock an account because someone requested a reset for its address.
Where the product intentionally discloses an existing account during signup, document that decision and the reason. Then bound automated probing rather than pretending the disclosure has been eliminated.
Use bot controls as a supporting layer
Rate limits and automation controls can reduce repeated probing, but they do not repair a response that reveals account existence in one request. Fix the disclosure first, then check whether public endpoints can be queried excessively.
Keep controls consistent across web and API paths. A protective frontend does not help when a second endpoint exposes the same lookup directly.
Review password-reset abuse for delivery flooding, which is a related but different problem. The account takeover use case provides the product context for automated account attacks. Bring the response comparison to the implementation review so disclosure fixes and traffic controls remain separate work items.
