CubeWP – All-in-One Dynamic Content Framework <= 1.1.27 - Unauthenticated Post Disclosure in class-cubewp-search-ajax-hooks.php
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:NTechnical Details
<=1.1.27Source Code
WordPress.org SVN# 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_filterorcubewp_get_search_results(inferred from the class nameclass-cubewp-search-ajax-hooks.php). - Vulnerable Parameter: Likely
query_args,post_status, or filter arrays passed within the$_POSTbody. - Authentication: Unauthenticated (
wp_ajax_noprivhook). - Preconditions: At least one post must exist with a non-public status (e.g.,
private,draft) containing sensitive information.
3. Code Flow
- Hook Registration: In
class-cubewp-search-ajax-hooks.php, the plugin registers an AJAX handler usingadd_action('wp_ajax_nopriv_...', ...). - Input Processing: The handler function (e.g.,
cubewp_search_results_callback) extracts search parameters from$_POST. - Query Construction: The extracted parameters are used to build an arguments array for
WP_Query. - The Sink: The plugin executes
new WP_Query($args). - Vulnerability: If
$args['post_status']is not explicitly forced topublish, or if the user can injectpost_statusvia the POST request,WP_Querywill 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.
- Identify Script Localization: Search for
wp_localize_scriptin the plugin code (likely inclass-cubewp-framework-public.phpor a search-specific loader). - Likely Variable:
window.cubewp_frontend_objorwindow.cubewp_search_params. - Likely Key:
nonceorcubewp_nonce. - Action String: Likely
cubewp-frontendorcubewp_search.
Execution Plan:
- Check for the CubeWP search shortcode:
grep -r "add_shortcode" .(Look for[cubewp_search_form]or[cubewp_results]). - Create a test page:
wp post create --post_type=page --post_status=publish --post_title="Search Test" --post_content="[cubewp_search_form]"(inferred shortcode). - Navigate to the page using
browser_navigate. - 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:postpost_status:draft(orprivate, or an arraypost_status[]=draft&post_status[]=private)keyword:[SENSITIVE_KEYWORD]
6. Test Data Setup
To verify exposure, create a private post with a unique "flag" keyword.
- 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 - 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 - Identify Search Shortcode: Search the codebase for
add_shortcodeto 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
privateand 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:
- Parse the JSON response body.
- Check if any post object in the results has a
post_titleequal to "Top Secret Project". - 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]=privatequery_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.
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
@@ -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.