Skip to content

CSRF in SSO Authorization Flow

High
dani-garcia published GHSA-pfp2-jhgq-6hg5 May 19, 2026

Package

vaultwarden

Affected versions

<1.35.8

Patched versions

1.36.0

Description

Summary

A cross-site request forgery / session fixation vulnerability in Vaultwarden's SSO authorization flow allowed an unauthenticated attacker to hijack any SSO user's login and obtain a fully authenticated session, leading to account takeover.

The OAuth state parameter accepted by the authorize endpoint was not bound to the initiating browser session. Combined with a PKCE flow under attacker-controlled parameters and a cleanup gap on failed token exchange, an attacker could pre-create an authorization context, induce a victim to complete IdP authentication against it, and then redeem the resulting tokens themselves.

Affected versions

All Vaultwarden versions with SSO support up to and including 1.35.8. Versions 1.36.0 and up are not vulnerable.

Root cause

Three design decisions combined to produce the vulnerability:

  1. No session binding at /connect/authorize. The endpoint accepted arbitrary client-supplied state and code_challenge values without authentication, cookies, or any other browser-session anchor.
  2. SsoAuth keyed by the client-supplied state. The server-side record holding the OIDC flow context was primary-keyed on a value the caller controls, allowing an attacker to fixate a row and have a subsequent IdP callback bearing that state populate it.
  3. No cleanup of SsoAuth on failed token exchange. When exchange_code propagated an IdP error (e.g. from a mismatched PKCE verifier), the row was left intact, preserving the victim's authorization code for later redemption.

Attack chain

  1. The attacker generates a PKCE code_challenge/code_verifier pair and a state value, then calls /connect/authorize with these. An SsoAuth row is stored keyed by the attacker's state, and the IdP authorization URL is returned.
  2. The attacker sends the IdP URL to the victim. The victim authenticates with the IdP — if an IdP session is already active, no interaction beyond the click is required.
  3. The IdP redirects the victim's browser to /connect/oidc-signin with their real authorization code. The server stores this code in the attacker-fixated SsoAuth row without verifying that the callback originated from the same browser that initiated the flow.
  4. The victim's browser is redirected to sso-connector.html, where the Bitwarden client automatically attempts token exchange. Because the client does not hold the attacker's verifier, the exchange fails at the IdP. The SsoAuth row is not deleted.
  5. The attacker calls /connect/token with the fixated state (which doubles as code in this implementation) and their own code_verifier. The exchange succeeds, the IdP returns the victim's identity, and access and refresh tokens for the victim's account are issued to the attacker.

Impact

  • Full account takeover of any SSO user without two-factor authentication.
  • Access to the victim's encrypted vault material (PrivateKey, Key, ciphers), enabling offline brute-force of the master password.
  • Account squatting / identity linking when SSO_SIGNUPS_MATCH_EMAIL is enabled (the default).
  • Disclosure of the victim's email, name, and SSO subject/issuer even when 2FA blocks the final session issuance.

Preconditions

  • SSO must be enabled on the Vaultwarden instance.
  • The victim must hold (or be able to create, under default settings) a Vaultwarden account linked by email to the IdP identity.
  • The victim must authenticate with the IdP when redirected (or already hold an active IdP session).
  • 2FA on the victim's account blocks final session issuance but does not prevent the rest of the chain.

Fix

The patched version binds the SSO authorization flow to the initiating browser so that an attacker-initiated SsoAuth row cannot be populated by a different browser's IdP callback. Server-side state cleanup on failed token exchange has also been tightened.

Workarounds for unpatched instances

  • Enforce 2FA for all SSO users. Blocks final session issuance but does not prevent the identity leak or account linking under default signup settings.
  • Restrict SSO to known domains via SSO_ALLOWED_ORGS / SIGNUPS_DOMAINS_WHITELIST to limit the targetable user pool.
  • Apply rate limits to /connect/authorize and /connect/token at a reverse proxy layer.

References

  • RFC 6749 §10.12 — Cross-Site Request Forgery
  • OAuth 2.0 Security Best Current Practice §4.10 — Session Fixation
  • OAuth 2.0 for Browser-Based Apps — Login CSRF

Credits

Independently reported between February and April 2026 by:

  • @Sijisu (2026-02-28)
  • @ddd (2026-04-11)
  • @santhsecurity (2026-04-25)

Individual roles are listed in the Credits section of this advisory.

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
Required
Scope
Unchanged
Confidentiality
Low
Integrity
High
Availability
High

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:H

CVE ID

CVE-2026-47158

Weaknesses

Cross-Site Request Forgery (CSRF)

The web application does not, or cannot, sufficiently verify whether a request was intentionally provided by the user who sent the request, which could have originated from an unauthorized actor. Learn more on MITRE.

Credits