Problem
Several unauthenticated endpoints disclose whether an email/username corresponds to an existing account:
POST /api/auth/register → 409 "Username or email already exists" when the email or username matches an existing row
POST /api/auth/login → distinguishable responses for unknown user vs invalid password (LOGIN_USER_NOT_FOUND)
POST /:id/collaborators (authenticated, owner-only) → 404 unknown email vs 409 duplicate
An attacker can probe which emails are registered. Noted during review of PR #80.
Why not fixed in #80
The leak originates in the public auth endpoints; hardening only the collaborator endpoint would degrade owner UX without removing the disclosure. A proper fix spans multiple surfaces and needs care around UX.
Proposed direction
- Uniform error responses for registration failures (single generic message regardless of which field collided)
- Same generic message for unknown-user and bad-password on login
- Add rate limiting (e.g. express-rate-limit) on auth routes to make probing expensive
- Revisit collaborator add responses once auth surfaces are uniform
Problem
Several unauthenticated endpoints disclose whether an email/username corresponds to an existing account:
POST /api/auth/register→ 409 "Username or email already exists" when the email or username matches an existing rowPOST /api/auth/login→ distinguishable responses for unknown user vs invalid password (LOGIN_USER_NOT_FOUND)POST /:id/collaborators(authenticated, owner-only) → 404 unknown email vs 409 duplicateAn attacker can probe which emails are registered. Noted during review of PR #80.
Why not fixed in #80
The leak originates in the public auth endpoints; hardening only the collaborator endpoint would degrade owner UX without removing the disclosure. A proper fix spans multiple surfaces and needs care around UX.
Proposed direction