Listdom <= 5.0.1 - Missing Authorization
Description
The AI-Powered Business Directory and Classified Ads Listings – Listdom plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 5.0.1. This makes it possible for authenticated attackers, with Contributor-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
<=5.0.1Source Code
WordPress.org SVNThis research plan targets **CVE-2025-67560**, a Missing Authorization vulnerability in the **Listdom** plugin (<= 5.0.1). The vulnerability allows **Contributor-level** users to execute functions that should be restricted to administrators. ### 1. Vulnerability Summary * **Vulnerability:** Missi…
Show full research plan
This research plan targets CVE-2025-67560, a Missing Authorization vulnerability in the Listdom plugin (<= 5.0.1). The vulnerability allows Contributor-level users to execute functions that should be restricted to administrators.
1. Vulnerability Summary
- Vulnerability: Missing Authorization (Broken Access Control).
- Location: AJAX handlers registered via
wp_ajax_listdom_*. - Cause: The plugin registers AJAX actions for authenticated users (
wp_ajax_) but fails to verify the user's capabilities (e.g.,current_user_can('manage_options')) within the callback functions. - Impact: A Contributor can perform actions such as modifying plugin settings, manipulating listing data, or triggering AI features that are intended for administrators.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Authentication: Authenticated (Contributor level).
- Vulnerable Actions (Candidates):
listdom_save_settingslistdom_change_statuslistdom_import_jsonlistdom_ai_generate_content(inferred from "AI-powered" title)
- Preconditions: A Contributor user account is required.
3. Code Flow
- Registration: The plugin registers an AJAX action in a file like
includes/class-listdom-ajax.phporadmin/class-listdom-admin-ajax.php.- Example:
add_action( 'wp_ajax_listdom_save_settings', array( $this, 'save_settings_callback' ) );
- Example:
- Trigger: A Contributor sends a POST request to
admin-ajax.phpwithaction=listdom_save_settings. - Bypass: The
save_settings_callback()function checks for a nonce but neglects to checkcurrent_user_can(). - Execution: The function proceeds to update the
wp_optionstable or modify listing posts.
4. Nonce Acquisition Strategy
Listdom typically localizes its AJAX configuration for the admin dashboard. Since Contributors have access to the /wp-admin/ backend, they can extract the required nonce from the page source.
- Localization Object:
listdom_admin_ajax_obj(inferred) orlistdom_vars. - Nonce Key:
listdom_nonceornonce. - Strategy:
- Log in as a Contributor.
- Navigate to the Dashboard (
/wp-admin/index.php). - Execute
browser_evalto find the nonce in the global JavaScript scope. - JS Command:
browser_eval("window.listdom_admin_ajax_obj?.nonce || window.listdom_vars?.nonce")(Verify the exact variable name in the page source if this fails).
5. Exploitation Strategy
We will attempt to modify a global plugin setting to demonstrate unauthorized access.
- Target Setting:
listdom_registration_status(or any setting stored inlistdom_options). - Request Details:
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body Parameters:
action:listdom_save_settings(inferred)nonce:[EXTRACTED_NONCE]settings: URL-encoded JSON or array data containing the malicious configuration.
- URL:
6. Test Data Setup
- User: Create a user with the
contributorrole. - Plugin State: Ensure Listdom is active and a basic listing is created if testing listing manipulation.
- Discovery: Use the following command to find the exact AJAX actions:
grep -rn "wp_ajax_listdom_" /var/www/html/wp-content/plugins/listdom/
7. Expected Results
- Success: The server returns a
200 OK(often with a JSON success message like{"success": true}). - Impact: A setting typically reserved for admins (e.g., directory privacy or AI API keys) is updated via the Contributor's request.
8. Verification Steps
After sending the HTTP request, use WP-CLI to verify the change:
- Check Options:
wp option get listdom_options - Confirm Lack of Authorization: Verify the function code in the plugin to confirm the absence of a capability check:
# Search for the function name identified in step 2 grep -A 10 "function [FUNCTION_NAME]" /var/www/html/wp-content/plugins/listdom/
9. Alternative Approaches
If listdom_save_settings is not the vulnerable hook, target listing status manipulation:
- Identify Action: Look for
listdom_change_statusorlistdom_update_listing. - Setup: Create a Listing with
post_status='pending'. - Exploit: Send a POST request as Contributor to update that listing to
publish. - Verification:
wp post list --post_type=listdom-listingto check if the status changed topublish.
Summary
The Listdom plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on its AJAX handlers in versions up to 5.0.1. This enables authenticated attackers with Contributor-level access or higher to perform administrative actions, such as updating plugin settings or modifying listing statuses, because the plugin only validates nonces but not user permissions.
Security Fix
@@ -10,4 +10,7 @@ public function save_settings_callback() { check_ajax_referer( 'listdom_nonce', 'nonce' ); + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( array( 'message' => 'Unauthorized access' ) ); + } $settings = $_POST['settings']; update_option( 'listdom_options', $settings ); wp_send_json_success(); } @@ -20,4 +23,7 @@ public function change_status_callback() { check_ajax_referer( 'listdom_nonce', 'nonce' ); + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( array( 'message' => 'Unauthorized access' ) ); + } $post_id = $_POST['post_id']; $status = $_POST['status']; wp_update_post( array( 'ID' => $post_id, 'post_status' => $status ) );
Exploit Outline
To exploit this vulnerability, an attacker with Contributor-level access logs into the WordPress dashboard and extracts a valid AJAX nonce from the localized JavaScript objects (e.g., 'listdom_admin_ajax_obj'). The attacker then constructs a POST request to '/wp-admin/admin-ajax.php' with the 'action' parameter set to a vulnerable handler such as 'listdom_save_settings'. By including the extracted nonce and the desired payload (e.g., modified configuration data in the 'settings' parameter), the attacker can execute administrative changes without having the 'manage_options' capability.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.