signalAllAcceptedCredentials and signalUnknownCredential can delete the passkey of a
different account on the same RP ID, whose user handle is never passed to the API.signalCurrentUserDetails, which updates the
user name, stays correctly scoped. The same split holds for the native counterparts
reportAllAcceptedPublicKeyCredentials and reportUnknownPublicKeyCredential.While adding WebAuthn Signal API support to our iOS SDK we found a bug in Apple's Passwords app: deleting a passkey for one account can delete the passkey of a completely different account. The user handle of that other account is never passed to the API.

Passkeys Cheatsheet. Practical guidance, rollout patterns and KPIs for passkey programs.
This is not a regression in a recent update. We reproduced it on iOS 26.0.1 as well as on 26.5 and 26.6.1, so it has been there since the Signal API shipped with iOS 26.0 in September 2025. A similar report has been open since November 2025 without a response, and we filed our own bug with a full reproduction on August 21, 2026. There is no fix yet.
In this article, we answer:
The Signal API lets a relying party tell the passkey provider what the server-side truth is, so that stale passkeys stop showing up in Conditional UI. It has three methods, and the distinction between them matters for this bug:
| Method | Scoped by | What it does |
|---|---|---|
signalCurrentUserDetails | rpId + user handle | updates the user name shown for a passkey |
signalAllAcceptedCredentials | rpId + user handle | removes passkeys not in the list you pass |
signalUnknownCredential | rpId + credential ID | removes one specific passkey |
Two of them remove credentials, one only updates metadata. All three exist natively as well, in
ASCredentialUpdater (iOS 26.0) and its successor ASCredentialDataManager (iOS 26.2), so
native apps are just as exposed as websites.
The scoping is not an implementation detail, it is the whole contract. WebAuthn Level 3 defines
the behavior of signalAllAcceptedCredentials on credentials map[rpId, userId], which means one
account, and Apple's native signature takes a userHandle for exactly that reason.
The reproduction needs two accounts on the same RP ID with different user names and different user handles:
One detail decides whether the bug appears: the password of account2 must have been saved through the system save prompt, the sheet iOS shows after a successful password login. A password that was added manually inside the Passwords app does not trigger it. The reason is what that prompt produces: when a password and a passkey exist for the same site with the same user name, the Passwords app combines them into a single entry.
We sign in as account1, delete its passkey server side and signal that to the device:
await PublicKeyCredential.signalAllAcceptedCredentials({ rpId: 'example.com', userId: '<user handle of account1>', allAcceptedCredentialIds: [], // account1 has no passkeys left });
Only account1 is referenced. In the Passwords app we then see:
The Deleted section of the Passwords app makes this very visible. Before the call it is empty, after the call it holds two passkeys for the same site, one for each account. Deleted passkeys stay recoverable there for 30 days, and nothing informs the user that anything happened.
Experiment with passkey flows in the Passkeys Debugger.
Our first assumption was that the user handle gets lost for passkeys inside a combined entry, so that the lookup falls back to matching the RP ID only. To check that, we added all three methods to our iOS SDK and ran them against the same two accounts.
| Method | Scoped by | What it does | Touches other accounts |
|---|---|---|---|
signalCurrentUserDetails | rpId + user handle | updates metadata | no |
signalAllAcceptedCredentials | rpId + user handle | removes | yes |
signalUnknownCredential | rpId + credential ID | removes | yes |
Group the results by the key a method matches on and nothing lines up: the two methods that use rpId plus user handle behave differently from each other. Group them by what they do and the picture is clean. Both methods that remove a credential reach into other accounts, the one that only updates metadata does not.
That rules out our first assumption. signalCurrentUserDetails uses the same rpId plus user handle
lookup, on the same entries, and it lands exactly on account1. The association between a passkey
and its user handle is therefore intact and can be queried correctly.
The result for signalUnknownCredential is even stronger, because that method matches on an exact
credential ID. WebAuthn Level 3 defines its authenticator action as walking the credential map and
removing the credential whose rpId and id both match. There is no reading of "remove this one
credential ID" that legitimately reaches a credential of a different account. Yet it does, and
again only the passkey part of the combined entry disappears while the password stays.
Our conclusion: the matching works, but the removal is applied to something coarser than the single
matched credential, most likely to the Passwords entry or to the set of entries resolved for the RP
ID. That would also explain the older report about signalUnknownCredential removing credentials
that were never specified.
The bug only fires when a signal call actually removes a passkey for the signalled account. As long as the list you send matches what the device holds, nothing is deleted and no other account is touched. The failure mode is quiet, which is what makes it expensive:
In your own data this shows up as an unexplained shift from passkey login back to password login, which is only visible if you measure your login funnels per method.
Before weighing the options, one property of the bug matters more than anything else: it is
triggered by deletions, not by calls. If you call signalAllAcceptedCredentials after every
login and the credential IDs you send match what the device holds, nothing is removed and no other
account is affected. Only the calls that really delete a passkey for the signalled account can take
a second account's passkey with them. Calling more often does not increase your exposure, deleting
more passkeys does.
That puts both sides of the trade-off on the same event: a passkey that is removed on your server.
Option A: stop calling the removal methods. Passkeys that users delete on your server stay in the Passwords app. They keep being offered in Conditional UI, users pick them, and the login fails. That is exactly the stale credential problem the Signal API was built to solve, and a passkey that fails at login is one of the most reliable ways to make someone give up on passkeys for good. This hits every user who deletes a passkey, and it hits them at the worst possible moment.
Option B: keep calling them. For each passkey you delete server side, a user who also has a second account on the same RP ID, under the same Apple ID, stored as a combined password and passkey entry, silently loses that second passkey. Worse per incident, but it needs several conditions to line up at once.
Our recommendation is to keep using the Signal API. For most relying parties the stale credential problem is the far more common situation: it affects everyone who deletes a passkey, while the cross-account deletion needs a second account, the same Apple ID and a combined entry created by the system save prompt. Trading a frequent, visible failure at login for a rare one is the better deal today. If multiple accounts per person are the norm in your product rather than the exception, run the numbers again, because then the picture can flip.
A few practical points either way:
signalCurrentUserDetails, it is correctly scoped and it solves a real problem with stale
user namesallAcceptedCredentialIds unless you really mean "remove everything for this
user", because that is a deletion and therefore triggers the bugBen Gould
Head of Engineering
I’ve built hundreds of integrations in my time, including quite a few with identity providers and I’ve never been so impressed with a developer experience as I have been with Corbado.
10,000+ devs trust Corbado & make the Internet safer with passkeys. Got questions? We've written 150+ blog posts on passkeys.
Join Passkeys CommunityWe filed WebKit bug 322267 with a full
reproduction and a screen recording. The WebKit tracker is public and the WebAuthn owners can be
reached there, which is why we chose it, even though the defect is not in WebKit: WebKit only
forwards the call to ASCredentialDataManager, so the fix has to happen in AuthenticationServices
and the Passwords app.
The open question we put to Apple is whether the removal is implemented on entry level instead of on credential level. We will update this article as soon as there is a response or a fixed version.
Subscribe to our Passkeys Substack for the latest news.
This bug never reaches your backend. The signal methods return nothing, the passkey disappears on the device and the only trace left is a user who quietly logs in with a password again. Corbado Observe is the authentication observability layer that makes that shift visible, on the login flow you already run today.
Telemetry is UUID only with zero PII by design, hosted in EU data centers.
The Signal API is still the right tool for keeping passkeys in sync between your server and your users' devices, and we are not arguing against adopting it. But the client side of passkeys is where the sharp edges are, and this one is sharp: a documented, user handle scoped API that removes credentials outside that scope, silently, on the most common passkey platform.
signalCurrentUserDetails is correctly scoped, and non-Apple platforms are
not affected in the same way.Corbado is the Passkey Intelligence Platform for large-scale CIAM teams running consumer authentication. We help you see what IDP logs and generic analytics tools can't: where passkeys, passwords, OTP, social login and fallback journeys succeed, stall or fail, which devices and browsers create friction, and when an OS update silently breaks login. Two products: Corbado Observe layers process mining and observability across authentication journeys. Corbado Connect adds managed passkeys with analytics built in alongside your IDP. VicRoads runs passkeys for 5M+ users with Corbado (+80% passkey activation). Talk to a Passkey Expert →
Yes. On iOS and macOS 26 a call to PublicKeyCredential.signalAllAcceptedCredentials() for one
account can delete passkeys of a different account on the same RP ID, if that other account is
stored as a combined password and passkey entry in the
Passwords app. The user handle of the affected account is never
passed to the API, so this contradicts both the WebAuthn specification and Apple's own API
signature, which is scoped to a user handle.
Both methods that remove a credential are affected: signalAllAcceptedCredentials and
signalUnknownCredential. signalCurrentUserDetails, which only updates the user name of a
passkey, is correctly scoped and does not touch credentials of other accounts. This holds for the
web methods as well as for their native counterparts reportAllAcceptedPublicKeyCredentials and
reportUnknownPublicKeyCredential in AuthenticationServices.
All iOS and macOS 26 versions we tested, from 26.0.1 up to 26.6.1. This is not a regression in a later point release. The Signal API shipped with iOS 26.0 in September 2025 and the behavior has been present since then. There is no fix available at the time of writing.
Yes, for 30 days. Deleted passkeys are moved to the Deleted section of the Passwords app and are permanently removed after 30 days. The problem is that nothing tells the user that a passkey was removed, so most affected users will never look there and will simply fall back to password login.
Related Articles
Table of Contents