Hi,
A recent penetration test against our tenant flagged a timing-based user enumeration issue on:
POST /dbconnections/change_password
POST /u/reset-password/request/Username-Password-Authentication
Finding: Both valid and invalid email addresses return HTTP 200 with the same generic “Check Your Email” page and message, so there’s no content-based leak. However, response times differ consistently and measurably:
-
Valid, existing email: ~130–260ms
-
Non-existent email: ~260–370ms
I know Attack Protection covers brute force, suspicious IP throttling, bot detection, and breached password detection, but none of those address timing-based enumeration specifically.
Questions:
- Is this a known issue with these endpoints? Is equalized/constant-time response handling on Auth0’s roadmap here?
- Is there any tenant-side configuration (Actions, custom domain settings, etc.) that can influence response timing before the initial reset-request response is sent, given that the Post Challenge Action trigger only fires after the email challenge is completed?
Any guidance — official or from others who’ve hit this in a pentest — would be appreciated. Happy to open a support ticket too if this needs to go through Auth0 security directly.
Hi @platbaseddeveloper
Welcome to the Auth0 Community!
- Yes, this is a known behavioral side-channel pattern across standard identity providers, including Auth0.
The timing discrepancy you observed originates from the differing code paths executed by the Auth0 authentication server depending on user existence:
-
The “Fast” Path (User exists ~130–260ms): When the database lookup is successful, Auth0 generates an ephemeral password-reset ticket and passes the task off to an asynchronous email-sending queue before immediately returning an HTTP 200 to the client.
-
The “Slow” Path (User does not exist ~260–370ms): When the user does not exist, Auth0 does not spin up a ticket-generation or queuing process. However, to mitigate brute-force indexing and generic credential-stuffing attacks, the backend intentionally routes through safety evaluation checks (such as more extensive Attack Protection checks, IP reputation tracking, and simulated hashing paths) to obscure the user’s absence . This additional security overhead can end up taking longer than the optimized queuing path for active users, resulting in the timing delta. This is also mentioned in the User Enumeration via Password Reset Timing Attack.
- Because both endpoints run entirely at the platform level before any Action flows (like Post-Login or Pre-User Registration) or custom extensibility scripts can be interceptively executed, there is no tenant-side config, custom domain proxy setting, or Auth0 Action that can equalize the response latency of these endpoints.
However, you can mitigate and address this pentest finding through several industry-standard practices:
A. Decouple via a Proxy Endpoint (Architectural Solution)
If your auditors strictly require a zero-leak timing guarantee, the recommended approach is to route password reset requests through your own backend gateway rather than exposing the /dbconnections/change_password endpoint directly to the public web:
-
Expose a custom proxy endpoint on your backend (e.g., POST /api/auth/request-reset).
-
Have your backend immediately return a generic 200 OK (e.g., in < 50ms) to the frontend.
-
Decouple the request execution completely by sending the payload to an asynchronous background queue on your backend.
-
The background queue can then call the Auth0 Management API (POST /api/v2/tickets/password-change) using an administrative M2M token, or forward the request to the Authentication API. Because your backend is the one communicating with Auth0, the end-user only ever sees the near-instantaneous static response time of your gateway .
B. Implement Rate Limiting and WAF Rules at the Edge
Timing attacks are only structurally viable if the attacker can issue thousands of requests to map statistical distribution trends.
-
Ensure Bot Detection is set to High inside your Auth0 Dashboard (Security > Attack Protection) to trigger immediate CAPTCHA challenges on suspicious, automated /reset patterns as mentioned in the Signup Attack Playbook*
-
Implement strict rate limits at your edge proxy or Web Application Firewall (WAF) (such as Cloudflare, AWS WAF, or Akamai) targeting /dbconnections/change_password and /u/reset-password. Limiting client IPs to a maximum of 3–5 reset requests per 15 minutes effectively ruins the statistical modeling required to run a timing side-channel attack.
C. Official Pentest Exception Wording
If you choose to accept the risk rather than wrapping the endpoint in a proxy (Method A), most security compliance bodies (such as SOC2, ISO27001, and PCI-DSS) accept a Risk Acceptance Exception for timing-based user enumeration on public login endpoints when backed by the following mitigating controls:
-
Standard content-based leaks are completely plugged (generic messages are used).
-
Passive rate limiting, Bot Detection, and Suspicious IP Throttling are fully enabled to restrict mass-indexing attempts.
-
Multi-Factor Authentication (MFA) or Passkeys are enforced on your user accounts, neutralizing the downstream threat of a leaked email directory
Kind Regards,
Nik