Overview

an ssrf in cloudreve through remote download

June 21, 2026
4 min read

TL;DR

I got CVE-2026-54562 in Cloudreve.

This one was a server-side request forgery in the remote download workflow, but the part I liked was the boundary.

It was not “any normal user can SSRF the server by default.”

The attacker needed to be:

  • authenticated
  • non-admin
  • in a group with GroupPermissionRemoteDownload enabled

That still mattered, because remote download is a feature-level group capability, not an admin-only role switch by itself.

Once that permission was granted to a non-admin group, the user could queue a remote download to loopback or another internal-only target, wait for Cloudreve to import the fetched response into their files, and then read it back normally.

The bug

The root issue was simple.

Cloudreve accepted a user-supplied URL for the remote download workflow, then passed it to the downloader without filtering loopback, localhost, IPv6 localhost, or redirect-to-loopback targets.

The affected endpoint was:

POST /api/v4/workflow/download

And the follow-up readback path stayed inside the normal product flow:

GET /api/v4/workflow?category=downloaded...
GET /api/v4/file?uri=cloudreve://my...
POST /api/v4/file/url

That is what made the bug stronger than a blind SSRF primitive. The attacker did not just cause an internal request. They could also recover the fetched response body after import.

Why it worked

The advisory called out three relevant code paths:

service/explorer/workflows.go:81
pkg/filemanager/workflows/remote_download.go:202
pkg/downloader/aria2/aria2.go:56

At a high level, the permission check existed, but it only answered:

is this user group allowed to use remote download at all?

It did not answer:

is this submitted URL safe to fetch from the server side?

That missing second check is the whole issue.

The advisory also makes the scope of the bug very explicit: the application did not block loopback, localhost, IPv6 localhost, or redirect targets resolving to internal addresses.

The negative control mattered

The cleanest part of this bug was the permission negative control.

Before the remote download permission was enabled for the default non-admin User group, the same request was denied:

POST /api/v4/workflow/download
Content-Type: application/json
{"src":["http://127.0.0.1:7777/secret"],"dst":"cloudreve://my"}

Response:

{"code":40007,"msg":"Group not allowed to download files"}

That matters, because it shows this was not an accidental “everyone can do it” bug.

The attack only became reachable after granting just the remote download capability to a non-admin group.

The exploit path

Once the user had remote download permission, the SSRF path was straightforward.

Queue a loopback download:

POST /api/v4/workflow/download
Content-Type: application/json
{"src":["http://127.0.0.1:7777/secret2"],"dst":"cloudreve://my"}

Response:

{"code":0,"data":[{"id":"OzH4","status":"queued","type":"remote_download"}]}

The internal listener on the Cloudreve host received the request:

127.0.0.1 - - [27/May/2026 13:00:46] "GET /secret2 HTTP/1.1" 200 -

Then Aria2 completed the fetch and Cloudreve imported it:

Download complete: /home/b4r/cysec/cvehunting/cloudreve/data/temp/.../secret2

After that, the attacker could read the imported file as a normal Cloudreve file and recover the response body:

SSRF_SECRET_2_20260527

That is the part that turns this from “server made a request” into a much more useful SSRF.

Validated variants

The advisory also confirmed that this was not limited to one loopback string.

Validated targets included:

  • http://127.0.0.1:7777/secret2
  • http://localhost:7777/localsecret
  • http://[::1]:7780/v6secret
  • redirect to http://127.0.0.1:7777/redirsecret

And the readback markers were recovered successfully for each variant:

  • SSRF_SECRET_2_20260527
  • LOCALHOST_SECRET_20260527
  • IPV6_SECRET_20260527
  • REDIR_SECRET_20260527

That last one matters because redirect handling often gets forgotten even when direct URL parsing is filtered later.

Why I liked it

I like SSRF bugs more when the product itself helps close the loop.

Here, the attacker did not need some out-of-band side channel to prove the fetch happened. The app imported the response into the attacker’s own files and then exposed it through the normal file APIs.

That makes the impact easy to explain:

  • attacker provides internal URL
  • server-side downloader fetches it
  • Cloudreve imports the fetched response
  • attacker reads the imported file back

That is a very clean SSRF-to-readback chain.

Impact

The confirmed impact was:

  • internal loopback HTTP services reachable from the downloader environment
  • imported response bodies readable by the attacker afterward

The advisory explicitly calls out exposure such as:

  • internal HTTP services
  • loopback-only admin panels
  • local service metadata
  • other network resources not directly reachable by the attacker

That is why the issue was classified as confidentiality impact, not just “weird network behavior.”

Severity and versions

The advisory data you shared lists:

  • CVE: CVE-2026-54562
  • Severity: Moderate
  • CVSS: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
  • CWE: CWE-918
  • Affected: <= 4.16.0
  • Patched: 4.16.1

So yes, this one is already patched.

The boundary I kept

I kept this write-up narrow in the same way the advisory did.

This is not a default-every-user bug.

Default normal users were blocked. The vulnerable path depended on a non-admin user group being granted remote download permission.

That still leaves a real package-level issue, because the permission model exposed a feature to non-admin users without putting any server-side URL safety policy behind it.

Reference

Thanks for reading this blog post all the way to the end