CVE-2025-64248

Request a Quote <= 2.5.3 - Missing Authorization

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
2.5.4
Patched in
5d
Time to patch

Description

The Request a Quote Form Plugin – Price Quote Request Management Made Easy plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 2.5.3. This makes it possible for authenticated attackers, with Subscriber-level access and above, to perform an unauthorized action.

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<=2.5.3
PublishedDecember 15, 2025
Last updatedDecember 19, 2025
Affected pluginrequest-a-quote

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2025-64248 ## 1. Vulnerability Summary The **Request a Quote Form Plugin** (versions <= 2.5.3) is vulnerable to **Missing Authorization**. While the plugin correctly implements CSRF protection via nonces in its AJAX handlers, it fails to perform a capability check…

Show full research plan

Exploitation Research Plan - CVE-2025-64248

1. Vulnerability Summary

The Request a Quote Form Plugin (versions <= 2.5.3) is vulnerable to Missing Authorization. While the plugin correctly implements CSRF protection via nonces in its AJAX handlers, it fails to perform a capability check (e.g., current_user_can( 'manage_options' )) to ensure the request is originating from an authorized administrator. This allows any authenticated user (starting from the Subscriber role) to perform administrative actions, specifically deleting quote requests.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: raq_delete_quote (inferred from plugin naming convention and standard AJAX registration)
  • Parameters:
    • action: raq_delete_quote
    • security: A valid nonce (action: raq_nonce)
    • id: The ID of the quote request to delete
  • Authentication: Required (Subscriber role or higher).
  • Preconditions: At least one quote request must exist in the system to be deleted.

3. Code Flow

  1. Entry Point: The plugin registers AJAX actions in its admin class (likely includes/admin/class-request-quote-admin.php or admin/class-request-a-quote-admin.php).
  2. Hook Registration:
    add_action( 'wp_ajax_raq_delete_quote', array( $this, 'raq_delete_quote_callback' ) );
    
  3. Vulnerable Function: The callback function (e.g., raq_delete_quote_callback) is invoked.
  4. Nonce Verification: The function calls check_ajax_referer( 'raq_nonce', 'security' ). This passes if the user is logged in and provides a valid nonce.
  5. Missing Check: The function proceeds to perform database operations (e.g., $wpdb->delete) without checking if the current user has the manage_options capability.
  6. Sink: The quote record corresponding to the provided id is deleted from the database.

4. Nonce Acquisition Strategy

The plugin uses wp_localize_script to pass the nonce to the admin dashboard. Even if a Subscriber cannot access the plugin's settings page, the script is often enqueued for all admin pages or the dashboard.

  1. Shortcode/Page Requirement: The plugin handles quote submissions via a frontend shortcode (e.g., [request_a_quote]). However, the deletion nonce is intended for the admin side.
  2. Detection: Check if the script is enqueued on wp-admin/index.php for a Subscriber.
  3. Execution Agent Steps:
    • Log in as a Subscriber.
    • Navigate to /wp-admin/index.php.
    • Use browser_eval to extract the nonce:
      window.raq_ajax_obj?.raq_nonce || window.raq_data?.nonce
      
    • (Alternative) Search the page source for raq_nonce.

5. Exploitation Strategy

Step 1: Create Test Data

As an unauthenticated user (or via the admin if easier for setup), submit a quote request to ensure the database is populated.

Step 2: Login as Subscriber

Use the http_request tool to authenticate as a Subscriber user.

Step 3: Obtain Nonce and ID

Navigate to the WordPress dashboard as the Subscriber and extract the security token (nonce) and identify a target quote ID.

Step 4: Execute Deletion

Perform an unauthenticated-authorized POST request to admin-ajax.php.

Request Details:

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Content-Type: application/x-www-form-urlencoded
  • Body: action=raq_delete_quote&security=[NONCE]&id=[QUOTE_ID]

6. Test Data Setup

  1. Create Administrator: Ensure an admin user exists.
  2. Create Subscriber: Create a user with the subscriber role.
  3. Plugin Setup: Activate the plugin.
  4. Create Quote:
    • Create a page with the shortcode [request-a-quote-form] (verify exact shortcode via grep -r "add_shortcode" .).
    • Visit the page and submit a test quote request.
  5. Identify ID: Use wp db query "SELECT id FROM wp_raq_quotes LIMIT 1;" to find the ID of the quote to delete.

7. Expected Results

  • Response: The AJAX handler should return a success status (e.g., 1 or a JSON {"success":true}).
  • Database State: The row in the quote table (likely wp_raq_quotes or similar) associated with the id should be removed.
  • Unauthorized Bypass: The action succeeds despite the user being a Subscriber, whereas it should require Admin permissions.

8. Verification Steps

  1. Check Database:
    wp db query "SELECT COUNT(*) FROM wp_raq_quotes WHERE id = [ID];"
    
    If the count is 0, the exploit was successful.
  2. Verify Role: Confirm the user used for the request has only the subscriber role:
    wp user get [USER_ID] --field=roles
    

9. Alternative Approaches

  • Bulk Delete: Check for a bulk delete action (e.g., raq_bulk_delete) which might also lack authorization checks.
  • Quote Status Update: If deletion is not possible, check for an action like raq_update_status that allows a Subscriber to change quote statuses (e.g., marking a quote as "Approved").
  • Parameter Fuzzing: If the ID is not easily guessable, the agent should attempt to iterate through small integers if the response differs between "ID not found" and "Success".

Check if your site is affected.

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