54bc6ef2118e43ebb079c2aa7a59217fc56bf79c
handleChangePassword revoked other sessions but never cleared webauthn_credentials, and enrollment needs no step-up. A passkey planted through a transiently-hijacked session needs no password, so it survived the reset + session-revoke as a standing login foothold. Add DeleteAllPasskeyCredentialsForUser and call it in the change-password remediation so every passkey is unbound alongside the session revoke. Removing zero rows is a successful no-op. Email-OTP remains the fallback factor, so this never locks anyone out; the user re-enrolls a passkey afterward if they want one.
Languages
Go
62.7%
TypeScript
22.5%
Shell
7.4%
Java
7.1%
Dockerfile
0.2%
Other
0.1%