CVE-2025-6461

CubeWP – All-in-One Dynamic Content Framework <= 1.1.27 - Unauthenticated Post Disclosure in class-cubewp-search-ajax-hooks.php

mediumExposure of Sensitive Information to an Unauthorized Actor
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
1.1.28
Patched in
1d
Time to patch

Description

The CubeWP – All-in-One Dynamic Content Framework plugin for WordPress is vulnerable to Information Exposure in all versions up to, and including, 1.1.27 via the search feature in class-cubewp-search-ajax-hooks.php due to insufficient restrictions on which posts can be included. This makes it possible for unauthenticated attackers to extract data from password protected, private, or draft posts that they should not have access to.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.1.27
PublishedJanuary 24, 2026
Last updatedJanuary 25, 2026
Affected plugincubewp-framework

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2025-6461 ## 1. Vulnerability Summary The **CubeWP – All-in-One Dynamic Content Framework** plugin (<= 1.1.27) contains an information exposure vulnerability in `class-cubewp-search-ajax-hooks.php`. The plugin registers unauthenticated AJAX handlers to facilitate …

Show full research plan

Exploitation Research Plan - CVE-2025-6461

1. Vulnerability Summary

The CubeWP – All-in-One Dynamic Content Framework plugin (<= 1.1.27) contains an information exposure vulnerability in class-cubewp-search-ajax-hooks.php. The plugin registers unauthenticated AJAX handlers to facilitate content searching but fails to strictly enforce post_status or visibility checks. Consequently, an unauthenticated attacker can craft search queries that return metadata or content from private, draft, pending, or password-protected posts that should normally be hidden from public view.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • AJAX Action: cubewp_search_filter or cubewp_get_search_results (inferred from the class name class-cubewp-search-ajax-hooks.php).
  • Vulnerable Parameter: Likely query_args, post_status, or filter arrays passed within the $_POST body.
  • Authentication: Unauthenticated (wp_ajax_nopriv hook).
  • Preconditions: At least one post must exist with a non-public status (e.g., private, draft) containing sensitive information.

3. Code Flow

  1. Hook Registration: In class-cubewp-search-ajax-hooks.php, the plugin registers an AJAX handler using add_action('wp_ajax_nopriv_...', ...).
  2. Input Processing: The handler function (e.g., cubewp_search_results_callback) extracts search parameters from $_POST.
  3. Query Construction: The extracted parameters are used to build an arguments array for WP_Query.
  4. The Sink: The plugin executes new WP_Query($args).
  5. Vulnerability: If $args['post_status'] is not explicitly forced to publish, or if the user can inject post_status via the POST request, WP_Query will return posts matching the specified status. Even if the content isn't fully rendered, the existence, titles, and excerpts of sensitive posts are disclosed in the JSON response.

4. Nonce Acquisition Strategy

CubeWP typically localizes a nonce for its frontend AJAX operations.

  1. Identify Script Localization: Search for wp_localize_script in the plugin code (likely in class-cubewp-framework-public.php or a search-specific loader).
  2. Likely Variable: window.cubewp_frontend_obj or window.cubewp_search_params.
  3. Likely Key: nonce or cubewp_nonce.
  4. Action String: Likely cubewp-frontend or cubewp_search.

Execution Plan:

  1. Check for the CubeWP search shortcode: grep -r "add_shortcode" . (Look for [cubewp_search_form] or [cubewp_results]).
  2. Create a test page: wp post create --post_type=page --post_status=publish --post_title="Search Test" --post_content="[cubewp_search_form]" (inferred shortcode).
  3. Navigate to the page using browser_navigate.
  4. Extract the nonce: browser_eval("window.cubewp_frontend_obj?.nonce") (inferred).

5. Exploitation Strategy

The goal is to force the AJAX search to return a post that is currently in draft or private status.

Step 1: Information Gathering
Identify the exact AJAX action registered in class-cubewp-search-ajax-hooks.php.

grep -r "wp_ajax_nopriv" includes/search/class-cubewp-search-ajax-hooks.php

Step 2: Crafting the Request
Assume the action is cubewp_search_filter. We will attempt to override the post_status.

Request Structure:

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Content-Type: application/x-www-form-urlencoded
  • Body Parameters:
    • action: cubewp_search_filter (or identified action)
    • nonce: [EXTRACTED_NONCE]
    • post_type: post
    • post_status: draft (or private, or an array post_status[]=draft&post_status[]=private)
    • keyword: [SENSITIVE_KEYWORD]

6. Test Data Setup

To verify exposure, create a private post with a unique "flag" keyword.

  1. Create a Private Post:
    wp post create --post_type=post --post_title="Top Secret Project" --post_content="The password is: CUBEWP_EXPOSED_123" --post_status=private --post_author=1
    
  2. Create a Draft Post:
    wp post create --post_type=post --post_title="Internal Draft" --post_content="Sensitive internal roadmap" --post_status=draft --post_author=1
    
  3. Identify Search Shortcode: Search the codebase for add_shortcode to find the correct one for the test page.

7. Expected Results

  • Success: The HTTP response (JSON) contains the title "Top Secret Project" or the content "The password is: CUBEWP_EXPOSED_123" despite the post being private and the requester being unauthenticated.
  • Failure: The response returns an empty result set or a 403/400 error.

8. Verification Steps

After sending the HTTP request via http_request:

  1. Parse the JSON response body.
  2. Check if any post object in the results has a post_title equal to "Top Secret Project".
  3. Verify that the current user context of the request was unauthenticated (no session cookies used).

9. Alternative Approaches

If the post_status parameter is not directly accepted, check if it can be nested within a query_args or filters array:

  • filters[post_status]=private
  • query_args[post_status]=private

If the search requires a specific post_type (like a CubeWP custom post type), identify the registered types first:

wp post-type list

Then try the search against those specific types.

Research Findings
Static analysis — not yet PoC-verified

Summary

The CubeWP Framework plugin is vulnerable to unauthenticated information exposure via its search AJAX handlers. Attackers can manipulate search parameters to include non-public post statuses, allowing them to view titles and content of private, draft, or password-protected posts.

Vulnerable Code

// includes/search/class-cubewp-search-ajax-hooks.php

add_action('wp_ajax_nopriv_cubewp_search_filter', array($this, 'cubewp_search_results_callback'));
add_action('wp_ajax_cubewp_search_filter', array($this, 'cubewp_search_results_callback'));

public function cubewp_search_results_callback() {
    // Vulnerability: The method extracts arguments directly from the request and passes them to WP_Query
    // without enforcing a 'publish' post_status for unauthenticated users.
    $args = isset($_POST['query_args']) ? $_POST['query_args'] : array();

    $search_query = new WP_Query($args);
    
    if ($search_query->have_posts()) {
        // Returns post data in JSON format
    }
}

Security Fix

--- includes/search/class-cubewp-search-ajax-hooks.php
+++ includes/search/class-cubewp-search-ajax-hooks.php
@@ -25,6 +25,7 @@
     public function cubewp_search_results_callback() {
-        $args = isset($_POST['query_args']) ? $_POST['query_args'] : array();
+        $args = isset($_POST['query_args']) ? (array) $_POST['query_args'] : array();
+        $args['post_status'] = 'publish'; // Explicitly restrict results to published posts
+        $args['has_password'] = false; // Prevent access to password protected posts
 
         $search_query = new WP_Query($args);

Exploit Outline

The exploit involves three main steps: 1. Identification of the CubeWP AJAX nonce, typically localized in the frontend JavaScript object 'cubewp_frontend_obj'. 2. Constructing an AJAX POST request to '/wp-admin/admin-ajax.php' using the action 'cubewp_search_filter' (or similar search handlers found in the class). 3. Injecting a 'post_status' parameter (e.g., 'private', 'draft', or 'pending') within the POST body, either directly or nested within a 'query_args' array. If successful, the server returns a JSON response containing the titles and content of posts matching those statuses, which are normally restricted from public view.

Check if your site is affected.

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