Skip to content
winfunc
Disclosure record · Fider

OAuth host poisoning enables cross-tenant account takeover

OAuth state signed an attacker-selected origin and the token endpoint trusted an unsigned session cookie

FiderDisclosedSource record

CVSS 3.1 base score

High
8.8/ 10

Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

Record

Project
Fider
Severity
High8.8
CVE
None listed
Disclosed
Trace
3 steps

Summary

Source

WrapRequest()

app/pkg/web/request.go:33

Sink

OAuthToken()

app/handlers/oauth.go:183

An attacker could start OAuth with a poisoned Host, receive the victim's still-unused provider code at an attacker origin, and redeem it on a chosen tenant by matching an unsigned user_session_id cookie.

Root cause. SignInByOAuth derived its continuation from raw Host/X-Forwarded-Host and signed that origin into state. The callback redirected the provider code and identifier there, while OAuthToken neither revalidated the state nor consumed a server-side transaction and accepted a caller-set session cookie as the binding.

Remediation evidence. Fider responded to the disclosure and merged exact PR #1626 on 27 July 2026. It replaces request-host authority with canonical tenant origins and a signed handoff bound to the provider, origin, and browser session.

Severity

Attack vectorAV
Network
Attack complexityAC
Low
Privileges requiredPR
None
User interactionUI
Required
ScopeS
Unchanged
ConfidentialityC
High
IntegrityI
High
AvailabilityA
High

Metric values as published in the disclosure vector. Meters show how far each value raises exposure.

Source-to-sink trace

  1. Source · attacker-controlledapp/pkg/web/request.go:33

    WrapRequest()

  2. Step 01app/pkg/web/request.go:33

    An unauthenticated request selected the externally visible host from direct or forwarded request headers.

    go
    host := request.Host
    if forwarded := request.Header.Get("X-Forwarded-Host"); forwarded != "" {
      host = forwarded
    }
    
  3. Step 02app/handlers/oauth.go:SignInByOAuth()

    The OAuth start handler placed that attacker origin and a session identifier into signed state.

    go
    redirect := c.BaseURL()
    state := jwt.EncodeOAuthState(redirect, c.SessionID())
    
  4. Step 03app/handlers/oauth.go:183

    The tenant token endpoint redeemed the captured provider code after comparing only a caller-controlled cookie to the disclosed identifier.

    go
    if c.Cookie("user_session_id") == state.Identifier {
      profile := provider.Exchange(code)
      SetAuthCookie(c, profile)
    }
    
  5. Sinkapp/handlers/oauth.go:183

    OAuthToken()

Impact

Reported impact

The attacker takes over the consenting victim's account in the selected tenant; if that victim is an administrator, the attacker gains tenant data export, settings, integration, user-management, and destructive content authority.

Attack surface

Built-in OAuth sign-in on multi-host Fider deployments that accepted arbitrary Host or untrusted forwarded-host values.

Preconditions

The attacker controls a public HTTPS origin and knows the target tenant host. A victim with an existing Fider account must approve the legitimate provider application; the attacker needs no OAuth client secret or Fider credential.

Attack path

  1. 1

    Proxy the OAuth start request with the attacker origin as Host.

  2. 2

    Have the victim complete normal provider authorization.

  3. 3

    Capture the provider code and state identifier from Fider's redirect to the attacker origin.

  4. 4

    Set user_session_id to the captured identifier on the chosen victim tenant.

  5. 5

    Redeem the code at that tenant's OAuth token endpoint and receive the victim's Fider session.

Proof of concept

Reproduction5 stages
  1. 01

    Environment setup

    Use an isolated vulnerable multi-host Fider deployment, a victim test account, and an attacker-controlled HTTPS callback collector.

  2. 02

    Target configuration

    Enable a built-in global OAuth provider and allow the application to receive an arbitrary Host or client-supplied X-Forwarded-Host.

  3. 03

    Exploit delivery

    Start OAuth through the poisoned authority, complete consent as the victim, capture the redirected code/identifier, and replay them to the victim tenant with the matching unsigned cookie.

  4. 04

    Expected response

    The vulnerable tenant endpoint sets a valid Fider auth cookie for the victim account.

  5. 05

    Outcome

    PR #1626 accepts only a canonical tenant origin and a cryptographically bound, single-purpose handoff, so the captured values cannot be redirected or replayed into another tenant.

Remediation

Guidance

Upgrade to a Fider release containing PR #1626. Derive security redirects from canonical tenant configuration, trust forwarded headers only from configured proxies, and bind OAuth state to tenant, provider, origin, session, expiry, and single use.

Before and after−2+3
redirect := c.BaseURL()state := jwt.EncodeOAuthState(redirect, c.SessionID())canonical := web.TenantBaseURL(c.Tenant())handoff := oauthTransactions.Create(tenantID, provider, sessionHash, canonical)state := jwt.EncodeOAuthState(handoff.ID)
View original source record

Check the upstream record for the project's current remediation status.

Your codebase

Investigate the paths that matter in your codebase.

Winfunc can trace relevant code paths, preserve supporting evidence, and prepare remediation suggestions for engineering review within an agreed scope.