[PR #8068] [CLOSED] fix(security): improve account enumeration protection on email sign-in #7724

Closed
opened 2026-03-13 13:47:16 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/better-auth/better-auth/pull/8068
Author: @Oluwatobi-Mustapha
Created: 2/19/2026
Status: Closed

Base: canaryHead: fix/m4-signin-timing-leak


📝 Commits (4)

  • 33f1f09 fix(security): prevent timing attack in sign-in [MEDIUM]
  • a3953a5 test: add timing attack protection test
  • 2a1467d Merge branch 'canary' into fix/m4-signin-timing-leak
  • 975fa32 Merge branch 'canary' into fix/m4-signin-timing-leak

📊 Changes

2 files changed (+74 additions, -32 deletions)

View changed files

📝 packages/better-auth/src/api/routes/sign-in.test.ts (+57 -0)
📝 packages/better-auth/src/api/routes/sign-in.ts (+17 -32)

📄 Description

Description

Problem

Sign-in endpoint leaks account state through timing differences, enabling account enumeration.

Timing Leak:

  • User doesn't exist: ~100ms (hash dummy password)
  • User exists, no credential account: ~100ms (hash dummy password)
  • User exists, wrong password: ~100ms (verify password)
  • Valid credentials: ~100ms (verify password)

BUT the code path differences create measurable timing variations that reveal:

  • Whether an email is registered
  • Whether account has password authentication
  • Account authentication method

Attack: Attacker measures response times across thousands of requests to enumerate valid accounts.

Solution

Refactor to ensure constant-time execution:

  1. Fetch all data upfront (no early returns)
  2. Always perform exactly ONE crypto operation
  3. Single validation check at the end
  4. Generic error message for all failures

Result: All failure paths take ~100ms regardless of reason.

Impact

  • Severity: MEDIUM
  • Exploitability: High (automated timing analysis)
  • Scope: All email/password sign-in attempts

Testing

  • Verified timing consistency across failure scenarios
  • Confirmed no information leak in error messages
  • Tested valid/invalid credentials still work correctly

Security Considerations

This eliminates timing side-channels that could reveal account existence. All authentication failures now have identical timing characteristics.


Reviewer Focus:

  • Verify single crypto operation per code path
  • Check no early returns before final validation
  • Confirm error messages don't leak account state

Summary by cubic

Prevents account enumeration by making email/password sign-in responses constant-time. All failure paths now share the same code path, timing, and error.

  • Bug Fixes
    • Perform exactly one crypto operation per request (verify if a hash exists, else hash).
    • Combine all checks into a single final validation; no early returns.
    • Return a generic "Invalid credentials" error and log once without leaking account state.
    • Add a timing test comparing non-existent user vs. wrong password to enforce consistent latency.

Written for commit 975fa32365. Summary will update on new commits.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/better-auth/better-auth/pull/8068 **Author:** [@Oluwatobi-Mustapha](https://github.com/Oluwatobi-Mustapha) **Created:** 2/19/2026 **Status:** ❌ Closed **Base:** `canary` ← **Head:** `fix/m4-signin-timing-leak` --- ### 📝 Commits (4) - [`33f1f09`](https://github.com/better-auth/better-auth/commit/33f1f097158ca3f44c19028f40855bc85241675f) fix(security): prevent timing attack in sign-in [MEDIUM] - [`a3953a5`](https://github.com/better-auth/better-auth/commit/a3953a503859f89be11874eb2fe1b4e7f8943ca8) test: add timing attack protection test - [`2a1467d`](https://github.com/better-auth/better-auth/commit/2a1467ded2a2405e1020660f596a8c0fde35228a) Merge branch 'canary' into fix/m4-signin-timing-leak - [`975fa32`](https://github.com/better-auth/better-auth/commit/975fa323655e4482bd0f59254e2f6c2ccd0ef26f) Merge branch 'canary' into fix/m4-signin-timing-leak ### 📊 Changes **2 files changed** (+74 additions, -32 deletions) <details> <summary>View changed files</summary> 📝 `packages/better-auth/src/api/routes/sign-in.test.ts` (+57 -0) 📝 `packages/better-auth/src/api/routes/sign-in.ts` (+17 -32) </details> ### 📄 Description ## Description ### Problem Sign-in endpoint leaks account state through timing differences, enabling account enumeration. **Timing Leak:** - User doesn't exist: ~100ms (hash dummy password) - User exists, no credential account: ~100ms (hash dummy password) - User exists, wrong password: ~100ms (verify password) - Valid credentials: ~100ms (verify password) **BUT** the code path differences create measurable timing variations that reveal: - Whether an email is registered - Whether account has password authentication - Account authentication method **Attack:** Attacker measures response times across thousands of requests to enumerate valid accounts. ### Solution Refactor to ensure constant-time execution: 1. Fetch all data upfront (no early returns) 2. Always perform exactly ONE crypto operation 3. Single validation check at the end 4. Generic error message for all failures **Result:** All failure paths take ~100ms regardless of reason. ### Impact - **Severity:** MEDIUM - **Exploitability:** High (automated timing analysis) - **Scope:** All email/password sign-in attempts ### Testing - [ ] Verified timing consistency across failure scenarios - [ ] Confirmed no information leak in error messages - [ ] Tested valid/invalid credentials still work correctly ### Security Considerations This eliminates timing side-channels that could reveal account existence. All authentication failures now have identical timing characteristics. --- **Reviewer Focus:** - Verify single crypto operation per code path - Check no early returns before final validation - Confirm error messages don't leak account state <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Prevents account enumeration by making email/password sign-in responses constant-time. All failure paths now share the same code path, timing, and error. - **Bug Fixes** - Perform exactly one crypto operation per request (verify if a hash exists, else hash). - Combine all checks into a single final validation; no early returns. - Return a generic "Invalid credentials" error and log once without leaking account state. - Add a timing test comparing non-existent user vs. wrong password to enforce consistent latency. <sup>Written for commit 975fa323655e4482bd0f59254e2f6c2ccd0ef26f. Summary will update on new commits.</sup> <!-- End of auto-generated description by cubic. --> --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-03-13 13:47:16 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#7724