Acme Co. checkout
Imagine this page is mid-checkout and embedded the third-party widget below to handle
"passkey-based payment confirmation". The integration docs told us to grant
allow="publickey-credentials-create publickey-credentials-get", so we did.
publickey-credentials-{create,get}=() —
the API is unreachable from inside them. Your allow= attribute is what gave
this iframe the power to fire WebAuthn. Click Verify with passkey in the widget
and watch your browser show a passkey-registration prompt branded for
evil-cyber-hacker.com — a domain you don't trust, on a page you do.
💡 Origin binding still does most of the work for the worst attacks: the iframe cannot register a passkey for this site (RP ID must match the iframe's own origin or an ancestor). What it can do is harvest a passkey at its OWN RP using your eyeballs, track you across every site that embeds it, and probe whether you have credentials registered there. Permissions Policy stops all of that.
By default, a cross-origin iframe sees
publickey-credentials-create=() and
publickey-credentials-get=() — the WebAuthn API simply throws on call.
The allow= attribute on the parent's <iframe> tag
delegates the capability from the parent's origin to the iframe's origin. We
granted that delegation legitimately for the widget's stated purpose. If the widget is
ever compromised — or its operator has different intentions than they claimed — that
delegation is now an attack surface.
What origin binding does and doesn't do: the iframe at
evil-cyber-hacker.com cannot register a credential bound to this site's RP
(RP ID must be the iframe's own origin or its ancestor). What it CAN do: register a
credential at evil-cyber-hacker.com using your authenticator inside this
page's context, silently probe for existing credentials there, surface conditional-UI
autofill suggestions to fingerprint you across sites. Permissions Policy stops all of
that.
Activity log
Messages from the iframe (via postMessage) plus any Permissions-Policy violations the browser reports.