Research/wpmgr-social-planted-password
0-dayNo CVEHighPublic

WPMgr v0.61.199, planted password survives OIDC link

WPMgr v0.61.199 POST /auth/register plants a pending user with an attacker-chosen password. MarkUserEmailVerified does not clear password_hash. A later Google/GitHub/OIDC callback binds the victim identity onto that row. The planted password still logs in. Labbed. No CVE yet.

Name
WPMgr v0.61.199, planted password survives OIDC link
Type
0-day analysis
CVE
n/a
CVE Risk
high
Disclosure Status
public
Vendor
mosamlife
Affected
WPMgr v0.61.199 (e1b3a163). Self-serve after the install is claimed. Victim verifies email, then signs in with SSO.
Published
09 Nov 2026
Updated
09 Nov 2026
Tags
0-day, wpmgr, oauth, account-linking, cwe-287, cwe-284, remote

Register first. Wait for Google.

I planted an account with someone else's email and a password they never chose. WPMgr marked it pending, which is correct, and mailed a verify link, which is also correct. The victim clicked that mail. Then they did the thing a reasonable person does with a fleet manager: they signed in with OIDC. WPMgr linked Google-or-Dex onto the planted row and left my hash sitting there. I logged in with the password I picked. They still had 2FA off. I had a session as them.

Someone who knows your email can do that after the install is claimed. They need you to verify the address. They do not need a mailbox if you click the unexpected verify mail yourself. SSO-only accounts that never had a password are a different story.

This is WPMgr v0.61.199 (e1b3a163988c9f1c31bc93922ea34322fa188792). No CVE yet. CWE-287 / CWE-284. 8.1 High (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N). Remote OAuth leftover. Pack: abraxas/wpmgr-social-planted-password.

The comment that almost closed it

decideSocial already names this pre-hijack. It refuses to link a provider-verified identity onto a row until email_verified_at is set. That gate is real. The pending path returns email_not_verified and never the copy that would tell the user to reset a password they did not set. ResendVerification is unauthenticated. MarkUserEmailVerified sets status=active and email_verified_at=now() and does not touch password_hash. The next callback hits socialLinkExisting → CompleteSocialLink.

So the recovery the product walks you through is: click the mail, try SSO again. That is exactly the plant.

Pin and skip list

Same pin as the Dex leftover, e1b3a163. MCP OAuth is in-class on paper. Open client registration is bounded to a row. PKCE S256 is mandatory. Redirects are exact-match. Consent sits behind PermAPIKeyManage. I left it closed. SAML is not implemented.

I wasted a lab evening treating an SSO-only empty password_hash as this bug. It is not. There is nothing to keep.

The lab

Compose wpmgrh04, loopback 18180-18186, Mailpit on a 1.2.3.0/24 gadget subnet because the product SMTP dialer (code.dny.dev/ssrf) refuses RFC1918 and loopback. Dex stands in for Google. Bootstrap claim. Plant victim.h04@lab.test as pending|hash|unverified. Mailpit hands over the raw token. Verify leaves active|hash|verified. OIDC links oidc|victim.h04@lab.test. Attacker password login still issues wpmgr_session.

Plain text
IOC planted-pending pending|hash|unverified
IOC email-verified-hash-kept active|hash|verified
IOC oidc-linked oidc|victim.h04@lab.test
IOC password-login-survived active|hash|verified oidc|victim.h04@lab.test
SUCCESS WPMGR-H04-SOCIAL-PLANT planted-password-survives-oidc-link WPMGR-H04-PLANTED-PASSWORD-SURVIVES

What an attacker can do

Needs an already-claimed install (self-serve is open) and the victim's email. The victim verifies. Then the victim SSOs. In ordinary words: they register as you, you confirm the mail, you sign in with Google, they still know a password for your account.

Privilege Method / sink Recon / integrity / availability Lab-proven or inferred
Plant a pending user with an attacker-chosen argon2 password POST /auth/register Integrity (account plant) Lab-proven
Mail a verification token for that planted row unauthenticated resend / register mail Recon Lab-proven. Mailpit
Activate the planted row without clearing the hash POST /auth/verify-email → MarkUserEmailVerified Integrity Lab-proven
Bind OIDC onto that same row GET /auth/oidc/callback → CompleteSocialLink Integrity (identity link) Lab-proven
Sign in as the victim with the planted password after SSO POST /auth/login Integrity (session as victim) Lab-proven

Stays closed on this leftover

Axis Method / sink Why it is closed
Integrity SSO-only empty password_hash No planted hash
Integrity MCP OAuth PKCE, exact redirect, consent grant
Integrity Unclaimed first-run Bootstrap claim
Integrity Password reset as a session mint Reset does not issue wpmgr_session

The fix

On verify, and again in CompleteSocialLink, clear password_hash (or force a reset) when the row was never used for a password login the owner chose. Do not link a provider onto a hash the current user did not set. Show the reset copy on the pending path.

I am @abraxas_null. Site abraxaslabs.tech. GitHub abraxas. Mail abraxas.null@proton.me.