Vulnerability research · 2026-05-19
Pre-authentication session fixation in Vaultwarden SSO.
A flaw in Vaultwarden's OpenID Connect single sign-on (CVE-2026-47158) let an unauthenticated attacker take over the account of any SSO user who could be led through a login. The authorization flow was not tied to the browser that started it, so an attacker could create a flow on the server and have a victim's identity delivered into it. It is fixed in 1.36.0.
Summary
- Identifier: CVE-2026-47158 (GHSA-pfp2-jhgq-6hg5)
- Class: CWE-352, session fixation in an OAuth 2.0 / PKCE flow
- CVSS 3.1: 8.3 (AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:H)
- Affected: Vaultwarden with the SSO client enabled, before 1.36.0
- Fixed: 1.36.0
- Reported by: Santh (2026-04-25); independently by Sijisu (2026-02-28) and ddd (2026-04-11)
- Advisory published: 2026-05-19
Background: Vaultwarden's SSO client
Vaultwarden is a Rust reimplementation of the Bitwarden server API, widely self-hosted. Recent versions added a built-in OpenID Connect client so an organization can place vault login behind its own identity provider (IdP). The login follows OAuth 2.0 with PKCE:
- The browser requests
/connect/authorizewith astatevalue and a PKCEcode_challenge. - Vaultwarden records the pending request and redirects the browser to the IdP.
- After the user authenticates, the IdP redirects back to
/connect/oidc-signinwith an authorizationcodeand the originalstate. - The browser completes login at
/connect/token, which exchanges thecode(with the matchingcode_verifier) for tokens and issues a Vaultwarden session.
To match the callback to the request that started it, Vaultwarden stores a server-side
record, SsoAuth, keyed by state.
The flaw: an authorization flow with no owner
Three properties combined.
/connect/authorizeaccepted an arbitrary, client-suppliedstateandcode_challengewith no authentication, no cookie, and no other anchor to the browser session. Any unauthenticated caller could create anSsoAuthrecord.- The
SsoAuthrecord was keyed only by the client-suppliedstate. Whoever knew thestatevalue owned the record. - When the token exchange failed — for example, because the PKCE verifier did not match — Vaultwarden left the
SsoAuthrecord in place, including any authorization code already written to it.
Because nothing tied the record to a particular browser, the server could not distinguish the party that created a flow from the party that finished it.
Exploitation
The attacker needs only to reach the instance and to get a victim to complete an SSO login.
1. The attacker generates a PKCE pair and a state, then creates the server-side record:
GET /connect/authorize?state=ATTACKER_STATE&code_challenge=ATTACKER_CHALLENGE&...
Vaultwarden stores SsoAuth[ATTACKER_STATE], holding the attacker's challenge.
2. The attacker builds the IdP authorization URL for that same flow and delivers it to a victim who is a legitimate SSO user of the instance (a link, an email, an embedded redirect).
3. The victim authenticates to the IdP. The IdP redirects the victim's browser to /connect/oidc-signin with a valid code and ATTACKER_STATE. Vaultwarden writes the victim's code into SsoAuth[ATTACKER_STATE].
4. The victim's browser tries to finish at /connect/token, but it does not hold the attacker's code_verifier, so the IdP exchange fails. Because the record is not cleaned up on failure, the victim's authorization code remains.
5. The attacker calls /connect/token with ATTACKER_STATE and their own verifier:
POST /connect/token state=ATTACKER_STATE&code_verifier=ATTACKER_VERIFIER
Vaultwarden finds the victim's code in the record, completes the exchange against the IdP, and issues a Vaultwarden session for the victim's account — to the attacker. The victim sees, at most, a login that did not complete.
Impact
For an instance using SSO, this is account takeover of any SSO user who can be led through
a login, and the attacker needs no credential of their own. Where those users do not also
have a second factor on the vault, the attacker obtains an authenticated session directly.
That session grants access to the user's encrypted vault material, which can be taken
offline and attacked against the master password without further interaction. The same
primitive supports account squatting and disclosure of account metadata: email, name, and
the linked SSO identity. The CVSS vector's UI:R reflects the single
requirement — the victim must complete an SSO login.
The fix
Version 1.36.0 binds the authorization flow to the browser that starts it. A record created by one browser can no longer be completed with an authorization code delivered by a different browser's IdP callback, which removes the fixation. Operators running SSO should upgrade to 1.36.0 or later. Until then, the exposure is limited to instances with the SSO client enabled; enforcing a second factor reduces, but does not remove, the consequences of a completed takeover.
Disclosure
The issue was reported to the Vaultwarden maintainers, who published advisory GHSA-pfp2-jhgq-6hg5 (CVE-2026-47158) on 2026-05-19. It credits three independent reporters; Santh's report was filed on 2026-04-25. The maintainers shipped the fix promptly, and we thank them for it.
Advisory: GHSA-pfp2-jhgq-6hg5.