XSS Is Deadly for Passkeys: The Hidden Risk of Attestation None

https://lobste.rs/rss Hits: 31
Summary

A single XSS vulnerability can turn passkeys from a phishing-resistant login mechanism into a persistent account takeover backdoor. If malicious JavaScript can run on your page, it may be able to register an attacker-controlled passkey against the victim’s account. The user sees nothing, the website records a successful registration, and the attacker walks away with a valid authentication backdoor.For an organisation, that means more than “someone found XSS”. It means identity compromise, persistence, audit-trail ambiguity, regulatory exposure, and a security control that appears to have worked while silently enabling an attacker.The uncomfortable truth is that while passkeys do bring amazing benefits, and I think that everyone should use them, there is a dangerous gap in the threat model that's being overlooked by almost everyone I speak to. This blog post explains the risk, demonstrates how this is possible, and what the effective defences look like.IntroductionBefore we get started, if you'd like a brief overview of how passkeys work, you can jump over to my Passkeys 101 blog post, where I explain the basics. I'm going to assume in this blog post that you understand the concept of passkeys, and we're going to look at how they work in more detail in this post.We also need to establish some terminology to make the rest of this blog post easier to understand:Relying Party: The website or application that stores and verifies a user's passkey credential for authentication. Authenticator: The user’s device or password manager that creates, stores, and uses the private key to prove the user’s identity to the Relying Party.Attestation: The mechanism an Authenticator can use during registration to prove what kind of hardware created the credential.How Passkey Registration WorksWhen registering a passkey with an RP like Report URI, JavaScript will make a call out to fetch the data it needs:const optRes = await fetch('/passkeys/register_get_options/' + getCsrfToken(), { met...

First seen: 2026-05-20 19:46

Last seen: 2026-05-22 02:10