Atomic Edge analysis of CVE-2026-42653:
This vulnerability is an unauthenticated stored cross-site scripting (XSS) in the Affiliate Program Suite — SliceWP Affiliates plugin for WordPress, versions up to and including 1.2.6. The flaw resides in the admin payout list table and the affiliate-facing visits list table, where raw user-supplied URL data is output without HTML escaping. This allows any unauthenticated visitor to inject arbitrary JavaScript that executes in the context of any user viewing the affected pages.
The root cause exists in two display areas. First, in `/slicewp/includes/admin/visits/class-list-table-visits.php` at lines 273 and 290, the `column_landing_url()` and `column_referrer_url()` methods output `rawurldecode( $item[‘landing_url’] )` and `rawurldecode( $item[‘referrer_url’] )` respectively without wrapping them in `esc_html()`. The diff shows that these values are stored directly from affiliate visits, with no sanitization on input. Second, the admin payout list table in `/slicewp/includes/admin/payouts/class-list-table-payouts.php` at line 301 passes payout IDs into a nonced URL without ensuring the payout belongs to the current user, but the XSS vector confirmed by the patch is the unescaped URL values in the visits tables. The patch adds `esc_html()` around the decoded URL outputs, which prevents the browser from interpreting injected HTML or JavaScript.
Exploitation is straightforward. An attacker sends a crafted visit to the site using a URL parameter such as `landing_url` or `referrer_url` containing a malicious payload. For example: `alert(‘XSS’)` as the landing URL. The plugin stores this value in the database without sanitization. When an administrator views the visits list table at `wp-admin/admin.php?page=slicewp-payouts&subpage=payouts-history` (or the affiliate visits page in the frontend), the plugin generates an anchor tag with the unsanitized URL as the visible text. The browser renders the injected script, executing the attacker’s code. Since the visits endpoint records requests from any visitor (affiliate or not), no authentication is required to trigger storage.
The patch introduces `esc_html()` around `rawurldecode()` calls in both column functions within `class-list-table-visits.php`. Before the patch, line 273 read: `‘ . rawurldecode( $item[‘landing_url’] ) . ‘`. After the patch, it reads: `‘ . esc_html( rawurldecode( $item[‘landing_url’] ) ) . ‘`. This HTML-encodes the output, converting “ to `>`, and other dangerous characters to their safe entities, so the browser displays them as text rather than interpreting them as markup. The patch also adds a null check in `functions.php` for the `slicewp_display_affiliate_visit` function and removes inline width styles from table headers, but these are hardening changes unrelated to the XSS.
If exploited, an attacker can execute arbitrary JavaScript in the session of any user visiting the admin visits page or the affiliate account visits tab. This includes administrators, who can then be targeted to steal session cookies, exfiltrate site data, perform actions like creating new admin users, or redirect users to phishing pages. The confidentiality and integrity impacts are high because the stolen context (admin) has full site control. The CVSS score of 7.2 reflects the ease of exploitation (network access, no authentication) and the high potential for account takeover or site defacement.
Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/slicewp/includes/admin/payouts/class-list-table-payouts.php
+++ b/slicewp/includes/admin/payouts/class-list-table-payouts.php
@@ -297,7 +297,7 @@
// Allow CSV Generation only if the Payout has an amount greater than zero.
if ( $item['amount'] != 0 ) {
- $output .= '<a href="' . esc_url( wp_nonce_url( add_query_arg( array( 'page' => 'slicewp-payouts', 'subpage' => 'payouts-history', 'slicewp_action' => 'generate_payouts_csv', 'payout_id' => $item['id'] ) , admin_url( 'admin.php' ) ), 'slicewp_generate_payouts_csv', 'slicewp_token' ) ) . '" class="slicewp-button-secondary">' . __( 'Generate CSV', 'slicewp' ) . '</a>';
+ $output .= '<a href="' . esc_url( wp_nonce_url( add_query_arg( array( 'page' => 'slicewp-payouts', 'slicewp_action' => 'generate_payouts_csv', 'payout_id' => $item['id'] ) , admin_url( 'admin.php' ) ), 'slicewp_generate_payouts_csv', 'slicewp_token' ) ) . '" class="slicewp-button-secondary">' . __( 'Generate CSV', 'slicewp' ) . '</a>';
} else {
$output .= '<a href="#" class="slicewp-button-secondary slicewp-disabled" onclick="return false;">' . __( 'Generate CSV', 'slicewp' ) . '</a>';
}
--- a/slicewp/includes/admin/visits/class-list-table-visits.php
+++ b/slicewp/includes/admin/visits/class-list-table-visits.php
@@ -270,7 +270,7 @@
*/
public function column_landing_url( $item ) {
- $output = '<a href="' . esc_url_raw( $item['landing_url'] ) . '" target="_blank">' . rawurldecode( $item['landing_url'] ) . '</a>';
+ $output = '<a href="' . esc_url_raw( $item['landing_url'] ) . '" target="_blank">' . esc_html( rawurldecode( $item['landing_url'] ) ) . '</a>';
return $output;
@@ -287,7 +287,7 @@
*/
public function column_referrer_url( $item ) {
- $output = '<a href="' . esc_url_raw( $item['referrer_url'] ) . '" target="_blank">' . rawurldecode( $item['referrer_url'] ) . '</a>';
+ $output = '<a href="' . esc_url_raw( $item['referrer_url'] ) . '" target="_blank">' . esc_html( rawurldecode( $item['referrer_url'] ) ) . '</a>';
return $output;
--- a/slicewp/includes/users/class-list-table-affiliate-account-commissions.php
+++ b/slicewp/includes/users/class-list-table-affiliate-account-commissions.php
@@ -165,6 +165,30 @@
/**
+ * Outputs the HTML of the table.
+ *
+ */
+ public function output_table() {
+
+ $this->output_table_before();
+
+ echo '<div class="slicewp-list-table-wrapper">';
+
+ echo '<table class="slicewp-list-table">';
+
+ $this->output_table_header();
+ $this->output_table_body();
+
+ echo '</table>';
+
+ echo '</div>';
+
+ $this->output_table_after();
+
+ }
+
+
+ /**
* Outputs the table date range picker.
*
*/
--- a/slicewp/includes/users/class-list-table-affiliate-account-payments.php
+++ b/slicewp/includes/users/class-list-table-affiliate-account-payments.php
@@ -133,6 +133,30 @@
/**
+ * Outputs the HTML of the table.
+ *
+ */
+ public function output_table() {
+
+ $this->output_table_before();
+
+ echo '<div class="slicewp-list-table-wrapper">';
+
+ echo '<table class="slicewp-list-table">';
+
+ $this->output_table_header();
+ $this->output_table_body();
+
+ echo '</table>';
+
+ echo '</div>';
+
+ $this->output_table_after();
+
+ }
+
+
+ /**
* Outputs the table row item details for the given item data.
*
* @param array $item
--- a/slicewp/includes/users/class-list-table-affiliate-account-visits.php
+++ b/slicewp/includes/users/class-list-table-affiliate-account-visits.php
@@ -67,6 +67,21 @@
/**
+ * Column "referrer_url".
+ *
+ * @param array $item
+ *
+ * @return string
+ *
+ */
+ public function column_referrer_url( $item ) {
+
+ return esc_html( ! empty( $item['referrer_url'] ) ? $item['referrer_url'] : '-' );
+
+ }
+
+
+ /**
* Column "date".
*
* @param array $item
@@ -79,6 +94,30 @@
return slicewp_date_i18n( $item['date_created'] );
}
+
+
+ /**
+ * Outputs the HTML of the table.
+ *
+ */
+ public function output_table() {
+
+ $this->output_table_before();
+
+ echo '<div class="slicewp-list-table-wrapper">';
+
+ echo '<table class="slicewp-list-table">';
+
+ $this->output_table_header();
+ $this->output_table_body();
+
+ echo '</table>';
+
+ echo '</div>';
+
+ $this->output_table_after();
+
+ }
/**
--- a/slicewp/includes/users/functions.php
+++ b/slicewp/includes/users/functions.php
@@ -327,6 +327,10 @@
$visit = slicewp_get_visit( absint( $item['visit_id'] ) );
+ if ( is_null( $visit ) ) {
+ return;
+ }
+
if ( $visit->get( 'affiliate_id' ) != $item['affiliate_id'] ) {
return;
}
@@ -337,9 +341,9 @@
echo '<thead>';
echo '<tr>';
- echo '<th class="slicewp-column-id" style="width: 85px;">' . __( 'Visit', 'slicewp' ) . '</th>';
- echo '<th class="slicewp-column-landing_url" style="width: 35%">' . __( 'Landing URL', 'slicewp' ) . '</th>';
- echo '<th class="slicewp-column-referrer_url" style="width: 35%">' . __( 'Referrer URL', 'slicewp' ) . '</th>';
+ echo '<th class="slicewp-column-id">' . __( 'Visit', 'slicewp' ) . '</th>';
+ echo '<th class="slicewp-column-landing_url">' . __( 'Landing URL', 'slicewp' ) . '</th>';
+ echo '<th class="slicewp-column-referrer_url">' . __( 'Referrer URL', 'slicewp' ) . '</th>';
echo '<th class="slicewp-column-date">' . __( 'Date', 'slicewp' ) . '</th>';
echo '</tr>';
echo '</thead>';
--- a/slicewp/index.php
+++ b/slicewp/index.php
@@ -3,7 +3,7 @@
* Plugin Name: SliceWP
* Plugin URI: https://slicewp.com/
* Description: The fastest and easiest way to set up an affiliate program for your store or membership site.
- * Version: 1.2.6
+ * Version: 1.2.7
* Author: SliceWP
* Author URI: https://slicewp.com/
* Text Domain: slicewp
@@ -103,7 +103,7 @@
public function __construct() {
// Defining constants.
- define( 'SLICEWP_VERSION', '1.2.6' );
+ define( 'SLICEWP_VERSION', '1.2.7' );
define( 'SLICEWP_BASENAME', plugin_basename( __FILE__ ) );
define( 'SLICEWP_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
define( 'SLICEWP_PLUGIN_DIR_URL', plugin_dir_url( __FILE__ ) );
--- a/slicewp/templates/affiliate-area/affiliate-account-tab-commissions.php
+++ b/slicewp/templates/affiliate-area/affiliate-account-tab-commissions.php
@@ -45,6 +45,7 @@
$table = new SliceWP_List_Table_Affiliate_Account_Commissions( array(
'screen_base_url' => add_query_arg( array( 'affiliate-account-tab' => 'commissions' ), strtok( set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ), '?' ) )
));
+
$table->output();
}
No newline at end of file