GitHub Advisoryadvisory · Go

GHSA-8r7f-r8hj-r3rv Cloudreve: Information Exposure in `GET /api/v4/user/search`: `SearchActive` omits the active-status predicate, leaking inactive/banned account emails

MEDIUM Published 2026-07-24 Modified 2026-07-24 Official page ↗
Aliases
CVE-2026-55496
Ecosystem
Go
Packages
github.com/cloudreve/Cloudreve/v4, github.com/cloudreve/Cloudreve/v3
Severity
Moderate
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N
Weaknesses
CWE-200, CWE-359
Reviewed
2026-07-24

Affected packages

• Go github.com/cloudreve/Cloudreve/v4: < 4.0.0-20260613023921-7e1289d55279 → fixed in 4.0.0-20260613023921-7e1289d55279 • Go github.com/cloudreve/Cloudreve/v3: <= 3.0.0-20250225100611-da4e44b77af4 (no fix yet)

Description

Summary `GET /api/v4/user/search` is available to any logged-in user. The service calls `userClient.SearchActive`, but despite its name that method filters only by email/nickname keyword and never adds a `StatusActive` predicate — while the sibling lookups `GetActiveByID` and `GetActiveByDavAccount`, defined a few lines above it, do. Search hits are serialized at `RedactLevelUser`, which includes the email address. A normal logged-in user can therefore enumerate and retrieve the email (plus nickname, avatar, creation time, redacted group, profile share-visibility) of inactive and banned accounts that an active-user directory is supposed to suppress. No global status interceptor compensates — the only User query interceptor is soft-delete, and inactive/banned rows are not soft-deleted. Details Root cause (verified at `26b6b10`) 1. Route — logged-in + `UserInfo.Read` scope (`routers/router.go`): ```go user := v4.Group("user") // protected user group (login required) user.GET("search", middleware.RequiredScopes(types.ScopeUserInfoRead), controllers.FromQueryusersvc.SearchUserService, controllers.UserSearch) ``` The `RequiredScopes` check applies to scoped OAuth tokens; plain session requests are not gated by it — so any logged-in user reaches the search. 2. Service — 2-char keyword to `SearchActive` (`service/user/info.go`): ```go type SearchUserService struct { Keyword string `form:"keyword" binding:"required,min=2"` } const resultLimit = 10 func (s *SearchUserService) Search(c *gin.Context) ([]*ent.User, error) { return dep.UserClient().SearchActive(c, resultLimit, s.Keyword) } ``` 3. The bug — `SearchActive` has no status predicate (`inventory/user.go`): ```go func (c *userClient) SearchActive(ctx context.Context, limit int, keyword string) ([]*ent.User, error) { ctx = context.WithValue(ctx, LoadUserGroup{}, true) return withUserEagerLoading(ctx, c.client.User.Query(). Where(user.Or(user.EmailContainsFold(keyword), user.NickContainsFold(keyword))). Limit(limit), // =2 chars of the target email/nick> Cookie: cloudreve-session= ``` 3. Observe the inactive/banned account in the results, including its `email`. Expected: only active accounts appear (matching the method name and the sibling `GetActive*` behavior). Actual: inactive/banned accounts are returned with their email addresses. Impact Any logged-in user can enumerate and harvest the email addresses (and basic profile metadata) of inactive and banned accounts that active-user lookups intentionally hide. No account access, passwords, or 2FA secrets are exposed; the impact is PII leakage and user enumeration. Remediation • Add `Where(user.StatusEQ(user.StatusActive))` to `SearchActive` (matching `GetActiveByID`). • Apply the same active-status requirement to `GET /api/v4/user/info/:id`, or fall back to anonymous-level redaction unless the target account is active. • Consider not returning email from directory search at all — display name + hashed ID is usually sufficient. • Regression tests: searching a keyword that matches an inactive/banned account must return no result (or no email).

Related

Alias · CVE (1)

  • CVE-2026-55496 Cloudreve is a self-hosted file management and sharing system. vulnerability

Weakness · CWE (2)

  • CWE-200 Exposure of Sensitive Information to an Unauthorized Actor weakness
  • CWE-359 Exposure of Private Personal Information to an Unauthorized Actor weakness

References