CVE-2026-54824

Quads Ads Manager for Google AdSense <= 3.0.3 - Unauthenticated Information Exposure

mediumExposure of Sensitive Information to an Unauthorized Actor
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
3.0.4
Patched in
9d
Time to patch

Description

The Quads Ads Manager for Google AdSense plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 3.0.3. This makes it possible for unauthenticated attackers to extract sensitive user or configuration data.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
Low
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=3.0.3
PublishedJune 17, 2026
Last updatedJune 25, 2026
Affected pluginquick-adsense-reloaded

What Changed in the Fix

Changes introduced in v3.0.4

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-54824 (Quads Ads Manager) ## 1. Vulnerability Summary The **Quads Ads Manager for Google AdSense** plugin (up to 3.0.3) contains a sensitive information exposure vulnerability within its unauthenticated AJAX handler `quads_submit_ad_buy_form`. A business-logic…

Show full research plan

Exploitation Research Plan: CVE-2026-54824 (Quads Ads Manager)

1. Vulnerability Summary

The Quads Ads Manager for Google AdSense plugin (up to 3.0.3) contains a sensitive information exposure vulnerability within its unauthenticated AJAX handler quads_submit_ad_buy_form. A business-logic flaw in this handler allows unauthenticated users to retrieve details of ad purchase orders from the database by providing an order ID. Exposed data includes buyer email addresses, user IDs, payment statuses, and configuration details stored in the quads_adbuy_data table.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • AJAX Action: quads_submit_ad_buy_form (Registered via wp_ajax_nopriv_quads_submit_ad_buy_form)
  • Vulnerable Parameter: order_id or id (to be verified in handler)
  • Authentication: None required (Unauthenticated)
  • Preconditions: At least one ad order must exist in the quads_adbuy_data table for data to be leaked.

3. Code Flow

  1. Entry Point: The plugin registers the AJAX action:
    add_action('wp_ajax_nopriv_quads_submit_ad_buy_form', 'quads_submit_ad_buy_form_handler') (Inferred registration name).
  2. Shortcode: The plugin uses the [quads_buy_form] shortcode (referenced in includes/ad-selling-helper.php) to render the purchase interface.
  3. Logic: The handler for quads_submit_ad_buy_form likely accepts an ID to "process" or "update" an order. Due to missing ownership checks, providing an existing ID causes the handler to fetch the record from the {$wpdb->prefix}quads_adbuy_data table and return it to the client (likely to populate the UI or confirm the order).
  4. Sink: The data is returned via wp_send_json_success() or echo json_encode().

4. Nonce Acquisition Strategy

The AJAX handler likely requires a nonce for validation, usually localized when the [quads_buy_form] shortcode is rendered.

  1. Identify the Page: The plugin automatically creates a page with the slug buy-adspace containing the [quads_buy_form] shortcode (see quads_create_sellpage_on_activation).
  2. Access the Page: Navigate to http://vulnerable-wp.local/buy-adspace/.
  3. Extract Nonce: The nonce is typically found in a localized JavaScript object.
    • Possible Variable Name: quads_ajax_object or quads_buy_form_vars.
    • Likely Key: nonce or security.
  4. Tool Command:
    // Use browser_eval to find the nonce
    browser_eval("window.quads_ajax_object?.nonce || window.quads_buy_form_vars?.security")
    

5. Exploitation Strategy

Step 1: Discover Order IDs

Ad order IDs are typically auto-incrementing integers. An attacker can iterate through small integers (1, 2, 3...) to find valid records.

Step 2: Perform the Leak

Submit a POST request to admin-ajax.php using the http_request tool.

Request Details:

  • URL: http://vulnerable-wp.local/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    action=quads_submit_ad_buy_form&order_id=1&security=[EXTRACTED_NONCE]
    
    (Note: If order_id doesn't work, try id or refId as seen in quads_authorize_payment_success).

Step 3: Parse Response

A successful exploit will return a JSON object containing database fields from the quads_adbuy_data table.

6. Test Data Setup

To verify the leak, we must ensure data exists to be leaked:

  1. Activate the Plugin: Ensure Quads Ads Manager <= 3.0.3 is active.
  2. Create a Sellable Ad Slot:
    wp post create --post_type=quads_ad_slot --post_title="Premium Banner" --post_status=publish
    # (Inferred post type, if different, find via wp post-type list)
    
  3. Simulate an Order: Manually insert a record into the custom table (if WP-CLI database access is available) or use the UI to start a purchase:
    wp db query "INSERT INTO wp_quads_adbuy_data (user_id, payment_status, start_date, end_date) VALUES (1, 'pending', '2026-01-01', '2026-01-31')"
    
  4. Check the Slug: Confirm the buy-adspace page exists:
    wp post list --name='buy-adspace' --post_type=page
    

7. Expected Results

The HTTP response should be a 200 OK with a JSON body similar to:

{
    "success": true,
    "data": {
        "id": "1",
        "user_id": "1",
        "payment_status": "pending",
        "start_date": "2026-01-01",
        "end_date": "2026-01-31",
        "ad_details": "...",
        "user_email": "admin@example.com"
    }
}

Exposure of user_email or payment_response (containing transaction details) confirms the vulnerability.

8. Verification Steps

  1. Verify via Database: Compare the leaked JSON data with the actual database entry:
    wp db query "SELECT * FROM wp_quads_adbuy_data WHERE id = 1" --format=json
    
  2. Confirm Non-Ownership: Ensure the exploit works when unauthenticated (no session cookies in the http_request tool).

9. Alternative Approaches

  • Parameter Fuzzing: If order_id is not the correct key, fuzz the AJAX handler with id, order, ad_id, or refId.
  • Shortcode Extraction: If the buy-adspace page is not auto-created, create one manually:
    wp post create --post_type=page --post_content='[quads_buy_form]' --post_status=publish
  • Error-Based Leak: If the response doesn't return the full object, try providing a malformed ID to see if the resulting SQL error or PHP warning leaks table names or configuration paths.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Quads Ads Manager plugin for WordPress is vulnerable to unauthenticated sensitive information exposure through its order-processing logic. A flaw in the `quads_submit_ad_buy_form` AJAX handler and related functions allows unauthenticated users to retrieve full ad purchase records, including buyer email addresses and payment statuses, by providing a valid order ID.

Vulnerable Code

// includes/ad-selling-helper.php @ 3.0.3
function quads_get_premimum_member_ad_space_on_id($id){
    global $wpdb;
    $table_name = $wpdb->prefix . 'quads_adbuy_data';
    $id         = absint( $id ); 

    $results = wp_cache_get( 'quads_ad_space_' . $id, 'quick-adsense-reloaded' );
    if ( false === $results ) {
        // Query the records - missing user_id check in the WHERE clause
        $results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $table_name WHERE payment_status = %s AND id = %d ORDER BY id DESC", 'paid', $id ) );
        wp_cache_set( 'quads_ad_space_' . $id, $results, 'quick-adsense-reloaded', 600 );
    }

---

// includes/ad-selling-helper.php @ 3.0.3
function quads_authorize_payment_success(){
    
    if ( !is_user_logged_in() ) {
        return false;
    }
    // Uses a weak generic 'security' nonce and lacks ownership validation
    if( !isset( $_GET[ 'security' ] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET[ 'security' ] ) ), 'security' )){ 
        return false;
    }
    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'] )){
        $slot_id = absint( $_GET['ad_slot_id'] );
        $order_id = absint($order_id);
        $user_id = absint($user_id);
        // ... process order using $user_id from GET param ...

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/quick-adsense-reloaded/3.0.3/includes/ad-selling-helper.php	2026-05-08 12:37:54.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/quick-adsense-reloaded/3.0.4/includes/ad-selling-helper.php	2026-06-12 13:56:34.000000000 +0000
@@ -1029,17 +1135,23 @@
     }
     return $results;
 } 
-function quads_get_premimum_member_ad_space_on_id($id){
+function quads_get_premimum_member_ad_space_on_id( $id, $user_id ) {
     global $wpdb;
     $table_name = $wpdb->prefix . 'quads_adbuy_data';
-    $id         = absint( $id ); 
+    $id         = absint( $id );
+    $user_id    = absint( $user_id );
 
-    $results = wp_cache_get( 'quads_ad_space_' . $id, 'quick-adsense-reloaded' );
+    if ( ! $id || ! $user_id ) {
+        return array();
+    }
+
+    $cache_key = 'quads_ad_space_' . $id . '_' . $user_id;
+    $results   = wp_cache_get( $cache_key, 'quick-adsense-reloaded' );
     if ( false === $results ) {
         // Query the records
         /* phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery,PluginCheck.Security.DirectDB.UnescapedDBParameter,WordPress.DB.PreparedSQL.NotPrepared */
-        $results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $table_name WHERE payment_status = %s AND id = %d ORDER BY id DESC", 'paid', $id ) );
-        wp_cache_set( 'quads_ad_space_' . $id, $results, 'quick-adsense-reloaded', 600 );
+        $results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $table_name WHERE payment_status = %s AND id = %d AND user_id = %d ORDER BY id DESC", 'paid', $id, $user_id ) );
+        wp_cache_set( $cache_key, $results, 'quick-adsense-reloaded', 600 );
     }

Exploit Outline

1. Navigate to the plugin's default storefront page at `/buy-adspace/` (or any page where the `[quads_buy_form]` shortcode is rendered) to retrieve a valid security nonce from the `quads_ajax_object` or `quads_buy_form_vars` JavaScript variables. 2. Construct an unauthenticated AJAX request to `/wp-admin/admin-ajax.php` using the action `quads_submit_ad_buy_form`. 3. Include the extracted nonce in the `security` or `nonce` parameter. 4. Iterate through integer values for the `order_id` or `id` parameter. 5. For each valid ID, the server will respond with a JSON object containing the order details from the `wp_quads_adbuy_data` table, exposing sensitive data such as `user_email`, `user_id`, and `payment_response` (transaction metadata).

Check if your site is affected.

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