My first CVE: AliasVault's passkey bridge trusted the page
On June 4, 2026, I reported an origin validation bug in the AliasVault browser extension. The maintainers confirmed it, reviewed my patch, and released version 0.29.4 about eight hours after the initial report.
The advisory was published two weeks later as CVE-2026-55587, with High severity and a CVSS score of 8.1. It is my first CVE.
The bug was in the extension’s WebAuthn bridge. A website could supply the origin and relying party ID used for a passkey request. AliasVault accepted those values without checking them against the page that sent the request.
An attacker page could therefore ask for a passkey assertion belonging to another site. The user still had to approve the AliasVault prompt. By then, the prompt was operating on a forged website identity.
Where the trust boundary broke
WebAuthn binds a credential to a relying party. When a site requests an assertion, the browser checks that the RP ID is valid for the current origin. A page on attacker.example cannot normally request a credential for victim.example.
AliasVault implements passkeys through a bridge between page JavaScript, a content script, and the extension background process. The page-facing side used CustomEvent messages including:
aliasvault:webauthn:get
aliasvault:webauthn:create
Any script on the page can dispatch a CustomEvent, so every value in event.detail is untrusted input.
The affected bridge forwarded three security-sensitive values from that payload:
event.detail.origin
event.detail.publicKey.rpId
event.detail.publicKey.rp.id
Those values reached passkey lookup and response generation without being checked against window.location. The extension had recreated part of the browser’s WebAuthn path, but it had not recreated the origin and RP validation that makes the path safe.
What the proof showed
I used two controlled domains, victim.amarbego.dev and attacker.amarbego.dev. First I registered an AliasVault passkey for the victim domain. Then the attacker page dispatched the extension’s bridge event with the victim origin and RP ID in its payload.
After I approved the AliasVault popup, the attacker page received a valid assertion. The decoded clientDataJSON claimed:
{
"type": "webauthn.get",
"origin": "https://victim.amarbego.dev",
"crossOrigin": false
}
The assertion was returned to https://attacker.amarbego.dev. That mismatch was the bug: attacker-controlled JavaScript selected the website identity recorded in the signed WebAuthn data.
An account attack would also need a valid challenge for the victim account, usually obtained or relayed through a phishing flow. The victim needed the extension installed and unlocked, passkey handling enabled, a stored credential for the target RP, and then had to approve the prompt. The issue did not expose the vault or master password, and it could not run silently.
Those conditions reduce the number of affected sessions. They do not restore WebAuthn’s origin binding. User approval only helps when the authenticator is approving the right origin and RP.
The patch
The fix landed in AliasVault 0.29.4 as commit a60d096.
The patched bridge derives trust from the current page context. It validates the request origin, checks the RP ID under WebAuthn’s domain rules, and rejects forged bridge messages before they reach the signing flow.
There is no practical workaround for affected versions. AliasVault users need browser extension 0.29.4 or later. The server, web app, and mobile apps were unaffected, and the advisory reports no known exploitation in the wild.
Disclosure timeline
- June 4, 15:29 UTC: I sent the report and proof of concept.
- June 4, 16:56 UTC: AliasVault confirmed the issue and started reviewing the fix.
- June 4, 23:06 UTC: version 0.29.4 was public.
- June 18, 07:30 UTC: the security advisory was published.
The maintainers handled this well. They reproduced the issue, reviewed the patch, tested it, and shipped it on the same day instead of leaving users exposed while the advisory paperwork caught up.
The extension owns the boundary
A browser extension does not inherit browser security checks merely because it exposes an API that looks like a browser API. Once an extension intercepts WebAuthn and carries requests across a page-to-extension bridge, it owns the validation at that boundary.
Content scripts are privileged relative to the page, but messages arriving from page JavaScript are still attacker-controlled. Origin, hostname, RP ID, extension message type, and any lookup key derived from them need to be checked at the point where the extension crosses into privileged code.
The popup did exactly what it was built to do: ask before signing. The request had already lied about which website was asking. Confirmation UI cannot repair an identity check that never happened.
I am glad to have my first CVE number. Version 0.29.4 closed the hole within one working day, and the advisory gives other passkey-provider authors a concrete failure mode to test for.