[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fL6DRmjI4T-Ywgy-GEd9ab12LFxORBjC6tXfBhAkbndg":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":24,"research_verified":25,"research_rounds_completed":26,"research_plan":27,"research_summary":28,"research_vulnerable_code":29,"research_fix_diff":30,"research_exploit_outline":31,"research_model_used":32,"research_started_at":33,"research_completed_at":34,"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":25,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":25,"source_links":35},"CVE-2026-42744","quads-ads-manager-for-google-adsense-missing-authorization","Quads Ads Manager for Google AdSense \u003C= 3.0.2 - Missing Authorization","The Quads Ads Manager for Google AdSense plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 3.0.2. This makes it possible for unauthenticated attackers to perform an unauthorized action.","quick-adsense-reloaded",null,"\u003C=3.0.2","3.0.3","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-05-28 00:00:00","2026-06-02 11:26:26",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Fdb5dced6-4dd4-4a9e-946b-52471fbb6251?source=api-prod",5,[22,23],"changelog.txt","includes\u002Fad-selling-helper.php","researched",false,3,"# Exploitation Research Plan: CVE-2026-42744 (Quads Ads Manager)\n\n## 1. Vulnerability Summary\nThe **Quads Ads Manager for Google AdSense** plugin (up to version 3.0.2) is vulnerable to **Missing Authorization**. The function `quads_authorize_payment_success` in `includes\u002Fad-selling-helper.php` is hooked to WordPress `init`. While it performs a check to ensure a user is logged in (`is_user_logged_in()`), it fails to verify if the user has administrative privileges or if the user is the owner of the specific advertisement order being processed. This allows any authenticated user (e.g., a Subscriber) to trigger the payment confirmation logic, marking advertisement slots as \"paid\" in the database without an actual transaction.\n\n## 2. Attack Vector Analysis\n- **Endpoint**: Any frontend or backend page (since the function is hooked to `init`).\n- **Method**: `GET`\n- **Action Hook**: `add_action( 'init', 'quads_authorize_payment_success' );`\n- **Required Parameters**:\n    - `security`: A valid WordPress nonce for the action `'security'`.\n    - `status`: Must be set to `success`.\n    - `ad_slot_id`: The ID of the ad slot (must be `> 0`).\n    - `refId`: A non-empty reference string (likely corresponds to the order ID based on the code's usage of `$order_id`).\n    - `user_id`: The ID of the user whose ad is being marked as paid.\n- **Authentication**: Authenticated user (Subscriber or higher).\n\n## 3. Code Flow\n1. **Entry**: WordPress initializes and triggers the `init` hook.\n2. **Trigger**: `quads_authorize_payment_success()` is called.\n3. **Auth Check**: `is_user_logged_in()` passes if the attacker is logged in as a Subscriber.\n4. **Nonce Check**: `wp_verify_nonce( $_GET['security'], 'security' )` validates the token.\n5. **Logic**:\n    - The code attempts to retrieve the user via `get_user_by( 'id', $user_id )`.\n    - It queries the `quads_adbuy_data` table for the order details.\n    - **Vulnerability Sink**: It calls `$wpdb->update()` on the `quads_adbuy_data` table, setting `payment_status` to `'paid'`.\n    - **Side Effect**: Sends a confirmation email to both the user and the administrator via `wp_mail()`.\n\n*Note: In the provided source snippet, `$order_id` is used but not explicitly initialized from `$_GET`. It is likely that `$order_id` is mapped to `$_GET['refId']` or assigned elsewhere in the full file.*\n\n## 4. Nonce Acquisition Strategy\nThe nonce action string is `'security'`. To obtain this nonce as a Subscriber:\n1. **Identify the Source**: The `quads_create_sellpage_on_activation()` function indicates that a page with the shortcode `[quads_buy_form]` is created (usually at the slug `\u002Fbuy-adspace`).\n2. **Setup**: If the page doesn't exist, create it:\n   `wp post create --post_type=page --post_title=\"Buy Ads\" --post_status=publish --post_content='[quads_buy_form]'`\n3. **Extraction**:\n   - Log in as a Subscriber user.\n   - Navigate to the page containing the `[quads_buy_form]`.\n   - Use `browser_eval` to search for the nonce. It may be in a hidden field or a localized JS variable.\n   - **Search Pattern**: Look for `wp_create_nonce( 'security' )` in the plugin source to find the exact JS localization key. If found in a form:\n     `browser_eval(\"document.querySelector('input[name=\\\"security\\\"]').value\")`\n\n## 5. Exploitation Strategy\n1. **Login**: Authenticate as a Subscriber user.\n2. **Capture Nonce**: Visit the ad purchase page and extract the `'security'` nonce.\n3. **Identify Target**: Determine a valid `ad_slot_id` and the database ID of an unpaid ad purchase (`refId`\u002F`order_id`).\n4. **Execute Attack**: Send a GET request to the site root with the forged parameters.\n   \n   **Request Example**:\n   ```http\n   GET \u002F?status=success&ad_slot_id=1&refId=1&user_id=2&security=abc123def4 HTTP\u002F1.1\n   Host: target.local\n   Cookie: [Subscriber Cookies]\n   ```\n\n## 6. Test Data Setup\n1. **Enable Feature**: Ensure the \"Sellable Ads\" feature is active.\n2. **Create Order**: Create an advertisement order in the database for the Subscriber user (ID 2).\n   - Use WP-CLI to insert a record into the `{wpdb->prefix}quads_adbuy_data` table with `payment_status = 'pending'`.\n3. **Find Slot**: Ensure an ad slot exists (Post Type `quads_ad_slot` or similar, depending on plugin structure).\n\n## 7. Expected Results\n- The plugin identifies the request as a successful payment.\n- The database record in `wp_quads_adbuy_data` for the given `refId` is updated: `payment_status` changes from `pending` to `paid`.\n- An email is triggered to the admin and the user confirming the payment.\n- The HTTP response may be a redirect or a success message, but the primary indicator is the database state.\n\n## 8. Verification Steps\n1. **Database Check**: After the HTTP request, verify the payment status via WP-CLI:\n   `wp db query \"SELECT payment_status FROM wp_quads_adbuy_data WHERE id = 1\"`\n   Expected output: `paid`.\n2. **Log Check**: Check the WordPress mail log (if a logger is installed) to see if the \"Ad Payment Confirmation\" email was sent.\n\n## 9. Alternative Approaches\n- **Parameter Mapping**: If `refId` does not map to the database `id`, check if the plugin uses `$_GET['order_id']` (common in such plugins).\n- **Unauthenticated Check**: Verify if the `is_user_logged_in()` check is truly enforced in all versions. If missing, the attack becomes CVSS 9.8 (Critical).\n- **CSRF**: Since the action uses GET and requires a nonce, if the nonce is obtainable by an attacker but the `is_user_logged_in()` check is strict, the vulnerability could be leveraged as a CSRF against an Admin if they click a malicious link.","The Quads Ads Manager for Google AdSense plugin is vulnerable to unauthorized access because the `quads_authorize_payment_success` function, hooked to the WordPress `init` action, lacks proper capability and ownership checks. This allows any authenticated user (such as a Subscriber) to mark an advertisement order as 'paid' in the database without completing a transaction.","\u002F\u002F includes\u002Fad-selling-helper.php line 52\nadd_action( 'init', 'quads_authorize_payment_success' );\nfunction quads_authorize_payment_success(){\n    \n    if ( !is_user_logged_in() ) {\n        return false;\n    }\n    if( !isset( $_GET[ 'security' ] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET[ 'security' ] ) ), 'security' )){ \n        return false;\n    }\n    if( isset( $_GET['status'] ) && $_GET['status']=='success' && isset( $_GET['ad_slot_id'] ) && $_GET['ad_slot_id'] > 0 && isset( $_GET['refId'] ) && $_GET['refId'] != \"\" && isset( $_GET['user_id'] ) && intval( $_GET['user_id'] ) >0 && !isset( $_GET['target'] )){\n        \u002F\u002F ... logic continues to update database -- line 92\n        \u002F\u002F phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching\n        $wpdb->update(\n            $table_name,\n            array('payment_status' => 'paid' , 'payment_response'=> wp_json_encode($params)), \u002F\u002F Data to update\n            array('id' => $order_id , 'user_id'=>$user->ID) \n        );","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fquick-adsense-reloaded\u002F3.0.2\u002Fincludes\u002Fad-selling-helper.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fquick-adsense-reloaded\u002F3.0.3\u002Fincludes\u002Fad-selling-helper.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fquick-adsense-reloaded\u002F3.0.2\u002Fincludes\u002Fad-selling-helper.php\t2026-04-16 14:19:34.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fquick-adsense-reloaded\u002F3.0.3\u002Fincludes\u002Fad-selling-helper.php\t2026-05-08 12:37:54.000000000 +0000\n@@ -7,6 +7,52 @@\n if( !defined( 'ABSPATH' ) ) {\n     exit;\n }\n+\n+\u002F**\n+ * Merge query args onto a return URL that may already contain ?key=value (e.g. ad_slot_id on the storefront).\n+ *\n+ * @param string $base_url Absolute URL.\n+ * @param array  $args     Query parameters to merge.\n+ * @return string\n+ *\u002F\n+function quads_add_return_query_args( $base_url, array $args ) {\n+    $base_url = is_string( $base_url ) ? trim( $base_url ) : '';\n+    if ( '' === $base_url ) {\n+        return '';\n+    }\n+    return add_query_arg( $args, $base_url );\n+}\n+\n+\u002F**\n+ * Absolute URL for the current request path plus sanitized query string (e.g. pre-selected ad slot).\n+ *\n+ * @return string\n+ *\u002F\n+function quads_get_checkout_redirect_base_url() {\n+    global $wp;\n+    $redirect_link = isset( $wp->request ) ? home_url( $wp->request ) : home_url( '\u002F' );\n+    if ( isset( $_SERVER['QUERY_STRING'] ) && is_string( $_SERVER['QUERY_STRING'] ) && $_SERVER['QUERY_STRING'] !== '' ) {\n+        parse_str( wp_unslash( $_SERVER['QUERY_STRING'] ), $parsed_qs );\n+        if ( ! empty( $parsed_qs ) && is_array( $parsed_qs ) ) {\n+            $clean_qs = array();\n+            foreach ( $parsed_qs as $qs_key => $qs_val ) {\n+                $saf_key = sanitize_key( wp_unslash( (string) $qs_key ) );\n+                if ( '' === $saf_key ) {\n+                    continue;\n+                }\n+                if ( is_array( $qs_val ) ) {\n+                    continue;\n+                }\n+                $clean_qs[ $saf_key ] = sanitize_text_field( wp_unslash( (string) $qs_val ) );\n+            }\n+            if ( ! empty( $clean_qs ) ) {\n+                $redirect_link = add_query_arg( $clean_qs, $redirect_link );\n+            }\n+        }\n+    }\n+\n+    return $redirect_link;\n+}","To exploit this vulnerability, an attacker must first authenticate with a Subscriber account. They then navigate to the plugin's ad purchase page (typically `\u002Fbuy-adspace`) to extract a valid 'security' nonce generated for the user session. With this nonce, the attacker crafts a GET request to the site root containing parameters used by the payment gateway callback logic: 'status=success', 'security' (the nonce), 'ad_slot_id' (a valid ad slot ID), 'refId' (the target order ID from the database), and 'user_id' (the attacker's own user ID). When the request is processed, the plugin updates the 'payment_status' of the order to 'paid' in the 'quads_adbuy_data' table, effectively bypassing the actual payment requirement.","gemini-3-flash-preview","2026-06-04 16:31:02","2026-06-04 16:33:36",{"type":36,"vulnerable_version":37,"fixed_version":11,"vulnerable_browse":38,"vulnerable_zip":39,"fixed_browse":40,"fixed_zip":41,"all_tags":42},"plugin","3.0.2","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fquick-adsense-reloaded\u002Ftags\u002F3.0.2","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fquick-adsense-reloaded.3.0.2.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fquick-adsense-reloaded\u002Ftags\u002F3.0.3","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fquick-adsense-reloaded.3.0.3.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fquick-adsense-reloaded\u002Ftags"]