SECURITY: A user with MFA enabled could bypass the MFA challenge by using a pre-existing auth cookie from a previous session. Vulnerability chain: 1. Auth::attempt() in LoginController created a Laravel session (unnecessary side effect — only credential validation was needed) 2. When MFA was required, the response did NOT revoke existing Sanctum tokens or expire the auth cookie 3. If the MFA session expired, the user could navigate directly to any page and the old auth cookie would authenticate them Fixes: - Replace Auth::attempt() with Hash::check() — no session created - Revoke ALL existing Sanctum tokens when MFA is required, so old sessions cannot bypass the challenge - Expire the auth cookie in the MFA-required response via forgetAuthCookie(), ensuring the browser discards stale tokens - Auth is now ONLY issued after successful MFA verification in MfaVerifyController New security tests (11 added): - MFA login returns no auth token or user data - MFA login expires the auth cookie - MFA login revokes all existing tokens - Old token returns 401 after MFA login - MFA session token cannot be used as Bearer token - MFA session consumed after successful verify (no replay) - MFA session survives failed verify (user can retry) - Auth cookie only issued on successful MFA verify - MFA session expires after TTL (10 minutes) - Email codes consumed after use (no replay) - Trusted device expires after 30 days Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
18 KiB
18 KiB