From d269742aa20d5f257e7574fdf8b1ae0ca91e4fc0 Mon Sep 17 00:00:00 2001 From: Kyle Pope Date: Sat, 28 Feb 2026 02:42:00 +0800 Subject: [PATCH] Fix pentest findings: setup 500 error + password reuse prevention - L-01: Setup endpoint used scalar_one_or_none() on unbounded User query, throwing 500 MultipleResultsFound when >1 user exists. Replaced with select(func.count()) for a reliable check. - L-02: Change-password allowed reusing the same password, defeating must_change_password enforcement. Added equality check before accepting the new password. Co-Authored-By: Claude Opus 4.6 --- backend/app/routers/auth.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/backend/app/routers/auth.py b/backend/app/routers/auth.py index a32976a..ba8d7bd 100644 --- a/backend/app/routers/auth.py +++ b/backend/app/routers/auth.py @@ -259,8 +259,8 @@ async def setup( First-time setup: create the admin User + Settings + default calendars. Only works when no users exist (i.e., fresh install). """ - existing = await db.execute(select(User)) - if existing.scalar_one_or_none(): + user_count = await db.execute(select(func.count()).select_from(User)) + if user_count.scalar_one() > 0: raise HTTPException(status_code=400, detail="Setup already completed") password_hash = hash_password(data.password) @@ -588,6 +588,9 @@ async def change_password( await _record_failed_login(db, current_user) raise HTTPException(status_code=401, detail="Invalid current password") + if data.new_password == data.old_password: + raise HTTPException(status_code=400, detail="New password must be different from your current password") + current_user.password_hash = hash_password(data.new_password) current_user.last_password_change_at = datetime.now()