Two problems with sign-count clone detection:
- suspicious_sign_count? flagged the case where both the stored and presented
counts are 0. Most synced passkeys (Apple/Google) report 0 every time, so every
legitimate sign-in was flagged — drowning real signals in noise. Per WebAuthn
§6.1.1 a 0 counter means "no counter"; only flag when BOTH counts are non-zero
and the new one does not advance.
- On a suspicious count the controller only logged a warning and then continued
to authenticate and overwrite the stored counter. A cloned credential therefore
worked indefinitely. webauthn_verify now rejects the sign-in (no session, no
counter update) and emails the user via a new SecurityMailer#suspicious_passkey_used.
Tests cover the corrected classification (synced/first-use/normal vs equal/
decreasing) and the new alert email.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>