You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Password managers can capture the TOTP secret from the setup QR and then autofill a mismatched code at login, cascading into a rate-limited lockout that the email fallback can't rescue.
I've been gobsmacked by this myself with 1password, and I recently saw a colleague go through exactly the same confusion.
Summary
Modern browser password managers that support built-in TOTP — 1Password, Apple Passwords / iCloud Keychain, Google Password Manager, Bitwarden, Dashlane, Proton Pass, NordPass, and others — can capture the otpauth:// provisioning URI encoded in the TOTP setup QR code and store it when the QR is visible on the profile page (depending on the manager and version, on page render or on an explicit scan/save action), before and independently of the user completing setup in Two-Factor. This creates a class of failures where the password manager holds a TOTP secret that the user's Two-Factor profile does not, and then "helpfully" autofills codes at login that cannot succeed. The resulting failed attempts push the account into the rate limiter, and because the same rate limiter also gates the emailed-code fallback, the user's escape hatch fails too.
This is not a single-vendor problem — any password manager with integrated OTP behaves this way, because it is the intended behavior of the otpauth:// standard. The existing tracker coverage is scattered and vendor-specific (Apple Passwords / Google in #880/#904, Safari prefill in #678, Bitwarden timing in #580), so there is no manager-agnostic description of the root cause or the cascade.
This issue is filed to capture the root cause and the end-to-end chain, which no single existing issue documents. Several issues cover individual links, but the origin (password-manager capture) and the cascade are undocumented.
The failure chain
Capture. The user opens their profile to set up TOTP. The QR renders (otpauth://totp/..., class-two-factor-totp.phpgenerate_qr_code_url() / js/totp-admin-qrcode.js). The password-manager browser extension can read the provisioning URI and offer to save a login item with an embedded OTP secret. The user accepts — reasonably believing this is how you set up 2FA.
Incomplete setup. The user does not click the inline "Verify" button (class-two-factor-totp.php:408) that actually performs POST /two-factor/1.0/totp and stores _two_factor_totp_key. They may click "Update Profile" and leave, assuming they are done. (Since fix: Ensure two-factor methods are fully configured before enabling them #798, the profile save now refuses to enable an unconfigured method, so TOTP ends up not enabled — but the password manager still holds a secret.)
Login mismatch. At the next login, the user is challenged for whichever method is configured (often Email). The password manager, matching by domain rather than by method, autofills its stored TOTP one-time code into the challenge field. That code is wrong — either because TOTP was never enabled, or because it's being injected into an Email (two-factor-email-code) field. The user submits it, unaware the manager pre-filled a bad value.
The net effect: a user who never intended to misconfigure anything is locked out, and every affordance the UI offers to recover is either pre-poisoned by the password manager or gated by the same rate limiter.
Why this isn't already covered
Link
Existing coverage
Gap
Two-button setup (Verify vs. Update Profile) saving an inconsistent state
Install 1Password or enable Apple Passwords in the browser.
Go to your WordPress profile with Two-Factor active and expand the Authenticator App (TOTP) setup.
Observe the password manager offer to save a login item with a one-time password from the visible QR (on page render or when you invoke its scan/save action, depending on the manager).
Accept the save, but do not click "Verify" and do not complete setup.
Log out and log back in. Observe the password manager autofill a TOTP code into the 2FA challenge field, even though TOTP was never enabled / the challenge is for a different method.
Notes / technical anchors
The setup verify field already sets autocomplete="off" (class-two-factor-totp.php:406), but that does not stop the extension from reading the otpauth:// URI in the rendered QR — capture keys off the QR/provisioning URI, not the input field.
The login email field sets autocomplete="one-time-code" (class-two-factor-email.php:367) and the login TOTP field sets it too (class-two-factor-totp.php:792), which is what invites cross-method autofill into whichever challenge is shown.
Possible directions (for discussion, not prescriptive)
Reduce silent capture: consider whether the QR/provisioning URI can be revealed only on an explicit user action (e.g., behind a "Show QR code" control) so managers don't auto-detect it on page load. This trades a little convenience for far less accidental capture.
Confirm intent before the manager can act: surface a clear "You must click Verify to finish — saving this in a password manager is not enough" affordance next to the QR.
Detect and warn on mismatch at login: when a submitted code fails validation for the active method but would be a plausible TOTP, hint that an autofilled code from a password manager may be involved.
Problem:
I've been gobsmacked by this myself with 1password, and I recently saw a colleague go through exactly the same confusion.
Summary
Modern browser password managers that support built-in TOTP — 1Password, Apple Passwords / iCloud Keychain, Google Password Manager, Bitwarden, Dashlane, Proton Pass, NordPass, and others — can capture the
otpauth://provisioning URI encoded in the TOTP setup QR code and store it when the QR is visible on the profile page (depending on the manager and version, on page render or on an explicit scan/save action), before and independently of the user completing setup in Two-Factor. This creates a class of failures where the password manager holds a TOTP secret that the user's Two-Factor profile does not, and then "helpfully" autofills codes at login that cannot succeed. The resulting failed attempts push the account into the rate limiter, and because the same rate limiter also gates the emailed-code fallback, the user's escape hatch fails too.This is not a single-vendor problem — any password manager with integrated OTP behaves this way, because it is the intended behavior of the
otpauth://standard. The existing tracker coverage is scattered and vendor-specific (Apple Passwords / Google in #880/#904, Safari prefill in #678, Bitwarden timing in #580), so there is no manager-agnostic description of the root cause or the cascade.This issue is filed to capture the root cause and the end-to-end chain, which no single existing issue documents. Several issues cover individual links, but the origin (password-manager capture) and the cascade are undocumented.
The failure chain
otpauth://totp/...,class-two-factor-totp.phpgenerate_qr_code_url()/js/totp-admin-qrcode.js). The password-manager browser extension can read the provisioning URI and offer to save a login item with an embedded OTP secret. The user accepts — reasonably believing this is how you set up 2FA.class-two-factor-totp.php:408) that actually performsPOST /two-factor/1.0/totpand stores_two_factor_totp_key. They may click "Update Profile" and leave, assuming they are done. (Since fix: Ensure two-factor methods are fully configured before enabling them #798, the profile save now refuses to enable an unconfigured method, so TOTP ends up not enabled — but the password manager still holds a secret.)two-factor-email-code) field. The user submits it, unaware the manager pre-filled a bad value.Two_Factor_Corerate limiting (see Rate-limit error message is alarming and its countdown is stale for legitimate users #918, Email resend bypasses retry delay in 2FA challenge flow #847).The net effect: a user who never intended to misconfigure anything is locked out, and every affordance the UI offers to recover is either pre-poisoned by the password manager or gated by the same rate limiter.
Why this isn't already covered
Reproduction (capture step)
Notes / technical anchors
autocomplete="off"(class-two-factor-totp.php:406), but that does not stop the extension from reading theotpauth://URI in the rendered QR — capture keys off the QR/provisioning URI, not the input field.autocomplete="one-time-code"(class-two-factor-email.php:367) and the login TOTP field sets it too (class-two-factor-totp.php:792), which is what invites cross-method autofill into whichever challenge is shown.autocomplete="off"(class-two-factor-core.php:1130), which interacts badly with the per-field hints — this is the same conflict already noted in TOTP codes from Apple Passwords are wiped on the login screen #880/fix: prevent autofilled TOTP codes from being wiped on login #904.Possible directions (for discussion, not prescriptive)
Related