CVE-2026-45282
Description
Authenticated Nextcloud users can bypass share restrictions to access link share attachments, affecting versions prior to 32.0.9 and 33.0.3.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Authenticated Nextcloud users can bypass share restrictions to access link share attachments, affecting versions prior to 32.0.9 and 33.0.3.
Vulnerability
Nextcloud Server versions 32.0.0 through 32.0.9 and 33.0.0 through 33.0.3 are affected by a vulnerability that allows an authenticated attacker to access attachments of link shares. This bypasses password protection and download restrictions if the attacker knows the share token and a documentId they own. Exploiting this for shared folders is significantly harder as it requires guessing a documentId within the folder.
Exploitation
An attacker who is already authenticated to Nextcloud and knows a share token can exploit this vulnerability. By providing a known documentId associated with their account, they can access attachments of link shares, even if those shares are password-protected or have download restrictions enabled. For shared folders, the attacker must also know or guess the documentId of a file contained within that folder.
Impact
Successful exploitation allows an attacker to extract attachments from link shares, circumventing configured security measures like password protection and download restrictions. The attacker gains access to these attachments but cannot access the shared file or folder itself. The scope of the compromise is limited to the attachments of specific link shares.
Mitigation
Nextcloud Server should be upgraded to version 32.0.9 or 33.0.3. For Nextcloud Enterprise Server, upgrade to 33.0.3, 32.0.9, 31.0.14.5, 30.0.17.9, 29.0.16.16, 28.0.14.17, or 27.1.11.5. As a workaround, the 'Text' app can be disabled. [2]
AI Insight generated on Jun 1, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
2- Range: 32.0.0 to <32.0.9, 33.0.0 to <33.0.3
Patches
1b55bed8d0eb4Merge pull request #8499 from nextcloud/fix/sharetoken-validation
2 files changed · +64 −13
lib/Middleware/SessionMiddleware.php+10 −8 modified@@ -122,15 +122,9 @@ private function assertDocumentSession(ISessionAwareController $controller): voi */ private function assertUserOrShareToken(ISessionAwareController $controller): void { $documentId = (int)$this->request->getParam('documentId'); - if (null !== $userId = $this->userSession->getUser()?->getUID()) { - if ($this->rootFolder->getUserFolder($userId)->getFirstNodeById($documentId) !== null) { - $controller->setUserId($userId); - $controller->setDocumentId($documentId); - return; - } - } + $shareToken = (string)$this->request->getParam('shareToken'); - if ('' !== $shareToken = (string)$this->request->getParam('shareToken')) { + if ($shareToken !== '') { try { $share = $this->shareManager->getShareByToken($shareToken); } catch (ShareNotFound) { @@ -164,6 +158,14 @@ private function assertUserOrShareToken(ISessionAwareController $controller): vo return; } + if (null !== $userId = $this->userSession->getUser()?->getUID()) { + if ($this->rootFolder->getUserFolder($userId)->getFirstNodeById($documentId) !== null) { + $controller->setUserId($userId); + $controller->setDocumentId($documentId); + return; + } + } + throw new InvalidSessionException(); }
tests/unit/Middleware/SessionMiddlewareTest.php+54 −5 modified@@ -7,12 +7,16 @@ use OCA\Text\Middleware\SessionMiddleware; use OCA\Text\Service\DocumentService; use OCA\Text\Service\SessionService; +use OCP\Constants; +use OCP\Files\File; use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\IL10N; use OCP\IRequest; use OCP\ISession; +use OCP\IUser; use OCP\IUserSession; +use OCP\Share\Exceptions\ShareNotFound; use OCP\Share\IManager; use OCP\Share\IShare; use Test\TestCase; @@ -89,29 +93,74 @@ public function testWrongArrayBlocked(): void { $this->invokeMiddleware($share); } + public function testLoggedInUserWithInvalidToken(): void { + $this->expectException(InvalidSessionException::class); + + $user = $this->createMock(IUser::class); + $user->method('getUID')->willReturn('user1'); + + $share = $this->createPasswordProtectedShare('42'); + $this->shareManager->method('getShareByToken')->willThrowException(new ShareNotFound()); + + $this->invokeMiddleware($share, $user); + } + + public function testLoggedInUserWithValidToken(): void { + $user = $this->createMock(IUser::class); + $user->method('getUID')->willReturn('user1'); + + $share = $this->createMock(IShare::class); + $share->method('getId')->willReturn('user2-share'); + $share->method('getPassword')->willReturn(null); + $share->method('getPermissions')->willReturn(Constants::PERMISSION_READ); + $share->method('getShareOwner')->willReturn('user2'); + $share->method('getAttributes')->willReturn(null); + + $this->shareManager->method('getShareByToken')->willReturn($share); + + $controller = $this->createMock(ISessionAwareController::class); + $controller->expects($this->never())->method('setUserId'); + $controller->expects($this->once())->method('setDocumentId'); + + $this->invokeMiddleware($share, $user, $controller); + } + + public function testLoggedInUserWithValidTokenUnauthenticated(): void { + $this->expectException(InvalidSessionException::class); + + $user = $this->createMock(IUser::class); + $user->method('getUID')->willReturn('user1'); + + $share = $this->createPasswordProtectedShare('user2-share'); + $this->session->method('get')->with('public_link_authenticated')->willReturn(null); + $this->shareManager->method('getShareByToken')->willReturn($share); + + $this->invokeMiddleware($share, $user); + } + private function createPasswordProtectedShare(string $id): IShare { $share = $this->createMock(IShare::class); $share->method('getId')->willReturn($id); $share->method('getPassword')->willReturn('password'); - $share->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_READ); + $share->method('getPermissions')->willReturn(Constants::PERMISSION_READ); $share->method('getShareOwner')->willReturn('owner'); $share->method('getAttributes')->willReturn(null); return $share; } - private function invokeMiddleware(IShare $share): void { + private function invokeMiddleware(IShare $share, ?IUser $user = null, ?ISessionAwareController $controller = null): void { $this->request->method('getParam')->willReturnMap([ ['documentId', null, 999], ['shareToken', null, 'token'], ]); - $this->userSession->method('getUser')->willReturn(null); + $this->userSession->method('getUser')->willReturn($user); $this->shareManager->method('getShareByToken')->willReturn($share); $folder = $this->createMock(Folder::class); - $folder->method('getFirstNodeById')->willReturn($this->createMock(\OCP\Files\File::class)); + $folder->method('getFirstNodeById')->willReturn($this->createMock(File::class)); $this->rootFolder->method('getUserFolder')->willReturn($folder); - $controller = $this->createMock(ISessionAwareController::class); + $controller ??= $this->createMock(ISessionAwareController::class); self::invokePrivate($this->middleware, 'assertUserOrShareToken', [$controller]); } }
Vulnerability mechanics
No source-code context for this CVE — mechanics is only generated when we can read the actual fix diff. Without that, the four sections (root cause, attack vector, affected code, fix) would be speculation rather than analysis.
References
3News mentions
0No linked articles in our index yet.