Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/restrict-content/core/includes/class-restrict-content.php
+++ b/restrict-content/core/includes/class-restrict-content.php
@@ -26,7 +26,7 @@
* @since 3.0
*/
final class Restrict_Content_Pro {
- const VERSION = '3.5.54';
+ const VERSION = '3.5.56';
/**
* Stores the base slug for the extension.
--- a/restrict-content/core/includes/gateways/stripe/functions.php
+++ b/restrict-content/core/includes/gateways/stripe/functions.php
@@ -179,7 +179,7 @@
/**
* Update the billing card for a given membership.
*
- * @param RCP_Membership $membership
+ * @param RCP_Membership $membership Membership object.
*
* @since 3.0
* @return void
@@ -298,7 +298,7 @@
wp_die( $error, __( 'Error', 'rcp' ), array( 'response' => '401' ) );
- exit;
+ return;
} catch (StripeErrorInvalidRequest $e) {
@@ -375,8 +375,8 @@
}
- wp_redirect( add_query_arg( 'card', 'updated' ) ); exit;
-
+ wp_redirect( add_query_arg( 'card', 'updated' ) );
+ return;
}
add_action( 'rcp_update_membership_billing_card', 'rcp_stripe_update_membership_billing_card' );
@@ -791,11 +791,16 @@
*/
function rcp_stripe_handle_initial_payment_failure() {
- $payment_id = ! empty( $_POST['payment_id'] ) ? absint( $_POST['payment_id'] ) : 0;
+ // Verify nonce for CSRF protection.
+ $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
+ if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'rcp_process_stripe_payment' ) ) {
+ wp_send_json_error( __( 'Security verification failed.', 'rcp' ) );
+ }
+
+ $payment_id = ! empty( $_POST['payment_id'] ) ? absint( wp_unslash( $_POST['payment_id'] ) ) : 0;
if ( empty( $payment_id ) ) {
wp_send_json_error( __( 'Missing payment ID.', 'rcp' ) );
- exit;
}
/**
@@ -805,18 +810,48 @@
$payment = $rcp_payments_db->get_payment( $payment_id );
- if ( empty( $payment ) ) {
+ if ( empty( $payment ) || ! is_object( $payment ) ) {
wp_send_json_error( __( 'Invalid payment.', 'rcp' ) );
- exit;
}
+ // Security check: Verify user ownership of the payment.
+ $current_user_id = get_current_user_id();
+ if ( empty( $current_user_id ) || absint( $payment->user_id ) !== $current_user_id ) {
+ wp_send_json_error( __( 'You do not have permission to perform this action.', 'rcp' ) );
+ }
+
+ // Only allow marking payments as failed if they are in pending status.
+ if ( 'pending' !== strtolower( $payment->status ) ) {
+ wp_send_json_error( __( 'This payment cannot be marked as failed.', 'rcp' ) );
+ }
+
+ // Verify the membership belongs to the current user.
+ if ( ! empty( $payment->membership_id ) ) {
+ $membership = rcp_get_membership( absint( $payment->membership_id ) );
+ if ( empty( $membership ) || absint( $membership->get_customer()->get_user_id() ) !== $current_user_id ) {
+ wp_send_json_error( __( 'You do not have permission to perform this action.', 'rcp' ) );
+ }
+ }
+
+ /**
+ * Fires before processing a payment failure.
+ *
+ * Can be used to implement additional security checks like rate limiting.
+ *
+ * @since 3.5.55
+ *
+ * @param object $payment Payment object.
+ * @param int $user_id Current user ID.
+ */
+ do_action( 'rcp_before_stripe_handle_payment_failure', $payment, $current_user_id );
+
$gateway = new RCP_Payment_Gateway_Stripe();
// Set some of the expected properties.
$gateway->payment = $payment;
$gateway->user_id = $payment->user_id;
$gateway->membership = rcp_get_membership( absint( $payment->membership_id ) );
- $gateway->error_message = ! empty( $_POST['message'] ) ? sanitize_text_field( $_POST['message'] ) : __( 'Unknown error', 'rcp' );
+ $gateway->error_message = ! empty( $_POST['message'] ) ? sanitize_text_field( wp_unslash( $_POST['message'] ) ) : __( 'Unknown error', 'rcp' );
do_action( 'rcp_registration_failed', $gateway );
@@ -830,7 +865,6 @@
do_action( 'rcp_stripe_signup_payment_failed', $error, $gateway );
wp_send_json_success();
- exit;
}
@@ -986,7 +1020,6 @@
}
wp_send_json_error( __( 'Error creating setup intent.', 'rcp' ) );
- exit;
}
@@ -1094,8 +1127,7 @@
wp_send_json_error( __( 'An unknown error occurred.', 'rcp' ) );
}
- exit;
-
+ return;
}
add_action( 'wp_ajax_rcp_stripe_delete_saved_payment_method', 'rcp_stripe_delete_saved_payment_method' );
--- a/restrict-content/core/includes/scripts.php
+++ b/restrict-content/core/includes/scripts.php
@@ -299,6 +299,7 @@
'error_occurred' => esc_html__( 'An unexpected error has occurred. Please try again or contact support if the issue persists.', 'rcp' ),
'enter_card_details' => esc_html__( 'Please enter your card details.', 'rcp' ),
'invalid_cardholder' => esc_html__( 'The card holder name you have entered is invalid', 'rcp' ),
+ 'stripe_payment_nonce' => wp_create_nonce( 'rcp_process_stripe_payment' ),
)
);
--- a/restrict-content/legacy/restrictcontent.php
+++ b/restrict-content/legacy/restrictcontent.php
@@ -21,7 +21,7 @@
}
if ( ! defined( 'RC_PLUGIN_VERSION' ) ) {
- define( 'RC_PLUGIN_VERSION', '3.2.22' );
+ define( 'RC_PLUGIN_VERSION', '3.2.23' );
}
if ( ! defined( 'RC_PLUGIN_DIR' ) ) {
--- a/restrict-content/restrictcontent.php
+++ b/restrict-content/restrictcontent.php
@@ -3,7 +3,7 @@
* Plugin Name: Restrict Content
* Plugin URI: https://restrictcontentpro.com
* Description: Set up a complete membership system for your WordPress site and deliver premium content to your members. Unlimited membership packages, membership management, discount codes, registration / login forms, and more.
- * Version: 3.2.22
+ * Version: 3.2.23
* Author: StellarWP
* Author URI: https://stellarwp.com/
* Requires at least: 6.0
@@ -18,7 +18,7 @@
define('RCP_PLUGIN_FILE', __FILE__);
define('RCP_ROOT', plugin_dir_path(__FILE__));
define('RCP_WEB_ROOT', plugin_dir_url(__FILE__));
-define('RCF_VERSION', '3.2.22');
+define('RCF_VERSION', '3.2.23');
// Load Strauss autoload.
require_once plugin_dir_path( __FILE__ ) . 'vendor/strauss/autoload.php';