FreeThe +45-page Authentication Analytics Whitepaper — measuring real login journeysDownload
Back to Overview

Signal API iOS Bug: Passkeys of Other Accounts Deleted

On iOS and macOS 26 the WebAuthn Signal API deletes passkeys of unrelated accounts. Our reproduction, the affected methods and the trade-off you face.

Vincent Delitz
Vincent Delitz

Created: August 21, 2026

Updated: August 21, 2026

Signal API iOS Bug: Passkeys of Other Accounts Deleted
Key Facts
  • On iOS and macOS 26 the WebAuthn Signal API removes passkeys it was never called for: 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.
  • The affected account has to be stored as a combined password and passkey entry in the Passwords app, which only happens when the password was saved through the iOS system save prompt. A password added manually inside the Passwords app does not trigger it.
  • Only the two removal methods are affected. signalCurrentUserDetails, which updates the user name, stays correctly scoped. The same split holds for the native counterparts reportAllAcceptedPublicKeyCredentials and reportUnknownPublicKeyCredential.
  • Reproduced on iOS 26.0.1, 26.5 and 26.6.1, so the behavior has been present since the Signal API shipped with iOS 26.0 in September 2025. There is no fix at the time of writing.
  • Deleted passkeys stay recoverable in the Deleted section of the Passwords app for 30 days, and nothing tells the user, so affected users silently fall back to password login.

1. Introduction#

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.

PasskeysCheatsheet Icon

Passkeys Cheatsheet. Practical guidance, rollout patterns and KPIs for passkey programs.

Get Cheat Sheet

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:

  1. What exactly happens? Which passkeys get deleted and under which conditions.
  2. Which of the three signal methods are affected? We tested all of them against the same setup.
  3. What should you do about it? Which trade-off you face, and why we still recommend using the Signal API.

2. Signal API in a nutshell#

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:

MethodScoped byWhat it does
signalCurrentUserDetailsrpId + user handleupdates the user name shown for a passkey
signalAllAcceptedCredentialsrpId + user handleremoves passkeys not in the list you pass
signalUnknownCredentialrpId + credential IDremoves 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.

3. What we observe on iOS and macOS 26#

3.1 Setup#

The reproduction needs two accounts on the same RP ID with different user names and different user handles:

  • account1: has a passkey
  • account2: has a passkey and a password

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.

3.2 What happens#

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:

  • account1's passkey is deleted, which is correct
  • account2's passkey is deleted as well, although its user handle was never passed
  • account2's password survives, only the passkey is gone

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.

Debugger Icon

Experiment with passkey flows in the Passkeys Debugger.

Try for Free

4. Which signal methods are affected#

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.

MethodScoped byWhat it doesTouches other accounts
signalCurrentUserDetailsrpId + user handleupdates metadatano
signalAllAcceptedCredentialsrpId + user handleremovesyes
signalUnknownCredentialrpId + credential IDremovesyes

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.

5. Impact for relying parties#

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:

  • Users lose a working passkey for an account you never signalled about. They find out at their next login, when the passkey is simply gone.
  • Nothing surfaces to you. Signal methods deliberately return no information about what the authenticator did, so there is no error to log and no callback to observe.

  • It only hits multi-account users. Anyone with a private and a work login, family members sharing a device, retail or banking customers with several accounts. You cannot measure that population from your backend, because what matters is which accounts share one Apple ID.
  • Recovery exists but is invisible. The passkey sits in Passwords under Deleted for 30 days. Almost nobody will look there.

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.

6. Trade-off you have to make#

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:

  • keep signalCurrentUserDetails, it is correctly scoped and it solves a real problem with stale user names
  • both removal methods are affected in the same way, so there is no safer one of the two to switch to
  • never send an empty allAcceptedCredentialIds unless you really mean "remove everything for this user", because that is a deletion and therefore triggers the bug
  • no change for Chrome and Google Password Manager, where the effect is hiding rather than deleting and can be reversed
  • brief your support team: Passwords, then Deleted, within 30 days
Ben Gould Testimonial

Ben 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 Community

7. Status and next steps#

We 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.

Substack Icon

Subscribe to our Passkeys Substack for the latest news.

Subscribe

8. How Corbado can help#

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.

  • Login Methods shows the passkey and password split per method with success, failure and cancel rates, so a drop in passkey logins surfaces as a trend rather than a support ticket.
  • Technology breaks the same outcomes down by OS and browser, which is what separates an iOS 26 regression from everything else happening on your login page.
  • Passkey Insights tracks your credential population by authenticator, transport and sync status, so passkeys that vanish from devices show up as a shrinking inventory.
  • User Search reconstructs a single user's authentication timeline, which is how you confirm that a working passkey stopped being offered between two sessions.

Telemetry is UUID only with zero PII by design, hosted in EU data centers.

9. Conclusion#

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.

  • What is broken? Both signal methods that remove a credential can delete passkeys of other accounts on the same RP ID, if those accounts are stored as a combined password and passkey entry in the Passwords app.
  • What still works? signalCurrentUserDetails is correctly scoped, and non-Apple platforms are not affected in the same way.
  • What can you do? In our view, keep using the Signal API: stale passkeys in Conditional UI hurt more users far more often than this bug does. Make sure your support team knows about the Deleted section of the Passwords app.
Corbado

About Corbado

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

Frequently Asked Questions#

Does signalAllAcceptedCredentials delete passkeys of other accounts on iOS?#

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.

Which WebAuthn Signal API methods are affected on iOS?#

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.

Which iOS versions are affected by the Signal API passkey deletion bug?#

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.

Can users recover a passkey that was deleted by the Signal API?#

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.

See how Corbado fits your passkey rollout and existing authentication stack.

Explore the Console

Share this article


LinkedInTwitterFacebook