GHSA-49h3-cwhj-4737: Cloudreve: Path Traversal in WOPI PUT_RELATIVE Allows Arbitrary File Creation in Owner Account
Summary
Cloudreve's WOPI PUT_RELATIVE handler treats X-WOPI-SuggestedTarget as a path, not a filename. It splits the header on / and joins the segments onto the source file's directory with URI.JoinRaw, which feeds Go's url.JoinPath. url.JoinPath resolves ./.. segments, so a slash-bearing target such as a/../../evil.docx collapses to a location outside the source file's directory. The lower-level upload path then validates only the final, already-cleaned basename (evil.docx), which is harmless, and checks ownership against the *resolved ancestor* — which is still the same user's drive.
A WOPI access token is bound to exactly one file (the route enforces fileId == session.FileID with a 403 otherwise). PUT_RELATIVE escapes that per-file scope: a token issued for one file can create (and, conditionally, overwrite) files elsewhere in the same account.
Root cause (verified at 26b6b10)
1. Token is single-file scoped (the boundary being escaped) — middleware ViewerSessionValidation:
fileId := hashid.FromContext(c)
if fileId != session.FileID { // 403 — token is bound to ONE file
c.Status(http.StatusForbidden); c.Abort(); return
}
Route: wopi := noAuth.Group("file/wopi", middleware.HashID(hashid.FileID), middleware.ViewerSessionValidation()); wopi.POST(":id", controllers.ModifyFile) → POST /api/v4/file/wopi/:id?access_token=<token>.
**2. PUT_RELATIVE dispatch** — routers/controllers/wopi.go:
case wopi.MethodPutRelative: // X-WOPI-Override: PUT_RELATIVE
err = service.PutContent(c, true)
3. SuggestedTarget joined as a path — service/explorer/viewer.go:
fileName, _ := wopi.UTF7Decode(c.GetHeader(wopi.SuggestedTargetHeader)) // X-WOPI-SuggestedTarget
fileUriParsed, _ := fs.NewUriFromString(fileUri)
if strings.HasPrefix(fileName, ".") { /* treat as extension */ }
fileUri = fileUriParsed.DirUri().JoinRaw(fileName).String() // <-- path join, not basename
...
subService := FileUpdateService{ Uri: fileUri }
res, err := subService.PutContent(c, lockSession)
4. JoinRaw spli
Details
Original advisory: https://github.com/advisories/GHSA-49h3-cwhj-4737
Exploitation outlook
EPSS (FIRST.org) estimates each CVE’s probability of exploitation in the next 30 days — here is the CSIRTS.com read on those numbers.
- Low exploitation riskCVE-2026-554950.38% 30-day exploitation probability — currently an unlikely target, but scores change as exploit code circulates. Riskier than 30% of all scored CVEs.
Referenced CVEs
| CVE | CSIRTS overview | External |
|---|---|---|
| CVE-2026-55495 | coverage & exploitation status | NVD · CVE.org |
Same CVEs, other sources
How other CERTs, PSIRTs and databases cover the vulnerabilities in this advisory.
More from GitHub Security Advisories
- mediumGHSA-jr6p-8pjj-mfx6: Capsule has an incomplete fix of CVE-2026-22872: TenantResource RawItems and Generators s…2026-07-31
- mediumGHSA-68cj-mvg9-rgm2: Capsule: CapsuleConfiguration NodeMetadata regex fields lack webhook validation, allowing…2026-07-31
- mediumGHSA-ff84-5f28-78qj: re2: Out-of-bounds heap read in `exec`/`test`/`match` via attacker-influenced `lastIndex`…2026-07-31
- mediumGHSA-6hxr-mr5r-9836: re2: Global `String.prototype.match` with an empty-matchable pattern never advances → inf…2026-07-31
- mediumGHSA-x83g-979r-f5fh: Sylius Mollie Plugin has unauthenticated IDOR that leaks order token and customer PII2026-07-31