{"record":{"id":"e707d41feeb47be7","repo":"zeroclaw-labs/zeroclaw","slug":"sign-counter-did-not-increase-new-count","errorCode":null,"errorMessage":"Sign counter did not increase ({new_count} <= {}). Possible cloned authenticator.","messagePattern":"Sign counter did not increase \\((.+?) <= (.+?)\\)\\. Possible cloned authenticator\\.","errorType":"exception","errorClass":null,"httpStatus":401,"severity":"critical","filePath":"crates/zeroclaw-runtime/src/security/webauthn.rs","lineNumber":467,"sourceCode":"\n        // The signed message is: authenticatorData || SHA-256(clientDataJSON)\n        let client_data_hash = ring::digest::digest(&ring::digest::SHA256, &client_data_bytes);\n        let mut signed_data = auth_data_bytes.clone();\n        signed_data.extend_from_slice(client_data_hash.as_ref());\n\n        let public_key_bytes = URL_SAFE_NO_PAD\n            .decode(&credential.public_key)\n            .context(\"Invalid base64url in stored public key\")?;\n\n        let sig_bytes = URL_SAFE_NO_PAD\n            .decode(&response.signature)\n            .context(\"Invalid base64url in signature\")?;\n\n        verify_es256_signature(&public_key_bytes, &signed_data, &sig_bytes)?;\n\n        // 5. Verify and update sign counter (clone detection)\n        if new_count > 0 || credential.sign_count > 0 {\n            anyhow::ensure!(\n                new_count > credential.sign_count,\n                \"Sign counter did not increase ({new_count} <= {}). Possible cloned authenticator.\",\n                credential.sign_count\n            );\n        }\n\n        // Update the sign counter\n        if let Some(user_creds) = all_credentials.get_mut(&credential.user_id)\n            && let Some(cred) = user_creds\n                .iter_mut()\n                .find(|c| c.credential_id == response.id)\n        {\n            cred.sign_count = new_count;\n        }\n        self.save_all_credentials(&all_credentials)?;\n\n        Ok(())\n    }","sourceCodeStart":449,"sourceCodeEnd":485,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-runtime/src/security/webauthn.rs#L449-L485","documentation":"finish_authentication enforces WebAuthn clone detection: when counters are in use (the new count is > 0 or the stored credential sign_count is > 0), each authentication must strictly increase the signature counter. A counter that fails to increase indicates a replayed assertion or a cloned authenticator, and the error flags possible credential cloning.","triggerScenarios":"The same assertion being processed twice (double-submit, replayed request, missing idempotency); a genuinely cloned credential used on two devices; some authenticators with buggy counters that plateau; restoring a passkey from a backup onto a second device; test harnesses always signing with the same counter value.","commonSituations":"Retry logic in the frontend resubmitting a finish request; proxy retries duplicating a POST; users restoring synced passkeys across devices; QA fixtures reusing canned assertions.","solutions":["Treat as a security event: reject the login, audit-log it, and offer the user re-registration of the credential","Make the finish endpoint idempotent per ceremony (one challenge = one successful finish) so replays cannot reach counter validation","In tests, increment the authenticator model's sign counter between assertions","If a specific authenticator model is known to never increment counters, prefer counter=0 consistently rather than mixed values"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"catch this error separately from other auth failures: deny the login (401), invalidate the session, write an audit event (user, credential id, counters), and notify/offer re-registration — never retry and never bypass the counter check","preventionTips":["Make the finish endpoint idempotent per ceremony so double-submits are dropped before signature verification","Disable automatic retries of auth-finish requests in frontend HTTP clients","In test harnesses, always increment the sign counter between assertions","Monitor for repeat counter failures per credential — a pattern indicates cloning or a firmware bug"],"tags":["webauthn","clone-detection","security","sign-counter","replay","rust"],"backgroundTag":"webauthn-clone-detected","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}