Domain-wide signup session enables cross-tenant administrator takeover
A parent-domain signup JWT carried a global user ID but no tenant identity
CVSS 3.1 base score
CriticalVector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Summary
Source
CreateTenant()
app/handlers/signup.go:84
Sink
User()
app/middlewares/user.go:126
An unauthenticated attacker could complete public signup for their own Fider tenant, then present the temporary parent-domain cookie to an existing victim subdomain and be authenticated there with the attacker's Administrator role.
Root cause. The JWT contained a global user ID but no tenant claim. Middleware loaded that ID through an unscoped query, and dbEntities.User.ToModel replaced the persisted tenant with the request tenant, making the final tenant equality check tautological while preserving the source role and security stamp.
Remediation evidence. Fider responded to the disclosure and merged exact PR #1623 on 27 July 2026. The fix binds the persisted user to its real tenant, scopes lookup by tenant, and prevents the transfer cookie from being promoted on a foreign host.
Severity
- Attack vectorAV
- Network
- Attack complexityAC
- Low
- Privileges requiredPR
- None
- User interactionUI
- None
- ScopeS
- Changed
- 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
- Source · attacker-controlledapp/
handlers/ signup.go:84 CreateTenant()
- Step 01app/
handlers/ signup.go:84 Public signup creates an attacker-controlled tenant and Administrator, then sets a temporary authentication cookie for the shared parent domain.
go SetSignUpAuthCookie(c, createTenant.Result, user) // Domain=.HOST_DOMAIN - Step 02app/
middlewares/ user.go:126 On a victim subdomain, middleware decoded the global user ID and loaded it without a tenant predicate.
go claims := jwt.DecodeFiderClaims(token) q := &query.GetUserByID{UserID: claims.UserID} bus.Dispatch(c, q) - Step 03app/
pkg/ dbx/ entities/ user.go:ToModel() Mapping substituted the victim request tenant into the attacker user object, allowing the equality guard to pass with the Administrator role intact.
go user.Tenant = contextTenant if user.Tenant.ID == c.Tenant().ID { c.SetUser(user) } - Sinkapp/
middlewares/ user.go:126 User()
Impact
Reported impact
The attacker obtains administrator access to another tenant, including its backup/export data, users, feedback, settings, integrations, and broad mutation endpoints. This is a complete cross-tenant confidentiality, integrity, and availability compromise short of separately owner-guarded whole-site deletion.
Attack surface
Public OAuth signup on multi-host Fider deployments using a shared parent HOST_DOMAIN.
Preconditions
Public signup and a built-in OAuth provider are enabled. The attacker needs only their own provider account and the victim tenant's public subdomain; no victim interaction or secret is required.
Attack path
- 1
Complete ordinary OAuth signup and create an attacker-owned tenant.
- 2
Receive the temporary parent-domain signup authentication cookie.
- 3
Before it is consumed, visit an administrator route on the victim subdomain.
- 4
The global lookup loads the attacker Administrator while the mapper assigns the victim tenant.
- 5
Use the resulting victim-tenant administrator context to access exports or mutations.
Proof of concept
- 01
Environment setup
Run a vulnerable multi-host Fider deployment with public signup, an attacker tenant, and a seeded victim tenant.
- 02
Target configuration
Configure one shared
HOST_DOMAINand a public OAuth provider. Use only attacker-owned provider credentials. - 03
Exploit delivery
Create the attacker tenant, preserve its
__signup_authcookie, then request an administrator-only victim-host route such as the backup export before visiting the attacker tenant. - 04
Expected response
The vulnerable server returns victim-tenant administrator content and promotes a host cookie even though the JWT user belongs to the attacker tenant.
- 05
Outcome
PR #1623 rejects the tenant mismatch using signed/persisted identity and tenant-scoped lookup before installing a user context.
Remediation
Guidance
Upgrade to a Fider release containing PR #1623 and invalidate pre-fix sessions. Bind every auth token and lookup to an immutable tenant ID, and make the signup transfer token single-destination and single-use.
q := &query.GetUserByID{UserID: claims.UserID}user.Tenant = c.Tenant()if claims.TenantID != c.Tenant().ID { return next(c) }q := &query.GetUserByIDForTenant{ UserID: claims.UserID, TenantID: claims.TenantID,}
Check the upstream record for the project's current remediation status.
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.

