Skip to content

Conversation

@Akhill2020
Copy link
Contributor

@Akhill2020 Akhill2020 commented Dec 1, 2025

Description: We got an message regarding IDOR vulnerability from patchstack, in this if any calendar is private assign still in ajax request someone can pass the private calendar ID and get the HTML for this private calendars events which is now fix by adding permission check and check for longed in user if the calendar is set to private for public it is working as it is.

Clickup: https://app.clickup.com/t/86d135nbm

Summary by CodeRabbit

  • Bug Fixes

    • Added server-side validation for calendar AJAX endpoints to ensure calendars exist and enforce per-calendar access, returning clear JSON errors when access is denied or not found.
    • Fixed cover image display for Google Calendar events and resolved an IDOR vulnerability.
  • Chores

    • Release bumped to 3.6.0; added cache clearing on first activation and during manual updates.
  • Documentation

    • Updated readme: now requires PHP 8.1 and notes breaking change dropping support for PHP < 8.0.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 1, 2025

📝 Walkthrough

Walkthrough

Adds server-side access validation to two AJAX calendar handlers (grid and list) ensuring the post exists, is type calendar, and enforces status/capability checks; bumps package version to 3.6.0 and updates readme/changelog to require PHP 8.1 and note fixes.

Changes

Cohort / File(s) Change Summary
AJAX Security: Grid handler
includes/calendars/views/default-calendar-grid.php
Adds validation that the requested post exists and has post_type === 'calendar'; checks post_status and enforces current_user_can('read_post', $id) for non-public statuses; returns JSON error on failure before calling draw_month.
AJAX Security: List handler
includes/calendars/views/default-calendar-list.php
Adds validation that the requested post exists and has post_type === 'calendar'; enforces access based on post_status (publish allowed; non-published require read_post); returns JSON error on failure before calling draw_list.
Metadata: Version bump
package.json
Updates version from 3.5.9 to 3.6.0.
Docs: Changelog & requirements
readme.txt
Adds v3.6.0 changelog entries (IDOR fix, OAuth cover image fix, cache clearing on activation/update) and updates minimum PHP requirement to 8.1.

Sequence Diagram(s)

sequenceDiagram
    participant Browser as Client (AJAX)
    participant Handler as WP AJAX Handler
    participant Posts as WP DB (posts)
    participant Auth as WP Auth/Capabilities

    Browser->>Handler: POST fetch grid/list (calendar_id, nonce)
    Handler->>Posts: get_post(calendar_id)
    Posts-->>Handler: post or null
    alt post missing OR post_type != "calendar"
        Handler-->>Browser: JSON error (invalid calendar)
    else
        Handler->>Auth: evaluate post_status
        alt post_status == "publish"
            Auth-->>Handler: allow
        else
            Handler->>Auth: current_user_can('read_post', calendar_id)
            alt has permission
                Auth-->>Handler: allow
            else
                Auth-->>Handler: deny
            end
        end
        alt denied
            Handler-->>Browser: JSON error (permission denied)
        else allowed
            Handler->>Handler: call draw_month/draw_list -> render HTML
            Handler-->>Browser: JSON success (HTML payload)
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • rosinghal

Poem

🐇 I hopped through lines to guard each date,

Checked each calendar before I open the gate.
Grid and list now ask kindly who you are,
So events stay safe, near and far. 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly addresses the main security fix (IDOR vulnerability) that is the primary focus of this PR, matching the core changes in both affected files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
includes/calendars/views/default-calendar-grid.php (1)

664-669: Redundant login check for private calendars.

The is_user_logged_in() check is redundant because current_user_can('read_post', $id) already returns false for logged-out users when the post is private.

Apply this diff to simplify the logic:

 } elseif ($post->post_status === 'private') {
-	// Private calendar - check if user has permission
-	if (!is_user_logged_in() || !current_user_can('read_post', $id)) {
+	// Private calendar - check if user has permission
+	if (!current_user_can('read_post', $id)) {
 		wp_send_json_error('You do not have permission to view this calendar.');
 		return;
 	}
includes/calendars/views/default-calendar-list.php (1)

791-796: Redundant login check for private calendars.

The is_user_logged_in() check is redundant because current_user_can('read_post', $id) already returns false for logged-out users when the post is private.

Apply this diff to simplify the logic:

 } elseif ($post->post_status === 'private') {
-	// Private calendar - check if user has permission
-	if (!is_user_logged_in() || !current_user_can('read_post', $id)) {
+	// Private calendar - check if user has permission
+	if (!current_user_can('read_post', $id)) {
 		wp_send_json_error('You do not have permission to view this calendar.');
 		return;
 	}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bb600c4 and 12c8fe3.

📒 Files selected for processing (2)
  • includes/calendars/views/default-calendar-grid.php (1 hunks)
  • includes/calendars/views/default-calendar-list.php (1 hunks)
🧰 Additional context used
🪛 GitHub Actions: build
includes/calendars/views/default-calendar-list.php

[error] 1-1: Prettier formatting check failed on this file. Run 'prettier --write' to fix code style issues.

includes/calendars/views/default-calendar-grid.php

[error] 1-1: Prettier formatting check failed on this file. Run 'prettier --write' to fix code style issues.

🔇 Additional comments (1)
includes/calendars/views/default-calendar-list.php (1)

779-803: LGTM! Effective IDOR vulnerability fix.

The security validation properly addresses the reported IDOR vulnerability by enforcing access control based on post status and user capabilities. The implementation correctly uses WordPress core functions and follows the platform's security model.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
includes/calendars/views/default-calendar-grid.php (2)

645-682: IDOR fix looks correct, but consider adding nonce verification for CSRF protection.

The permission checks properly address the IDOR vulnerability by validating post existence, type, and user capabilities before rendering. However, this AJAX handler lacks nonce verification, which is a WordPress security best practice for AJAX endpoints to prevent CSRF attacks.

Consider adding nonce verification:

 public function draw_grid_ajax()
 {
     if (isset($_POST['month']) && isset($_POST['year']) && isset($_POST['id'])) {
+        // Verify nonce for CSRF protection
+        if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'simcal_default_calendar')) {
+            wp_send_json_error('Security check failed.');
+            return;
+        }
+
         $month = absint($_POST['month']);
         $year = absint($_POST['year']);
         $id = absint($_POST['id']);

Note: This would require passing a nonce from the JavaScript side when making the AJAX request.


662-676: Consider refactoring to eliminate the empty if-block.

The empty if block for published status is functional but could be cleaner using early return or restructured conditions.

-       // Check if post is published (public) or user has permission to read it
-       if ($post->post_status === 'publish') {
-           // Public calendar - allow access
-       } elseif ($post->post_status === 'private') {
-           // Private calendar - check if user has permission
-           if (!is_user_logged_in() || !current_user_can('read_post', $id)) {
-               wp_send_json_error('You do not have permission to view this calendar.');
-               return;
-           }
-       } else {
-           // Draft, pending, or other status - check if user has permission
-           if (!current_user_can('read_post', $id)) {
-               wp_send_json_error('You do not have permission to view this calendar.');
-               return;
-           }
-       }
+       // Check if user has permission to view the calendar
+       if ($post->post_status !== 'publish') {
+           // Private calendars require login
+           if ($post->post_status === 'private' && !is_user_logged_in()) {
+               wp_send_json_error('You do not have permission to view this calendar.');
+               return;
+           }
+           // Non-public calendars require read capability
+           if (!current_user_can('read_post', $id)) {
+               wp_send_json_error('You do not have permission to view this calendar.');
+               return;
+           }
+       }
includes/calendars/views/default-calendar-list.php (1)

773-809: IDOR fix correctly mirrors the grid view implementation.

The permission checks are consistent with the grid view handler, properly addressing the IDOR vulnerability. The same recommendations apply:

  1. Consider adding nonce verification for CSRF protection
  2. The empty if block for publish status could be refactored

Apply the same nonce verification pattern suggested for the grid view:

 public function draw_list_ajax()
 {
     if (isset($_POST['ts']) && isset($_POST['id'])) {
+        // Verify nonce for CSRF protection
+        if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'simcal_default_calendar')) {
+            wp_send_json_error('Security check failed.');
+            return;
+        }
+
         $ts = absint($_POST['ts']);
         $id = absint($_POST['id']);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 12c8fe3 and dfaefb1.

📒 Files selected for processing (4)
  • includes/calendars/views/default-calendar-grid.php (1 hunks)
  • includes/calendars/views/default-calendar-list.php (1 hunks)
  • package.json (1 hunks)
  • readme.txt (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • readme.txt
🔇 Additional comments (2)
package.json (1)

5-5: Version bump aligns with security fix.

The version increment to 3.5.10 appropriately reflects the IDOR vulnerability fix being introduced.

includes/calendars/views/default-calendar-list.php (1)

139-156: The nonce is already available in the frontend. The simcal_common_scripts_variables() function at includes/functions/shared.php:166 creates and passes the nonce to the frontend via wp_create_nonce('simcal'), which is then localized as part of the script variables. The frontend JavaScript can access this nonce through the localized simcal_default_calendar object.

Likely an incorrect or invalid review comment.

@Akhill2020 Akhill2020 requested a review from rosinghal January 6, 2026 08:06
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dfaefb1 and 569b21d.

📒 Files selected for processing (1)
  • includes/calendars/views/default-calendar-list.php
🔇 Additional comments (1)
includes/calendars/views/default-calendar-list.php (1)

779-786: LGTM: Post validation is correct.

The validation properly checks that the post exists and is of type 'calendar' before proceeding with access control checks.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
readme.txt (1)

101-101: Minor: Clarify the PHP requirement inconsistency.

Line 101 states "Support for PHP versions below 8.0 has been discontinued," which implies PHP 8.0+ is supported. However, line 5 specifies "Requires PHP: 8.1," which is stricter. This could confuse users running PHP 8.0.

Consider updating the changelog to read: "Support for PHP versions below 8.1 has been discontinued" to align with the actual requirement.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 383ef77 and cbc337e.

⛔ Files ignored due to path filters (1)
  • composer.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • package.json
  • readme.txt
🚧 Files skipped from review as they are similar to previous changes (1)
  • package.json
🔇 Additional comments (1)
readme.txt (1)

100-104: LGTM – changelog properly documents the IDOR fix.

The new 3.6.0 changelog entry clearly documents the Insecure Direct Object Reference (IDOR) vulnerability fix alongside other improvements. The breaking change for PHP version is also properly flagged.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
includes/calendars/views/default-calendar-list.php (1)

779-797: Effective IDOR fix with room for defense-in-depth improvements.

The security validation correctly addresses the IDOR vulnerability by:

  • Validating the calendar post exists and is the correct type
  • Allowing public calendars unrestricted access
  • Requiring read_post capability for non-public calendars, which properly leverages WordPress's permission system

Consider these defense-in-depth enhancements:

  1. Add nonce verification to prevent programmatic enumeration of calendar IDs:
check_ajax_referer('simcal_default_calendar_nonce', 'nonce');
  1. Use generic error messages to avoid information disclosure:
// Instead of different messages, use:
wp_send_json_error('Unable to load calendar.');
  1. Simplify the conditional to avoid the empty if-block:
♻️ Optional refactor
-// Check if post is published (public) or user has permission to read it
-if ($post->post_status === 'publish') {
-    // Public calendar - allow access
-} else {
-    // Draft, pending, or other status - check if user has permission
-    if (!current_user_can('read_post', $id)) {
-        wp_send_json_error('You do not have permission to view this calendar.');
-        return;
-    }
-}
+// Check if post is published (public) or user has permission to read it
+if ($post->post_status !== 'publish' && !current_user_can('read_post', $id)) {
+    wp_send_json_error('Unable to load calendar.');
+    return;
+}
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cbc337e and 761128d.

📒 Files selected for processing (2)
  • includes/calendars/views/default-calendar-grid.php
  • includes/calendars/views/default-calendar-list.php
🚧 Files skipped from review as they are similar to previous changes (1)
  • includes/calendars/views/default-calendar-grid.php

@Akhill2020 Akhill2020 merged commit 2c55629 into main Jan 8, 2026
3 checks passed
@Akhill2020 Akhill2020 deleted the issue-idor-vulnarability branch January 8, 2026 12:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants