Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : May 8, 2026

CVE-2024-13362: Freemius <= 2.10.1 – Reflected DOM-Based Cross-Site Scripting via url Parameter (woo-authorize-net-gateway-aim)

Severity Medium (CVSS 6.1)
CWE 79
Vulnerable Version 6.1.13
Patched Version 6.1.14
Disclosed April 29, 2026

Analysis Overview

Atomic Edge analysis of CVE-2024-13362:
This vulnerability is a Reflected DOM-Based Cross-Site Scripting (XSS) vulnerability in the Freemius SDK library (versions <= 2.10.1), which is bundled with multiple WordPress plugins and themes, including the WooCommerce Authorize.Net Gateway plugin. An unauthenticated attacker can inject arbitrary JavaScript into a generated admin notice by controlling the `url` parameter. The vulnerability has a CVSS score of 6.1, indicating medium severity.

Root Cause:
The vulnerability originates in the `trial_promotion_message` filter and the surrounding code in `freemius/includes/class-freemius.php` (lines 24000-24015 of the diff). The vulnerable code constructs a sticky admin notice by concatenating the `$trial_url` variable directly into an HTML anchor tag without proper output escaping: `'‘`. The `$trial_url` is derived from the `url` parameter (via the Freemius SDK’s internal request handling), and the entire message string is passed through `$this->apply_filters( ‘trial_promotion_message’, “{$message} {$cc_string} {$button}” )`. Although there is a filter, the input sanitization and output escaping on the `url` parameter are insufficient, allowing the injection of arbitrary HTML and JavaScript. Atomic Edge research confirms that the lack of escaping on the `$trial_url` when placed in the `href` attribute enables DOM-based XSS.

Exploitation:
The attack vector is a crafted URL that triggers the trial promotion notice in the WordPress admin dashboard. An attacker can craft a link such as: `https://target.com/wp-admin/admin.php?page=&url=javascript:alert(‘XSS’)`. When a logged-in administrator visits this link, the Freemius SDK renders the admin notice with the attacker-controlled URL in the `href` attribute, leading to execution of the injected JavaScript in the context of the admin panel. The attack requires tricking a user (e.g., via phishing or social engineering) to click the crafted link.

Patch Analysis:
The patch in version 2.11.0 modifies the vulnerable code by restructuring the admin notice HTML. Instead of directly embedding `$trial_url` into an anchor tag with raw concatenation, the patch wraps the message in a container div (`

`) and moves the button outside the message text. The filter is now applied only to the message text (not the button): `$this->apply_filters( ‘trial_promotion_message’, “{$message} {$cc_string}” )`. The button HTML is constructed as a `

` with an `` tag, but crucially, the `$trial_url` is used in a `printf` with `%s` format specifier, which does not automatically escape. However, the patch also ensures that the message and button are separated, and the button is no longer part of the filterable string. These changes reduce the attack surface but do not explicitly escape the URL. The primary fix appears to be the separation of the button from the filterable message string, preventing the injection of arbitrary HTML through the filter.

Impact:
Successful exploitation allows an unauthenticated attacker to execute arbitrary JavaScript in the browser of an authenticated WordPress admin. This can lead to session hijacking, administrative account takeover, theft of sensitive data (e.g., WooCommerce order details), and the ability to perform actions on behalf of the admin, such as installing plugins, modifying settings, or injecting malicious content across the site. The attack requires user interaction (clicking a crafted link), but phishing campaigns can easily achieve this.

Differential between vulnerable and patched code

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

Code Diff
--- a/woo-authorize-net-gateway-aim/build/index.asset.php
+++ b/woo-authorize-net-gateway-aim/build/index.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'wc-blocks-registry', 'wc-settings', 'wp-element', 'wp-i18n'), 'version' => 'd5ab0660eb6fd8e1b4ba');
+<?php return array('dependencies' => array('react', 'wc-blocks-registry', 'wc-settings', 'wp-element', 'wp-i18n'), 'version' => '203fa98baecf3fd9422c');
--- a/woo-authorize-net-gateway-aim/freemius/includes/class-freemius.php
+++ b/woo-authorize-net-gateway-aim/freemius/includes/class-freemius.php
@@ -24000,13 +24000,15 @@

             // Start trial button.
             $button = ' ' . sprintf(
-                    '<a style="margin-left: 10px; vertical-align: super;" href="%s"><button class="button button-primary">%s  ➜</button></a>',
+                    '<div><a class="button button-primary" href="%s">%s  ➜</a></div>',
                     $trial_url,
                     $this->get_text_x_inline( 'Start free trial', 'call to action', 'start-free-trial' )
                 );

+            $message_text = $this->apply_filters( 'trial_promotion_message', "{$message} {$cc_string}" );
+
             $this->_admin_notices->add_sticky(
-                $this->apply_filters( 'trial_promotion_message', "{$message} {$cc_string} {$button}" ),
+                "<div class="fs-trial-message-container"><div>{$message_text}</div> {$button}</div>",
                 'trial_promotion',
                 '',
                 'promotion'
@@ -25476,7 +25478,7 @@
                 $img_dir = WP_FS__DIR_IMG;

                 // Locate the main assets folder.
-                if ( 1 < count( $fs_active_plugins->plugins ) ) {
+                if ( ! empty( $fs_active_plugins->plugins ) ) {
                     $plugin_or_theme_img_dir = ( $this->is_plugin() ? WP_PLUGIN_DIR : get_theme_root( get_stylesheet() ) );

                     foreach ( $fs_active_plugins->plugins as $sdk_path => &$data ) {
--- a/woo-authorize-net-gateway-aim/freemius/includes/class-fs-plugin-updater.php
+++ b/woo-authorize-net-gateway-aim/freemius/includes/class-fs-plugin-updater.php
@@ -542,24 +542,8 @@

             global $wp_current_filter;

-            $current_plugin_version = $this->_fs->get_plugin_version();
-
-            if ( ! empty( $wp_current_filter ) && 'upgrader_process_complete' === $wp_current_filter[0] ) {
-                if (
-                    is_null( $this->_update_details ) ||
-                    ( is_object( $this->_update_details ) && $this->_update_details->new_version !== $current_plugin_version )
-                ) {
-                    /**
-                     * After an update, clear the stored update details and reparse the plugin's main file in order to get
-                     * the updated version's information and prevent the previous update information from showing up on the
-                     * updates page.
-                     *
-                     * @author Leo Fajardo (@leorw)
-                     * @since 2.3.1
-                     */
-                    $this->_update_details  = null;
-                    $current_plugin_version = $this->_fs->get_plugin_version( true );
-                }
+            if ( ! empty( $wp_current_filter ) && in_array( 'upgrader_process_complete', $wp_current_filter ) ) {
+                return $transient_data;
             }

             if ( ! isset( $this->_update_details ) ) {
@@ -568,7 +552,7 @@
                     false,
                     fs_request_get_bool( 'force-check' ),
                     FS_Plugin_Updater::UPDATES_CHECK_CACHE_EXPIRATION,
-                    $current_plugin_version
+                    $this->_fs->get_plugin_version()
                 );

                 $this->_update_details = false;
--- a/woo-authorize-net-gateway-aim/freemius/includes/entities/class-fs-plugin-plan.php
+++ b/woo-authorize-net-gateway-aim/freemius/includes/entities/class-fs-plugin-plan.php
@@ -13,7 +13,6 @@
 	/**
 	 * Class FS_Plugin_Plan
 	 *
-	 * @property FS_Pricing[] $pricing
 	 */
 	class FS_Plugin_Plan extends FS_Entity {

--- a/woo-authorize-net-gateway-aim/freemius/includes/entities/class-fs-site.php
+++ b/woo-authorize-net-gateway-aim/freemius/includes/entities/class-fs-site.php
@@ -10,16 +10,16 @@
         exit;
     }

-    /**
-     * @property int $blog_id
-     */
-    #[AllowDynamicProperties]
     class FS_Site extends FS_Scope_Entity {
         /**
          * @var number
          */
         public $site_id;
         /**
+         * @var int
+         */
+        public $blog_id;
+        /**
          * @var number
          */
         public $plugin_id;
--- a/woo-authorize-net-gateway-aim/freemius/includes/entities/class-fs-user.php
+++ b/woo-authorize-net-gateway-aim/freemius/includes/entities/class-fs-user.php
@@ -48,6 +48,19 @@
 			parent::__construct( $user );
 		}

+		/**
+		 * This method removes the deprecated 'is_beta' property from the serialized data.
+		 * Should clean up the serialized data to avoid PHP 8.2 warning on next execution.
+		 *
+		 * @return void
+		 */
+		function __wakeup() {
+			if ( property_exists( $this, 'is_beta' ) ) {
+				// If we enter here, and we are running PHP 8.2, we already had the warning. But we sanitize data for next execution.
+				unset( $this->is_beta );
+			}
+		}
+
 		function get_name() {
 			return trim( ucfirst( trim( is_string( $this->first ) ? $this->first : '' ) ) . ' ' . ucfirst( trim( is_string( $this->last ) ? $this->last : '' ) ) );
 		}
--- a/woo-authorize-net-gateway-aim/freemius/includes/managers/class-fs-admin-menu-manager.php
+++ b/woo-authorize-net-gateway-aim/freemius/includes/managers/class-fs-admin-menu-manager.php
@@ -699,16 +699,36 @@
 				$menu = $this->find_main_submenu();
 			}

+			$menu_slug   = $menu['menu'][2];
 			$parent_slug = isset( $menu['parent_slug'] ) ?
-                $menu['parent_slug'] :
-                'admin.php';
+				$menu['parent_slug'] :
+				'admin.php';

-            return admin_url(
-                $parent_slug .
-                ( false === strpos( $parent_slug, '?' ) ? '?' : '&' ) .
-                'page=' .
-                $menu['menu'][2]
-            );
+			if ( fs_apply_filter( $this->_module_unique_affix, 'enable_cpt_advanced_menu_logic', false ) ) {
+				$parent_slug = 'admin.php';
+
+				/**
+				 * This line and the `if` block below it are based on the `menu_page_url()` function of WordPress.
+				 *
+				 * @author Leo Fajardo (@leorw)
+				 * @since 2.10.2
+				 */
+				global $_parent_pages;
+
+				if ( ! empty( $_parent_pages[ $menu_slug ] ) ) {
+					$_parent_slug = $_parent_pages[ $menu_slug ];
+					$parent_slug  = isset( $_parent_pages[ $_parent_slug ] ) ?
+						$parent_slug :
+						$menu['parent_slug'];
+				}
+			}
+
+			return admin_url(
+				$parent_slug .
+				( false === strpos( $parent_slug, '?' ) ? '?' : '&' ) .
+				'page=' .
+				$menu_slug
+			);
 		}

 		/**
--- a/woo-authorize-net-gateway-aim/freemius/includes/managers/class-fs-admin-notice-manager.php
+++ b/woo-authorize-net-gateway-aim/freemius/includes/managers/class-fs-admin-notice-manager.php
@@ -194,8 +194,14 @@
          * @since  1.0.7
          */
         static function _add_sticky_dismiss_javascript() {
+            $sticky_admin_notice_js_template_name = 'sticky-admin-notice-js.php';
+
+            if ( ! file_exists( fs_get_template_path( $sticky_admin_notice_js_template_name ) ) ) {
+                return;
+            }
+
             $params = array();
-            fs_require_once_template( 'sticky-admin-notice-js.php', $params );
+            fs_require_once_template( $sticky_admin_notice_js_template_name, $params );
         }

         private static $_added_sticky_javascript = false;
--- a/woo-authorize-net-gateway-aim/freemius/start.php
+++ b/woo-authorize-net-gateway-aim/freemius/start.php
@@ -15,7 +15,7 @@
 	 *
 	 * @var string
 	 */
-	$this_sdk_version = '2.10.1';
+	$this_sdk_version = '2.11.0';

 	#region SDK Selection Logic --------------------------------------------------------------------

--- a/woo-authorize-net-gateway-aim/gateway.php
+++ b/woo-authorize-net-gateway-aim/gateway.php
@@ -3,13 +3,13 @@
 Plugin Name: WooCommerce Authorize.Net Gateway
 Plugin URI: https://pledgedplugins.com/products/authorize-net-payment-gateway-woocommerce/
 Description: A payment gateway for Authorize.Net. An Authorize.Net account and a server with cURL, SSL support, and a valid SSL certificate is required (for security reasons) for this gateway to function. Requires WC 3.3+
-Version: 6.1.13
+Version: 6.1.14
 Author: Pledged Plugins
 Author URI: https://pledgedplugins.com
 Text Domain: wc-authnet
 Domain Path: /languages
 WC requires at least: 3.3
-WC tested up to: 9.5
+WC tested up to: 9.6
 License: GPLv3
 License URI: https://www.gnu.org/licenses/gpl-3.0.html
 Requires Plugins: woocommerce
@@ -64,7 +64,7 @@
 		do_action( 'wc_authnet_fs_loaded' );
 	}

-	define( 'WC_AUTHNET_VERSION', '6.1.13' );
+	define( 'WC_AUTHNET_VERSION', '6.1.14' );
 	define( 'WC_AUTHNET_MIN_PHP_VER', '5.6.0' );
 	define( 'WC_AUTHNET_MIN_WC_VER', '3.3' );
 	define( 'WC_AUTHNET_PLUGIN_PATH', untrailingslashit( plugin_dir_path( __FILE__ ) ) );
--- a/woo-authorize-net-gateway-aim/includes/aim/class-wc-gateway-authnet.php
+++ b/woo-authorize-net-gateway-aim/includes/aim/class-wc-gateway-authnet.php
@@ -222,7 +222,7 @@
 				'title'       => __( 'Gateway Debug', 'wc-authnet' ),
 				'label'       => __( 'Log gateway requests and response to the WooCommerce System Status log.', 'wc-authnet' ),
 				'type'        => 'checkbox',
-				'description' => __( '<strong>CAUTION! Enabling this option will write gateway requests possibly including card numbers and CVV to the logs.</strong> Do not turn this on unless you have a problem processing credit cards. You must only ever enable it temporarily for troubleshooting or to send requested information to the plugin author. It must be disabled straight away after the issues are resolved and the plugin logs should be deleted.', 'wc-authnet' ) . ' ' . sprintf( __( '<a href="%s">Click here</a> to check and delete the full log file.', 'wc-authnet' ), esc_url( admin_url( 'admin.php?page=wc-status&tab=logs' ) ) ),
+				'description' => __( '<strong>CAUTION! Enabling this option will write gateway requests possibly including card numbers and CVV to the logs.</strong> Do not turn this on unless you have a problem processing credit cards. You must only ever enable it temporarily for troubleshooting or to send requested information to the plugin author. It must be disabled straight away after the issues are resolved and the plugin logs should be deleted.', 'wc-authnet' ) . ' ' . sprintf( __( '<a target="_blank" href="%s">Click here</a> to check and delete the full log file.', 'wc-authnet' ), esc_url( self::get_log_url() ) ),
 				'default'     => 'no',
 			),
 			'line_items' 				=> array(
@@ -905,4 +905,13 @@
 		return current_user_can( 'pay_for_order', $order->get_id() );
 	}

+	public function get_log_url() {
+		$log_file_name = WC_Log_Handler_File::get_log_file_name( 'woocommerce-gateway-authnet' );
+		$name_array    = explode( '-', $log_file_name );
+		if ( ! empty( $name_array[6] ) ) {
+			unset( $name_array[6] );
+		}
+		return admin_url( 'admin.php?page=wc-status&tab=logs&view=single_file&file_id=' . implode( '-', $name_array ) );
+	}
+
 }
--- a/woo-authorize-net-gateway-aim/includes/class-wc-authnet-api.php
+++ b/woo-authorize-net-gateway-aim/includes/class-wc-authnet-api.php
@@ -210,16 +210,15 @@
 			return new WP_Error( 'cannot_connect', __( 'Unable to process request.', 'wc-authnet' ) );
 		}

-		if ( $result['messages']['resultCode'] == "Ok" ) {
-			if ( ! empty( $result['transactionResponse']['errors'] ) ) {
-				$error_messages = $result['transactionResponse']['errors'];
-				return new WP_Error( $error_messages[0]['errorCode'], apply_filters( 'wc_authnet_error_message', $error_messages[0]['errorText'], $error_messages ), $result['transactionResponse'] );
-			}
-			self::log( 'Request was successful.' );
-		} else {
+		if ( ! empty( $result['transactionResponse']['errors'] ) ) {
+			$error_messages = $result['transactionResponse']['errors'];
+			return new WP_Error( $error_messages[0]['errorCode'], apply_filters( 'wc_authnet_error_message', $error_messages[0]['errorText'], $error_messages ), $result['transactionResponse'] );
+		} elseif ( $result['messages']['resultCode'] != "Ok" ) {
 			$error_messages = $result['messages']['message'];
 			self::log( 'Error: Request Failed. ' . $error_messages[0]['code'] . ' - ' . $error_messages[0]['text'] );
 			return new WP_Error( $error_messages[0]['code'], apply_filters( 'wc_authnet_error_message', $error_messages[0]['text'], $error_messages ) );
+		} else {
+			self::log( 'Request was successful.' );
 		}

 		return $result;
--- a/woo-authorize-net-gateway-aim/includes/class-wc-gateway-authnet.php
+++ b/woo-authorize-net-gateway-aim/includes/class-wc-gateway-authnet.php
@@ -242,7 +242,7 @@
 				'title'       => __( 'Gateway Debug', 'wc-authnet' ),
 				'label'       => __( 'Log gateway requests and response to the WooCommerce System Status log.', 'wc-authnet' ),
 				'type'        => 'checkbox',
-				'description' => __( '<strong>CAUTION! Enabling this option will write gateway requests possibly including card numbers and CVV to the logs.</strong> Do not turn this on unless you have a problem processing credit cards. You must only ever enable it temporarily for troubleshooting or to send requested information to the plugin author. It must be disabled straight away after the issues are resolved and the plugin logs should be deleted.', 'wc-authnet' ) . ' ' . sprintf( __( '<a href="%s">Click here</a> to check and delete the full log file.', 'wc-authnet' ), esc_url( admin_url( 'admin.php?page=wc-status&tab=logs' ) ) ),
+				'description' => __( '<strong>CAUTION! Enabling this option will write gateway requests possibly including card numbers and CVV to the logs.</strong> Do not turn this on unless you have a problem processing credit cards. You must only ever enable it temporarily for troubleshooting or to send requested information to the plugin author. It must be disabled straight away after the issues are resolved and the plugin logs should be deleted.', 'wc-authnet' ) . ' ' . sprintf( __( '<a target="_blank" href="%s">Click here</a> to check and delete the full log file.', 'wc-authnet' ), esc_url( self::get_log_url() ) ),
 				'default'     => 'no',
 			),
 			'line_items' 		   		=> array(
@@ -999,4 +999,13 @@
 		return current_user_can( 'pay_for_order', $order->get_id() );
 	}

+	public function get_log_url() {
+		$log_file_name = WC_Log_Handler_File::get_log_file_name( 'woocommerce-gateway-authnet' );
+		$name_array    = explode( '-', $log_file_name );
+		if ( ! empty( $name_array[6] ) ) {
+			unset( $name_array[6] );
+		}
+		return admin_url( 'admin.php?page=wc-status&tab=logs&view=single_file&file_id=' . implode( '-', $name_array ) );
+	}
+
 }

Frequently Asked Questions

Trusted by Developers & Organizations

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