[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fbDyZH99tf4bZsAbHpdCTZZaL5LTLWjimjN_21eMd5b8":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":30,"research_verified":31,"research_rounds_completed":32,"research_plan":33,"research_summary":34,"research_vulnerable_code":35,"research_fix_diff":36,"research_exploit_outline":37,"research_model_used":38,"research_started_at":39,"research_completed_at":40,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":31,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":31,"source_links":41},"CVE-2026-42640","classified-listing-ai-powered-classified-ads-business-directory-plugin-missing-authorization-2","Classified Listing – AI-Powered Classified ads & Business Directory Plugin \u003C= 5.3.8 - Missing Authorization","The Classified Listing – AI-Powered Classified ads & Business Directory Plugin plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 5.3.8. This makes it possible for unauthenticated attackers to perform an unauthorized action.","classified-listing",null,"\u003C=5.3.8","5.3.9","medium",5.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:N\u002FS:U\u002FC:N\u002FI:L\u002FA:N","Missing Authorization","2026-04-29 00:00:00","2026-05-04 13:57:35",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Fcbb25a81-a92b-4773-9194-9aa355750817?source=api-prod",6,[22,23,24,25,26,27,28,29],"README.txt","app\u002FControllers\u002FAjax\u002FAjaxCFG.php","app\u002FControllers\u002FAjax\u002FAjaxSettings.php","app\u002FControllers\u002FAjax\u002FCheckout.php","app\u002FControllers\u002FAjax\u002FExport.php","app\u002FControllers\u002FAjax\u002FFilterFormAdminAjax.php","app\u002FControllers\u002FAjax\u002FFormBuilderAjax.php","app\u002FControllers\u002FAjax\u002FImport.php","researched",false,3," 5.3.8) doesn't check if the user owns the image, an unauthenticated attacker can delete any attachment in the WordPress media library by guessing the ID. This is a classic \"Missing Authorization\" (IDOR) that fits the \"unauthenticated\" profile.\n    However, the description says \"Missing Authorization\" (Missing capability check). This usually means a function that *should* be admin-only.\n\n    Let's go with the most obvious \"Admin function with missing capability check\":\n    **`rtcl_edit_field_insert`** or **`rtcl_edit_field_delete`** in `AjaxCFG.php`.\n    Even though the snippet doesn't show `nopriv`, I'll assume it's reachable or the vulnerability is Subscriber+.\n    Wait, the CVSS is 5.3.\n    `AV:N\u002FAC:L\u002FPR:N\u002FUI:N\u002FS:U\u002FC:N\u002FI:L\u002FA:N`\n    `I:L` (Integrity: Low), `A:N` (Availability: None).\n    This matches \"Unauthorized action\" like creating a draft post or changing a minor setting.\n    If it were `A:H`, it would be deleting posts.\n\n    Okay, `AjaxCFG::edit_field_insert`.\n    It creates a draft post. Integrity: Low.\n    `FilterFormAdminAjax::create_update_filter`.\n    It updates an option. Integrity: Low.\n\n","The Classified Listing plugin fails to perform capability checks in several AJAX handlers, allowing unauthenticated or low-privileged users to manage custom fields, modify filter settings, and update global configuration options. Additionally, file upload handlers lacked ownership verification, permitting users to attach files to arbitrary listings.","\u002F\u002F app\u002FControllers\u002FAjax\u002FAjaxCFG.php:18\n\tfunction edit_field_delete() {\n\t\t$data = null;\n\t\t$error = true;\n\t\tif ( Functions::verify_nonce() ) {\n\t\t\t$post_id = !empty( $_REQUEST['id'] ) ? $_REQUEST['id'] : 0;\n\t\t\tif ( $post_id && ( $post = get_post( $post_id ) ) && $post->post_type === rtcl()->post_type_cf ) {\n\t\t\t\t$p = wp_delete_post( $post_id, true );\n\n---\n\n\u002F\u002F app\u002FControllers\u002FAjax\u002FFilterFormAdminAjax.php:20\n\tpublic function create_update_filter() {\n\t\tif ( !wp_verify_nonce( isset( $_REQUEST[rtcl()->nonceId] ) ? $_REQUEST[rtcl()->nonceId] : null, rtcl()->nonceText ) ) {\n\t\t\twp_send_json_error( esc_html__( 'Session error !!', 'classified-listing' ) );\n\t\t}\n\t\t$filterId = !empty( $_POST['filterId'] ) ? sanitize_text_field( wp_unslash( $_POST['filterId'] ) ) : '';\n\n---\n\n\u002F\u002F app\u002FControllers\u002FAjax\u002FFormBuilderAjax.php:664 (Before ownership check was added)\n\t\t$parent_post_id = isset( $_POST[\"listingId\"] ) ? absint( $_POST[\"listingId\"] ) : 0;\n\n\t\tFilters::beforeUpload();\n\t\t\u002F\u002F you can use WP's wp_handle_upload() function:\n\t\t$status = wp_handle_upload( $_FILES['image'], [ 'test_form' => false ] );","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fclassified-listing\u002F5.3.8\u002Fapp\u002FControllers\u002FAjax\u002FAjaxCFG.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fclassified-listing\u002F5.3.9\u002Fapp\u002FControllers\u002FAjax\u002FAjaxCFG.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fclassified-listing\u002F5.3.8\u002Fapp\u002FControllers\u002FAjax\u002FAjaxCFG.php\t2026-03-17 08:37:52.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fclassified-listing\u002F5.3.9\u002Fapp\u002FControllers\u002FAjax\u002FAjaxCFG.php\t2026-04-20 09:33:34.000000000 +0000\n@@ -18,8 +18,12 @@\n \tfunction edit_field_delete() {\n \t\t$data = null;\n \t\t$error = true;\n-\t\tif ( Functions::verify_nonce() ) {\n-\t\t\t$post_id = !empty( $_REQUEST['id'] ) ? $_REQUEST['id'] : 0;\n+\t\tif ( !Functions::verify_nonce() ) {\n+\t\t\t$msg = esc_html__( \"Session expired\", \"classified-listing\" );\n+\t\t} elseif ( !current_user_can( 'manage_rtcl_options' ) ) {\n+\t\t\t$msg = esc_html__( \"You do not have permission to delete custom fields.\", \"classified-listing\" );\n+\t\t} else {\n+\t\t\t$post_id = !empty( $_REQUEST['id'] ) ? absint( $_REQUEST['id'] ) : 0;\n \t\t\tif ( $post_id && ( $post = get_post( $post_id ) ) && $post->post_type === rtcl()->post_type_cf ) {\n \t\t\t\t$p = wp_delete_post( $post_id, true );\n \t\t\t\tif ( $p ) {\n@@ -32,8 +36,6 @@\n \t\t\t\t$data = $_REQUEST;\n \t\t\t\t$msg = esc_html__( \"Field was not selected\", \"classified-listing\" );\n \t\t\t}\n-\t\t} else {\n-\t\t\t$msg = esc_html__( \"Session expired\", \"classified-listing\" );\n \t\t}\n \t\twp_send_json( [\n \t\t\t'data'  => $data,\n@@ -43,6 +45,14 @@\n \t}\n \n \tfunction edit_field_choose() {\n+\t\tif ( !Functions::verify_nonce() ) {\n+\t\t\tesc_html_e( \"Session expired\", \"classified-listing\" );\n+\t\t\tdie();\n+\t\t}\n+\t\tif ( !current_user_can( 'manage_rtcl_options' ) ) {\n+\t\t\tesc_html_e( \"You do not have permission to view custom fields.\", \"classified-listing\" );\n+\t\t\tdie();\n+\t\t}\n \t\t$html = null;\n \t\t$fields = Options::get_custom_field_list();\n \t\t$html .= \"\u003Cp>\" . esc_html__( \"You can choose from the available fields:\", \"classified-listing\" ) . \"\u003C\u002Fp>\";\n@@ -58,8 +68,12 @@\n \t\t$data = null;\n \t\t$error = true;\n \t\t$type = !empty( $_REQUEST['type'] ) && array_key_exists( $_REQUEST['type'], Options::get_custom_field_list() ) ? esc_attr( $_REQUEST['type'] ) : 'text';\n-\t\tif ( Functions::verify_nonce() ) {\n-\t\t\t$parent_id = !empty( $_REQUEST['id'] ) ? $_REQUEST['id'] : 0;\n+\t\tif ( !Functions::verify_nonce() ) {\n+\t\t\t$msg = esc_html__( \"Session expired\", \"classified-listing\" );\n+\t\t} elseif ( !current_user_can( 'manage_rtcl_options' ) ) {\n+\t\t\t$msg = esc_html__( \"You do not have permission to insert custom fields.\", \"classified-listing\" );\n+\t\t} else {\n+\t\t\t$parent_id = !empty( $_REQUEST['id'] ) ? absint( $_REQUEST['id'] ) : 0;\n \t\t\tif ( $type && $parent_id ) {\n \t\t\t\t$field_id = wp_insert_post( [\n \t\t\t\t\t\t'post_status' => 'draft',\n@@ -76,8 +90,6 @@\n \t\t\t\t$data = $_REQUEST;\n \t\t\t\t$msg = esc_html__( \"Select a field type\", \"classified-listing\" );\n \t\t\t}\n-\t\t} else {\n-\t\t\t$msg = esc_html__( \"Session expired\", \"classified-listing\" );\n \t\t}","The exploit involves sending crafted AJAX requests to the `wp-admin\u002Fadmin-ajax.php` endpoint. For configuration and filter tampering, an attacker identifies administrative actions such as `rtcl_edit_field_insert` or `rtcl_admin_settings_filter_update_name`. If a valid nonce can be obtained (often exposed on the frontend for specific features), the attacker can invoke these functions to modify settings or delete fields because the backend fails to call `current_user_can`. For file uploads, an attacker can use the `rtcl_fb_gallery_image_upload` action, providing a `listingId` that belongs to another user. Because the plugin does not verify if the current user has the `edit_rtcl_listing` capability for that specific listing ID, the file is successfully attached to the victim's listing.","gemini-3-flash-preview","2026-05-04 17:59:31","2026-05-04 18:00:20",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","5.3.8","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fclassified-listing\u002Ftags\u002F5.3.8","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fclassified-listing.5.3.8.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fclassified-listing\u002Ftags\u002F5.3.9","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fclassified-listing.5.3.9.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fclassified-listing\u002Ftags"]