Skip to content

WordPress plugin · High, 7.5 of 10 · patched

The two-factor plugin that let attackers bring their own passkey

Two-factor login exists for one bad day: the day a password leaks. This plugin, on 10,000 or more sites, added passkeys in version 6.2.9. A guard written for codes sent to an email address or a phone let anyone who knew the password of a user who signs in with a passkey add their own passkey to that account, in the middle of the login, and then sign in with it. The guard did not fit the new factor. It is public as CVE-2026-111949, scored 7.5 of 10 by WPScan, and credited to RIA Labs.

Patched

Read this part first

If your site uses a two-factor plugin with a passkey option, read the advisory. It names the plugin and the affected versions: 6.2.9 to 6.3.0. WPScan lists 6.3.1 as the fixed version. Update to it or later.

One caution. The plugin’s changelog for 6.3.1 does not name passkeys. The 6.3.1 code adds a check for this case: a pending login can no longer add a passkey to an account that already has two-factor set up. We read it but did not run it, so this post goes by WPScan’s record.

WPScan says updating closes the hole. Updating does not remove a passkey that was already added. Have each passkey user open their passkey list and remove any entry they did not add. Each entry shows the date it was added. If you find an extra one, or cannot check an account, change that account’s password and use Log Out Everywhere Else on its profile. If an administrator account had an extra passkey, treat the site as compromised. That is our own suggestion, not the advisory’s. WPScan is holding its proof of concept back until 19 November 2026. There is no exploit code below.

How bad it is

7.5 of 10, WPScan’s score: CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H. It is a takeover: signing in as the user, administrators included. Two conditions hold it below Critical. We read them as PR:L, the attacker knows the password, and AC:H, the victim already has a passkey set up. Remove both and the vector scores 9.8.

The first condition is the whole reason two-factor exists. Passwords are reused, phished and leaked. A second factor is supposed to make a stolen password not enough. Here it was enough.

We reported the narrower reading on purpose: a Subscriber victim, which we scored 4.8, because claiming administrators would have meant attesting to multisite behaviour we had not tested. We also saw the same takeover work against an administrator on a single site in our lab, and said so in the report as an observation. WPScan scored it 7.5, the number of record.

The fix that fit codes but not passkeys

This is not the first bug of this kind in this plugin. Earlier, CVE-2026-16036 showed that during the login challenge, the plugin did not tie the second factor being set up to the one the account already had, so someone who knew a password could rebind it. WPScan published it, crediting Artus KG as finder, and it was fixed in 6.2.7.

6.2.7, the release that fixed it, added one shared guard. It asked: is the method being set up the same as the one this account already uses? If yes, it let the request through and discarded any new destination, so a one-time code could only go to the address already on file. For codes sent to an email address or a phone, that is safe. There is no new address to steal.

Passkeys have no address on file. For a passkey, “same method as already set up” is not a safety check. It is a blanket permission to add another one. Passkeys arrived in 6.2.9, two releases after that fix, and the guard was never extended to cover them.

A quiet kind of takeover

The attacker types the victim’s password into the real login form. The plugin then serves the second-factor step. For a passkey user, the page offers only one thing: sign in with a passkey. There is no button to add one. But the server behind the page would still accept a request to register a new passkey on that account.

The attacker’s passkey was added next to the victim’s, not in place of it. The owner’s own passkey kept working. Nothing broke for the owner. The only trace we know of was one more dated entry in their passkey list.

How we know

A description is not a finding. We built a throwaway WordPress site with the plugin’s 6.2.9 release, and checked it against the official download file by file, 297 of them, with no difference. Both preconditions were made through the plugin’s real screens: the victim set up their own passkey in their own session, and we sent the victim’s real password to the real login form.

The attack requests came from a fresh session that carried no WordPress login cookie until the last step issued one. Broken copies of the same requests were refused. Then the sign-in as the victim worked. The same chain worked against an administrator victim.

What we did not test: a multisite install, the plugin’s enterprise multi-factor mode, which is off by default, and any firewall or rate limiter in front of a production site.

Three questions for your own security features

None of this is specific to one plugin. Any product that adds a new way to log in is worth asking these about.

  1. Which old guards assume the old feature’s shape? A check that fit the earlier methods may mean something else for the newest one.
  2. Does “same as already set up” mean the same method, or the same destination? Those are not the same question, and for a method with no destination, neither one makes adding a credential safe.
  3. Does every new factor get a test for adding a second one? The test most likely to be missing is the one an honest user would never run.

None of it needs exotic tooling. It needs the last bug to be read as a pattern, then looked for in the next feature.

What it proves, and what it doesn’t

Our pipeline flagged the passkey path in 6.2.9. Checking what was already public tied it to a fix from 6.2.7: a guard that fit codes sent to an email address or a phone, and not the new method.

It does not show anyone getting in without a password. The attacker needs the password, and the victim needs a passkey. It does not say whether 6.3.1 closes the hole, because we did not retest it. And it is not a claim to have found this first or alone. WPScan lists RIA Labs, and we know of no one else credited.

If you ship a security feature, or run a site full of plugins, we’ll read it. Nominate a target and the first scan costs nothing.

Published 19 October 2026. CVE-2026-111949 · CVSS 3.1 base score 7.5 · CWE-287 (Improper Authentication) · credited to RIA Labs, scored and published by WPScan. Status as of 19 October 2026. Corrections, or a plugin you maintain and want looked at: info@ria-labs.com.

See what a scan turns up

Nominate a target. The first scan costs nothing, and we’ll walk you through it.