VYPR
High severity8.1NVD Advisory· Published Jun 1, 2026

CVE-2026-45281

CVE-2026-45281

Description

Nextcloud Server allows authenticated users to access and modify other users' calendars due to improper authorization controls.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Nextcloud Server allows authenticated users to access and modify other users' calendars due to improper authorization controls.

Vulnerability

Nextcloud Server versions 32.0.0 to before 32.0.9 and 33.0.0 to before 33.0.3 are affected by improper authorization controls in the calendar backend. An authenticated attacker with knowledge of another user's principal URL can gain unauthorized access to their calendar [1].

Exploitation

An attacker must first be an authenticated user within Nextcloud. With knowledge of a target user's principal URL, the attacker can send a crafted request to the calendar backend to access and modify the target user's calendar data [1].

Impact

Successful exploitation allows an attacker to gain full access to a target user's calendar, enabling them to view and modify its contents. This compromises the confidentiality and integrity of the calendar data [1].

Mitigation

Nextcloud Server should be upgraded to version 33.0.3 or 32.0.9. For Nextcloud Enterprise Server, specific upgraded versions are recommended, including 33.0.3 and 32.0.9, among others [1]. As a temporary workaround, access to the endpoints remote.php/dav/principals/users//calendar-proxy-read and remote.php/dav/principals/users//calendar-proxy-write can be blocked, and the oc_dav_cal_proxy table can be cleared if data integrity is a concern [1].

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

1

Patches

1
60a1e725e0c2

Merge pull request #59962 from nextcloud/fix/delegation/add-acls

https://github.com/nextcloud/serverHamzaApr 28, 2026via nvd-ref
7 files changed · +116 15
  • apps/dav/composer/composer/autoload_classmap.php+2 0 modified
    @@ -96,6 +96,8 @@
         'OCA\\DAV\\CalDAV\\Outbox' => $baseDir . '/../lib/CalDAV/Outbox.php',
         'OCA\\DAV\\CalDAV\\Plugin' => $baseDir . '/../lib/CalDAV/Plugin.php',
         'OCA\\DAV\\CalDAV\\Principal\\Collection' => $baseDir . '/../lib/CalDAV/Principal/Collection.php',
    +    'OCA\\DAV\\CalDAV\\Principal\\ProxyRead' => $baseDir . '/../lib/CalDAV/Principal/ProxyRead.php',
    +    'OCA\\DAV\\CalDAV\\Principal\\ProxyWrite' => $baseDir . '/../lib/CalDAV/Principal/ProxyWrite.php',
         'OCA\\DAV\\CalDAV\\Principal\\User' => $baseDir . '/../lib/CalDAV/Principal/User.php',
         'OCA\\DAV\\CalDAV\\Proxy\\Proxy' => $baseDir . '/../lib/CalDAV/Proxy/Proxy.php',
         'OCA\\DAV\\CalDAV\\Proxy\\ProxyMapper' => $baseDir . '/../lib/CalDAV/Proxy/ProxyMapper.php',
    
  • apps/dav/composer/composer/autoload_static.php+2 0 modified
    @@ -111,6 +111,8 @@ class ComposerStaticInitDAV
             'OCA\\DAV\\CalDAV\\Outbox' => __DIR__ . '/..' . '/../lib/CalDAV/Outbox.php',
             'OCA\\DAV\\CalDAV\\Plugin' => __DIR__ . '/..' . '/../lib/CalDAV/Plugin.php',
             'OCA\\DAV\\CalDAV\\Principal\\Collection' => __DIR__ . '/..' . '/../lib/CalDAV/Principal/Collection.php',
    +        'OCA\\DAV\\CalDAV\\Principal\\ProxyRead' => __DIR__ . '/..' . '/../lib/CalDAV/Principal/ProxyRead.php',
    +        'OCA\\DAV\\CalDAV\\Principal\\ProxyWrite' => __DIR__ . '/..' . '/../lib/CalDAV/Principal/ProxyWrite.php',
             'OCA\\DAV\\CalDAV\\Principal\\User' => __DIR__ . '/..' . '/../lib/CalDAV/Principal/User.php',
             'OCA\\DAV\\CalDAV\\Proxy\\Proxy' => __DIR__ . '/..' . '/../lib/CalDAV/Proxy/Proxy.php',
             'OCA\\DAV\\CalDAV\\Proxy\\ProxyMapper' => __DIR__ . '/..' . '/../lib/CalDAV/Proxy/ProxyMapper.php',
    
  • apps/dav/lib/CalDAV/Principal/ProxyRead.php+23 0 added
    @@ -0,0 +1,23 @@
    +<?php
    +
    +declare(strict_types=1);
    +
    +/**
    + * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
    + * SPDX-License-Identifier: AGPL-3.0-or-later
    + */
    +
    +namespace OCA\DAV\CalDAV\Principal;
    +
    +use Sabre\DAVACL;
    +
    +class ProxyRead extends \Sabre\CalDAV\Principal\ProxyRead implements DAVACL\IACL {
    +	use DAVACL\ACLTrait;
    +
    +	/**
    +	 * @inheritDoc
    +	 */
    +	public function getOwner() {
    +		return $this->principalInfo['uri'];
    +	}
    +}
    
  • apps/dav/lib/CalDAV/Principal/ProxyWrite.php+23 0 added
    @@ -0,0 +1,23 @@
    +<?php
    +
    +declare(strict_types=1);
    +
    +/**
    + * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
    + * SPDX-License-Identifier: AGPL-3.0-or-later
    + */
    +
    +namespace OCA\DAV\CalDAV\Principal;
    +
    +use Sabre\DAVACL;
    +
    +class ProxyWrite extends \Sabre\CalDAV\Principal\ProxyWrite implements DAVACL\IACL {
    +	use DAVACL\ACLTrait;
    +
    +	/**
    +	 * @inheritDoc
    +	 */
    +	public function getOwner() {
    +		return $this->principalInfo['uri'];
    +	}
    +}
    
  • apps/dav/lib/CalDAV/Principal/User.php+40 0 modified
    @@ -36,4 +36,44 @@ public function getACL() {
     		];
     		return $acl;
     	}
    +
    +	/**
    +	 * Returns a specific child node, referenced by its name.
    +	 *
    +	 * @param string $name
    +	 *
    +	 * @return \Sabre\DAV\INode
    +	 */
    +	public function getChild($name) {
    +		$principal = $this->principalBackend->getPrincipalByPath($this->getPrincipalURL() . '/' . $name);
    +		if (!$principal) {
    +			throw new \Sabre\DAV\Exception\NotFound("Node with name $name was not found");
    +		}
    +		if ($name === 'calendar-proxy-read') {
    +			return new ProxyRead($this->principalBackend, $this->principalProperties);
    +		}
    +
    +		if ($name === 'calendar-proxy-write') {
    +			return new ProxyWrite($this->principalBackend, $this->principalProperties);
    +		}
    +
    +		throw new \Sabre\DAV\Exception\NotFound("Node with name $name was not found");
    +	}
    +
    +	/**
    +	 * Returns an array with all the child nodes.
    +	 *
    +	 * @return \Sabre\DAV\INode[]
    +	 */
    +	public function getChildren() {
    +		$r = [];
    +		if ($this->principalBackend->getPrincipalByPath($this->getPrincipalURL() . '/calendar-proxy-read')) {
    +			$r[] = new ProxyRead($this->principalBackend, $this->principalProperties);
    +		}
    +		if ($this->principalBackend->getPrincipalByPath($this->getPrincipalURL() . '/calendar-proxy-write')) {
    +			$r[] = new ProxyWrite($this->principalBackend, $this->principalProperties);
    +		}
    +
    +		return $r;
    +	}
     }
    
  • build/integration/dav_features/caldav-delegation.feature+8 1 modified
    @@ -20,4 +20,11 @@ Feature: calendar delegation
         When "admin" updates property "{DAV:}group-member-set" to href "/remote.php/dav/principals/users/user0" of principal "users/admin/calendar-proxy-write" on the endpoint "/remote.php/dav/principals/"
         Then The CalDAV response should be multi status
         And The CalDAV response should contain an href "/remote.php/dav/principals/users/admin/calendar-proxy-write"
    -    And The CalDAV response should contain a property "{DAV:}group-member-set"
    \ No newline at end of file
    +    And The CalDAV response should contain a property "{DAV:}group-member-set"
    +  
    +  Scenario: Admin cannot grant User1 access to User0's calendar account
    +    Given user "admin" exists
    +    And user "user0" exists
    +    And user "user1" exists
    +    When "admin" updates property "{DAV:}group-member-set" to href "/remote.php/dav/principals/users/user1" of principal "users/user0/calendar-proxy-write" on the endpoint "/remote.php/dav/principals/"
    +    Then The CalDAV HTTP status code should be "404"
    \ No newline at end of file
    
  • build/integration/features/bootstrap/CalDavContext.php+18 14 modified
    @@ -408,19 +408,23 @@ public function updatesHrefPropertyOfPrincipal(
     		$xml = new \Sabre\Xml\Service();
     		$body = $xml->write('{DAV:}propertyupdate', $propPatch, '/');
     
    -		$this->response = $this->client->request(
    -			'PROPPATCH',
    -			$davUrl,
    -			[
    -				'headers' => [
    -					'Content-Type' => 'application/xml; charset=UTF-8',
    -				],
    -				'body' => $body,
    -				'auth' => [
    -					$user,
    -					$password,
    -				],
    -			]
    -		);
    +		try {
    +			$this->response = $this->client->request(
    +				'PROPPATCH',
    +				$davUrl,
    +				[
    +					'headers' => [
    +						'Content-Type' => 'application/xml; charset=UTF-8',
    +					],
    +					'body' => $body,
    +					'auth' => [
    +						$user,
    +						$password,
    +					],
    +				]
    +			);
    +		} catch (\GuzzleHttp\Exception\ClientException $e) {
    +			$this->response = $e->getResponse();
    +		}
     	}
     }
    

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

3

News mentions

0

No linked articles in our index yet.