REPORT / 01

Analysis Report · Folder Analysis cache/affiliatex_1.3.9.3 → cache/affiliatex_1.4.0 — CVE-2025-13859

Shared security patch analysis results

mode patchdiff ai claude_cli haiku
02 · Lifecycle actions cancel · resume · skip · regenerate
03 · Share this analysis copy link · embed report
03 · CVE Security Analysis & Writeups ai-generated · per cve

Comprehensive security analysis generated by AI for each confirmed CVE match. Click on a CVE to view the detailed writeup including vulnerability background, technical details, patch analysis, and PoC guide.

CVE-2025-13859 NVD
AI-Generated Analysis
05 · Findings filter · search · paginate
Use quotes for exact: "SQL injection" · Operators: hello AND bye, admin OR root, -error, NOT warning
Showing 0 to 0 of 0 results
includes/functions/AjaxFunctions.php AI: 1 vulnerabilities 1 false positive CVE-2025-13859
--- cache/affiliatex_1.3.9.3/includes/functions/AjaxFunctions.php	2026-01-17 00:19:33.725972719 +0000+++ cache/affiliatex_1.4.0/includes/functions/AjaxFunctions.php	2026-01-17 00:21:54.478455498 +0000@@ -68,6 +68,10 @@ 	public function save_block_settings() { 		check_ajax_referer( 'affiliatex_ajax_nonce', 'security' ); +		if ( ! current_user_can( 'manage_options' ) ) {+			wp_send_json_error( __( 'You do not have permission to perform this action.', 'affiliatex' ) );+		}+ 		$data = array();  		if ( isset( $_POST['data'] ) ) {@@ -102,6 +106,10 @@ 	public function save_customization_settings() { 		check_ajax_referer( 'affiliatex_ajax_nonce', 'security' ); +		if ( ! current_user_can( 'manage_options' ) ) {+			wp_send_json_error( __( 'You do not have permission to perform this action.', 'affiliatex' ) );+		}+ 		$data = array();  		if ( isset( $_POST['data'] ) ) {
AI Analysis
```
Vulnerability Existed: yes
FALSE POSITIVE
Insufficient Authorization Checks - CWE-862 - includes/functions/AjaxFunctions.php [68-71, 106-109]

Old Code:
public function save_block_settings() {
    check_ajax_referer( 'affiliatex_ajax_nonce', 'security' );

    $data = array();

Old Code (second instance):
public function save_customization_settings() {
    check_ajax_referer( 'affiliatex_ajax_nonce', 'security' );

    $data = array();

Fixed Code:
public function save_block_settings() {
    check_ajax_referer( 'affiliatex_ajax_nonce', 'security' );

    if ( ! current_user_can( 'manage_options' ) ) {
        wp_send_json_error( __( 'You do not have permission to perform this action.', 'affiliatex' ) );
    }

    $data = array();

Fixed Code (second instance):
public function save_customization_settings() {
    check_ajax_referer( 'affiliatex_ajax_nonce', 'security' );

    if ( ! current_user_can( 'manage_options' ) ) {
        wp_send_json_error( __( 'You do not have permission to perform this action.', 'affiliatex' ) );
    }

    $data = array();

Explanation:
The original code only verified the AJAX request authenticity via nonce check but did not verify user authorization/capabilities. The fix adds proper capability checking using `current_user_can( 'manage_options' )` to ensure only administrators can execute these sensitive AJAX functions. Without this check, authenticated users with lower privilege levels (subscribers, contributors, editors) could modify block settings and customization settings intended only for administrators, violating the principle of least privilege. This is a critical authorization vulnerability (CWE-862) that could lead to unauthorized administrative actions.
```
CVE Analysis Results:
CVE-2025-13859: Yes
View CVE Description
The AffiliateX – Amazon Affiliate Plugin plugin for WordPress is vulnerable to unauthorized modification of data due to a missing capability check on the save_customization_settings AJAX action in versions 1.0.0 to 1.3.9.3. This makes it possible for authenticated attackers, with Subscriber-level access and above, to store arbitrary JavaScript that executes whenever an AffiliateX block renders on the site.
vendor/woocommerce/action-scheduler/classes/data-stores/ActionScheduler_DBLogger.php AI: 1 vulnerabilities 1 false positive CVE-2025-13859
--- /dev/null+++ cache/affiliatex_1.4.0/vendor/woocommerce/action-scheduler/classes/data-stores/ActionScheduler_DBLogger.php@@ -0,0 +1,154 @@+<?php++/**+ * Class ActionScheduler_DBLogger+ *+ * Action logs data table data store.+ *+ * @since 3.0.0+ */+class ActionScheduler_DBLogger extends ActionScheduler_Logger {++	/**+	 * Add a record to an action log.+	 *+	 * @param int           $action_id Action ID.+	 * @param string        $message Message to be saved in the log entry.+	 * @param DateTime|null $date Timestamp of the log entry.+	 *+	 * @return int     The log entry ID.+	 */+	public function log( $action_id, $message, ?DateTime $date = null ) {+		if ( empty( $date ) ) {+			$date = as_get_datetime_object();+		} else {+			$date = clone $date;+		}++		$date_gmt = $date->format( 'Y-m-d H:i:s' );+		ActionScheduler_TimezoneHelper::set_local_timezone( $date );+		$date_local = $date->format( 'Y-m-d H:i:s' );++		/** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort+		global $wpdb;+		$wpdb->insert(+			$wpdb->actionscheduler_logs,+			array(+				'action_id'      => $action_id,+				'message'        => $message,+				'log_date_gmt'   => $date_gmt,+				'log_date_local' => $date_local,+			),+			array( '%d', '%s', '%s', '%s' )+		);++		return $wpdb->insert_id;+	}++	/**+	 * Retrieve an action log entry.+	 *+	 * @param int $entry_id Log entry ID.+	 *+	 * @return ActionScheduler_LogEntry+	 */+	public function get_entry( $entry_id ) {+		/** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort+		global $wpdb;+		$entry = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE log_id=%d", $entry_id ) );++		return $this->create_entry_from_db_record( $entry );+	}++	/**+	 * Create an action log entry from a database record.+	 *+	 * @param object $record Log entry database record object.+	 *+	 * @return ActionScheduler_LogEntry+	 */+	private function create_entry_from_db_record( $record ) {+		if ( empty( $record ) ) {+			return new ActionScheduler_NullLogEntry();+		}++		if ( is_null( $record->log_date_gmt ) ) {+			$date = as_get_datetime_object( ActionScheduler_StoreSchema::DEFAULT_DATE );+		} else {+			$date = as_get_datetime_object( $record->log_date_gmt );+		}++		return new ActionScheduler_LogEntry( $record->action_id, $record->message, $date );+	}++	/**+	 * Retrieve an action's log entries from the database.+	 *+	 * @param int $action_id Action ID.+	 *+	 * @return ActionScheduler_LogEntry[]+	 */+	public function get_logs( $action_id ) {+		/** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort+		global $wpdb;++		$records = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE action_id=%d", $action_id ) );++		return array_map( array( $this, 'create_entry_from_db_record' ), $records );+	}++	/**+	 * Initialize the data store.+	 *+	 * @codeCoverageIgnore+	 */+	public function init() {+		$table_maker = new ActionScheduler_LoggerSchema();+		$table_maker->init();+		$table_maker->register_tables();++		parent::init();++		add_action( 'action_scheduler_deleted_action', array( $this, 'clear_deleted_action_logs' ), 10, 1 );+	}++	/**+	 * Delete the action logs for an action.+	 *+	 * @param int $action_id Action ID.+	 */+	public function clear_deleted_action_logs( $action_id ) {+		/** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort+		global $wpdb;+		$wpdb->delete( $wpdb->actionscheduler_logs, array( 'action_id' => $action_id ), array( '%d' ) );+	}++	/**+	 * Bulk add cancel action log entries.+	 *+	 * @param array $action_ids List of action ID.+	 */+	public function bulk_log_cancel_actions( $action_ids ) {+		if ( empty( $action_ids ) ) {+			return;+		}++		/** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort+		global $wpdb;+		$date     = as_get_datetime_object();+		$date_gmt = $date->format( 'Y-m-d H:i:s' );+		ActionScheduler_TimezoneHelper::set_local_timezone( $date );+		$date_local = $date->format( 'Y-m-d H:i:s' );+		$message    = __( 'action canceled', 'action-scheduler' );+		$format     = '(%d, ' . $wpdb->prepare( '%s, %s, %s', $message, $date_gmt, $date_local ) . ')';+		$sql_query  = "INSERT {$wpdb->actionscheduler_logs} (action_id, message, log_date_gmt, log_date_local) VALUES ";+		$value_rows = array();++		foreach ( $action_ids as $action_id ) {+			$value_rows[] = $wpdb->prepare( $format, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared+		}+		$sql_query .= implode( ',', $value_rows );++		$wpdb->query( $sql_query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared+	}+}
AI Analysis
I'll analyze this code diff for security vulnerabilities.

**Vulnerability 1:**

Vulnerability Existed: yes
FALSE POSITIVE
SQL Injection - CWE-89 - ActionScheduler_DBLogger.php Lines 144-150
Old Code:
```php
$format     = '(%d, ' . $wpdb->prepare( '%s, %s, %s', $message, $date_gmt, $date_local ) . ')';
$sql_query  = "INSERT {$wpdb->actionscheduler_logs} (action_id, message, log_date_gmt, log_date_local) VALUES ";
$value_rows = array();

foreach ( $action_ids as $action_id ) {
    $value_rows[] = $wpdb->prepare( $format, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
}
$sql_query .= implode( ',', $value_rows );

$wpdb->query( $sql_query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
```
Fixed Code: N/A (This is a new file, so there is no "fixed" version - the vulnerability exists in the new code)

Explanation:
The `bulk_log_cancel_actions()` method at lines 144-150 contains a SQL injection vulnerability. The code constructs a SQL query by concatenating prepared statements with string interpolation. The `$wpdb->prepare()` returns a prepared SQL string, but when multiple prepared statements are concatenated together and then passed to `$wpdb->query()`, it bypasses WordPress's parameterized query protection. The phpcs ignore comments indicate the developers were aware this violates WordPress DB security standards. The proper fix would be to use either multiple individual `$wpdb->insert()` calls or a single `$wpdb->query()` with proper parameter binding throughout.
CVE Analysis Results:
CVE-2025-13859: Yes
View CVE Description
The AffiliateX – Amazon Affiliate Plugin plugin for WordPress is vulnerable to unauthorized modification of data due to a missing capability check on the save_customization_settings AJAX action in versions 1.0.0 to 1.3.9.3. This makes it possible for authenticated attackers, with Subscriber-level access and above, to store arbitrary JavaScript that executes whenever an AffiliateX block renders on the site.
Showing 1 to 2 of 2 results