MetaMask / MetaMask/metamask-mobile
[Bug]: Seedless (Sign in with Apple) wallet permanently rate-limited after reinstall: lock re-arms to 24h on every attempt, password never evaluated, support cannot reset
- Dominant language
- TypeScript
- Stars
- 3k
- Forks
- 1.7k
- Avg merge
- 1d 14h
- Merged PRs (30d)
- 669
Description
### Describe the bug
A seedless wallet created with **Sign in with Apple** on MetaMask iOS cannot be unlocked after the app was deleted and reinstalled. Every unlock returns **"Too many attempts. Try again in 23:59:xx"**. The **incorrect-password error has never appeared once**, from the very first attempt after the reinstall. The password is the Apple-generated one saved in iCloud Keychain and has never changed; it unlocked the wallet daily for a week before the reinstall.
The lock **re-arms to a full 24 hours on every attempt** and the guess counter **never decays**. Controlled test: zero attempts for 2 days, then 3 days, then about 4 days; the first attempt after each wait returned a fresh 24:00 lock. Zero attempts since August 23, so the account is in whatever state the nodes hold right now.
MetaMask Support (tickets #121135651 and #127213997) has stated in writing that support cannot read or reset the per-account rate-limit counters on the TOPRF key-share nodes and has no admin override. The Builder Hub (topic 3504) says it is out of scope for the developer forum. So there is currently **no path for an affected user to regain access**, even with the correct credentials.
Client-side observation, verified in the shipped `@metamask/toprf-secure-backup@1.1.0`: `validateSeed` in `dist/toprfEvalRequest.mjs` throws `rateLimitExceeded` from `checkRateLimitErrors` **before** `filterCompletedRequests` and before the `TOPRF_EVAL_THRESHOLD = 3` check, so a single rate-limited node aborts a recovery that three healthy nodes could serve, and the UI shows only the maximum lock across nodes. Whether one node or all five are locked on this account is not observable from the client.
A fuller write-up with account identifiers was sent to bugbounty@consensys.net on 2026-09-14 (UTC). Identifiers are deliberately not posted here; happy to share them privately with anyone on the onboarding team.
### Expected behavior
Either the correct password is evaluated once the stated cooldown expires, or the counter decays with time as the "try again in X" message implies. A lock that re-arms on every attempt and never decays is a permanent lockout.
### Screenshots/Recordings
Not attached. Producing a new screenshot requires a new attempt, which re-arms the 24h lock; I am avoiding that until someone can read the node-side state.
### Steps to reproduce
1. Create a wallet on MetaMask iOS with Sign in with Apple (this one: July 23, 2026), accepting Apple's suggested strong password (saved to iCloud Keychain).
2. Use it normally for a week (Face ID unlock).
3. Delete the app (July 30). Reinstall from the App Store (July 31). Choose "I have an existing wallet", Sign in with Apple.
4. Apple sign-in succeeds and the wallet is found. At the unlock step, enter the saved password (AutoFill).
5. Observe only "Too many attempts" with escalating waits (3 min → 10 → 30 → 45 → 24 h). Never "incorrect password".
6. Wait 2, 3, 4 days with zero attempts. First attempt after each wait: fresh 24:00 lock.
7. Same result on the Chrome extension (13.44.0.0), whose state shows `firstTimeFlowType: socialImport`, no local vault, `completedOnboarding: false` — the unlock screen is issuing the network recovery call.
### Error messages or log output
UI string only: `Too many attempts. Try again in 23:59:xx` (i18n `unlockPageTooManyFailedAttempts`, thrown as `SeedlessOnboardingController - Too many login attempts`). No raw payload captured; capturing one needs a new attempt.
### Where was this bug found?
Live version (from official store)
### Version
App Store build current on July 31, 2026 at the reinstall (8.4.x era); exact build number not recorded. The lock persists on today's 8.10.1 as far as can be told without attempting.
### Build number
Not recorded
### Build type
_No response_
### Device
iPhone, iOS 26.5.2
### Operating system
iOS
### Additional context
- Support conversation history: chat Aug 1 (agent Nyx), ticket #121135651 Aug 3–16 (agents Kirk/Sam, resolved "nothing we can do"), ticket #127213997 Aug 23 (resolved Aug 24 with no reply).
- Builder Hub topic: https://builder.metamask.io/t/3504
- Related: #27384 was a different seedless permanent-lockout (local vault format); this one is node-side.
- Funds are in the wallet's Bitcoin account. I will never share the password or a recovery phrase, and I am not asking for either to be recovered; I am asking for the node-side rate-limit state to be inspected and, if it cannot decay, reset.
Contributor guide
Research direction
The client observation is in @metamask/toprf-secure-backup@1.1.0, specifically dist/toprfEvalRequest.mjs: validateSeed, checkRateLimitErrors, filterCompletedRequests, and TOPRF_EVAL_THRESHOLD = 3. Start by tracing that recovery path and determining the per-account state on the TOPRF key-share nodes. Done means the correct password can be evaluated after cooldown, or counters decay or reset without a permanent lockout; account identifiers should be shared privately.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- ios, react-native, typescript
- Domain
- authentication, backend-api-design, security
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100