🛡️ CVE-2026-54560 — cloudreve
Description
Cloudreve: OAuth access tokens bypass scope enforcement due to missing client_id claim
Summary
Cloudreve's OAuth access tokens can bypass OAuth scope enforcement.
This does not appear to be the intended design. The documentation describes OAuth client permissions/scopes, the API
has an insufficient-scope error code, and the code comments say RequiredScopes(...) should verify scopes when a
token has scopes, while skipping checks only for non-scoped session-based authentication.
However, OAuth access tokens are issued without the OAuth client_id claim. Later, the JWT verifier only loads scopes
into the request context when claims.ClientID != "". Because the OAuth access token has no client_id, its scopes
are not loaded, and RequiredScopes(...) treats the request like a non-scoped first-party/session token and skips
scope checks.
As a result, a low-scope OAuth access token, for example one granted only openid, can call APIs requiring higher
scopes such as file, share, workflow, user setting, WebDAV account, and potentially admin scopes when the authorizing
user is an administrator.
Why this seems unintended
Cloudreve appears to have an explicit OAuth scope model:
1. The official docs describe OAuth client permissions/scopes and require the authorization request to include
requested scopes.
2. The API error code list includes an OAuth insufficient-scope error.
3. RequiredScopes(...) is used across sensitive API groups such as files, shares, workflows, user settings, WebDAV
devices, and admin APIs.
4. The middleware comment says scope checks are skipped only when hasScopes is false, for example session-based
authentication.
5. Default OAuth clients created during migration explicitly list scopes such as Files.Write, Workflow.Write, and
Shares.Write.
This suggests the intended design is:
- First-party/session tokens may be non-scoped and skip OAuth scope checks.
- OAuth access tokens should carry scope metadata and be checked against
RequiredScopes(...).
The current implementation makes OAuth access tokens fall into the first category by mistake.
Affected code
In the OAuth authorization code exchange, Cloudreve passes both ClientID and Scopes into token issuance:
```go
token, err := tokenAuth.Issue(c, &auth.IssueTokenArgs{
User: user,
ClientID: s.ClientID,
Scopes: authCode.Scopes,
RefreshTTLOverride: refreshTTLOverride,
})
Location:
- service/oauth/oauth.go
In Issue(...), the access token includes Scopes but does not include ClientID:
accessToken, err := jwt.NewWithClaims(jwt.SigningMethodHS256, Claims{
TokenType: TokenTypeAccess,
RegisteredClaims: jwt.RegisteredClaims{
Subject: uidEncoded,
NotBefore: jwt.NewNumericDate(issueDate),
ExpiresAt: jwt.NewNumericDate(accessTokenExpired),
},
Scopes: args.Scopes,
}).SignedString(t.secret)
By contrast, the refresh token does include both:
Scopes: args.Scopes,
ClientID: args.ClientID,
Location:
- pkg/auth/jwt.go
During request authentication, scopes are only inserted into request context if ClientID is present:
if claims.ClientID != "" {
util.WithValue(c, ScopeContextKey{}, claims.Scopes)
}
Location:
- pkg/auth/jwt.go
Then CheckScope(...) skips scope enforcement if no scopes are present in context:
hasScopes, tokenScopes := GetScopesFromContext(c)
if !hasScopes {
return nil
}
Location:
- pkg/auth/jwt.go
RequiredScopes(...) relies on this check:
if err := auth.CheckScope(c, requiredScopes...); err != nil {
c.JSON(200, serializer.Err(c, err))
c.Abort()
return
}
Location:
- middleware/auth.go
Sensitive route groups protected by RequiredScopes(...) include:
- Files: Files.Read / Files.Write
- Shares: Shares.Read / Shares.Write
- Workflows: Workflow.Read / Workflow.Write
- User settings and security info
- WebDAV device/account management
- Admin APIs: Admin.Read / Admin.Write
Location:
- routers/router.go
Reproduction steps
1. Create or use an OAuth client with a low-privilege scope, for example only openid.
2. Complete the OAuth authorization code flow for a normal user with:
scope=openid
3. Exchange the authorization code via:
POST /api/v4/session/oauth/token
4. Decode the returned access token.
Expected token metadata should preserve enough OAuth client/scope context for later enforcement.
Actual behavior:
- The access token contains the requested scopes.
- The access token does not contain client_id.
5. Use the returned token as a bearer token:
Authorization: Bearer <access_token>
6. Call an API that requires a scope not granted to the OAuth app, for example an endpoint requiring Files.Read,
Files.Write, UserInfo.Write, or DavAccount.Write.
Expected result:
- The request s
How this vulnerability can be exploited
This issue can be reached over the network, attack complexity is low, an attacker needs low-level privileges on the target. A user must be tricked into taking some action. The scope is unchanged, so the impact stays within the vulnerable component. Rated impact: confidentiality high, integrity high, availability low.
Affected software
CVE-2026-54560 is recorded against 4 packages.
- github.com/cloudreve/cloudreve
- github.com/cloudreve/cloudreve/v3
- github.com/cloudreve/cloudreve/v4
- unknown
Timeline and source
Published on 22 July 2026. No public exploit is currently recorded for this entry. Record sourced from NVD.
References
github.com (Advisory)
nvd.nist.gov (Advisory)
github.com (Web)
github.com (Web)
Details
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:L
Affected Packages
| Software | From version | Fixed in |
|---|---|---|
| github.com/cloudreve/cloudreve | — | — |
| github.com/cloudreve/cloudreve/v3 | — | — |
| github.com/cloudreve/cloudreve/v4 | — | — |
| unknown | — | — |
References
Similar Threats
- High CVE-2026-55502
- Medium CVE-2026-55495
- Medium CVE-2026-55496
- Medium CVE-2026-55497
- Medium CVE-2026-55499
More CVE 2026 advisories
Browse all of CVE 2026 in the advisory index.
Site Security Check
Is cloudreve part of your stack?
CVE-2026-54560 is rated CVSS 8.0 High. BotEraser scans your installation against known CVE records and tells you whether this vulnerability applies to the versions you actually run.
Scan My Site Free →No credit card required · Results in minutes
ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.