AOSSIE-Org / AOSSIE-Org/DebateAI

[BUG]: Password reset code stored in cleartext — vulnerable to offline brute-force by anyone with DB read access

Offen
#507 1 Kommentar 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
bug
Vorherrschende Sprache
TypeScript
Sterne
84
Forks
198
Ø Merge
2 T. 19 Std.
Gemergte PRs (30 T.)
30

Beschreibung

### Bug Description

The 6-digit password reset code is stored in the database in cleartext (`resetPasswordCode` field), and `VerifyForgotPassword` compares the submitted code directly against it. Because the code is only 6 digits (~1,000,000 possibilities), anyone who can read the database (a leaked backup, a compromised read replica, an insider, or a breach) can brute-force all possible codes offline and reset any user's password.

**Affected code** (`backend/controllers/auth.go`):
- `ForgotPassword` stores the raw code:
```go
"resetPasswordCode": resetCode,
```
- `VerifyForgotPassword` matches on the raw code:
```go
FindOne(dbCtx, bson.M{"email": request.Email, "resetPasswordCode": request.Code})
```

**Why a plain hash isn't enough:** a fast generic hash (e.g. SHA-256) of a 6-digit code is trivially reversible — an attacker just hashes all 10^6 codes and matches. So the standard fixes are:
1. **Store a server-keyed HMAC** of the code (HMAC with a secret key from config), and compute the same HMAC during confirmation. Without the server key, a DB reader can't precompute matches. OR
2. **Use a high-entropy random token** (e.g. 32+ bytes) instead of a 6-digit code, so brute-force is infeasible even if stored as-is or plainly hashed.

This was flagged by CodeRabbit (CWE-312, Cleartext Storage of Sensitive Information) during review of #485. It's pre-existing behavior — #485 only added code expiry — so it's tracked here as a separate follow-up.

Note: #485 already reduces the exposure window by expiring codes after 15 minutes, but the offline brute-force risk on a stored code remains until the code is HMAC'd or replaced with a high-entropy token.

@Ri1tik flagged by CodeRabbit during review of my #485 PR (reset-code expiry). It's pre-existing and separate from that PR, so I've filed it here as a follow-up. Could you assign this to me? I'll implement it as a server-keyed HMAC of the reset code (with the same HMAC computed at confirmation) so the stored value isn't brute-forceable, keeping the change scoped to the reset flow.

### Steps to Reproduce

1. Request a password reset for any account.
2. Inspect the user document in MongoDB (e.g. via mongosh or a DB viewer).
3. Observe `resetPasswordCode` is stored as the plain 6-digit code.
4. An attacker with read access could match/brute-force it offline against the confirmation logic.

### Logs and Screenshots

backend/controllers/auth.go — ForgotPassword:
"resetPasswordCode": resetCode, // stored in cleartext

backend/controllers/auth.go — VerifyForgotPassword:
FindOne(..., bson.M{"email": request.Email, "resetPasswordCode": request.Code}) // direct match

Flagged by CodeRabbit as CWE-312 during review of #485.

### Environment Details

- File: backend/controllers/auth.go (ForgotPassword, VerifyForgotPassword)
- Backend: Go / MongoDB
- Branch: main
- Related: follow-up to #485 (which adds expiry); this is a separate hardening concern (cleartext storage)
- Suggested fix: HMAC the code with a server-side secret, or switch to a high-entropy token

### Impact

Medium - Feature works but has issues

### Code of Conduct

- [x] I have joined the [Discord server](https://discord.gg/hjUhu33uAn) and will post updates there
- [x] I have searched existing issues to avoid duplicates

Beitragsleitfaden

Für dieses Repository ist kein Beitragsleitfaden indexiert

Rechercherichtung

Start in backend/controllers/auth.go at ForgotPassword and VerifyForgotPassword, then trace the existing reset-code configuration and expiry flow from related issue #485. Done means the database no longer stores a directly brute-forceable reset code, confirmation still succeeds for valid codes, and expired codes remain rejected.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
go, mongodb
Bereich
authentication, backend, security
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Aktiv
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
62/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.