Analysis Report Folder Analysis cache/tutor_3.9.2 → cache/tutor_3.9.4 - CVE-2025-13935

Shared security patch analysis results

AI Used: claude_cli haiku
Share this analysis
CVE Security Analysis & Writeups

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-13935
AI-Generated Analysis
Use quotes for exact: \"SQL injection\" | Operators: hello AND bye, admin OR root, -error, NOT warning
Showing 0 to 0 of 0 results
classes/Course.php AI: 2 vulnerabilities 2 true positives CVE-2025-13935
--- cache/tutor_3.9.2/classes/Course.php	2026-01-09 00:37:03.808520625 +0000+++ cache/tutor_3.9.4/classes/Course.php	2026-01-09 00:38:24.081403085 +0000@@ -2119,12 +2119,17 @@ 			die( esc_html__( 'Please Sign-In', 'tutor' ) ); 		} +		if ( ! tutor_utils()->is_enrolled( $course_id, $user_id ) ) {+			die( esc_html__( 'User is not enrolled in course', 'tutor' ) );+		}+ 		/** 		 * Filter hook provided to restrict course completion. This is useful 		 * for specific cases like prerequisites. WP_Error should be returned 		 * from the filter value to prevent the completion. 		 */ 		$can_complete = apply_filters( 'tutor_user_can_complete_course', true, $user_id, $course_id );+ 		if ( is_wp_error( $can_complete ) ) { 			tutor_utils()->redirect_to( $permalink, $can_complete->get_error_message(), 'error' ); 		} else {@@ -2992,6 +2997,25 @@ 			if ( $password_protected ) { 				wp_send_json_error( __( 'This course is password protected', 'tutor' ) ); 			}++			/**+			 * This check was added to address a security issue where users could+			 * enroll in a course via an AJAX call without purchasing it.+			 *+			 * To prevent this, we now verify whether the course is paid.+			 * Additionally, we check if the user is already enrolled, since+			 * Tutor's default behavior enrolls users automatically upon purchase.+			 *+			 * @since 3.9.4+			 */+			if ( tutor_utils()->is_course_purchasable( $course_id ) ) {+				$is_enrolled = (bool) tutor_utils()->is_enrolled( $course_id, $user_id );++				if ( ! $is_enrolled ) {+					wp_send_json_error( __( 'Please purchase the course before enrolling', 'tutor' ) );+				}+			}+ 			$enroll = tutor_utils()->do_enroll( $course_id, 0, $user_id ); 			if ( $enroll ) { 				wp_send_json_success( __( 'Enrollment successfully done!', 'tutor' ) );
AI Analysis
Vulnerability Existed: yes
TRUE POSITIVE
Improper Access Control - CWE-284 - classes/Course.php Lines 2122-2124
[Old Code]
No enrollment check present before allowing course completion
[Fixed Code]
```php
if ( ! tutor_utils()->is_enrolled( $course_id, $user_id ) ) {
    die( esc_html__( 'User is not enrolled in course', 'tutor' ) );
}
```
Explanation:
The original code allowed users to mark a course as complete without verifying enrollment status. An authenticated user could directly call the course completion function with any course_id and user_id to mark completion, even if not enrolled. The fix adds an enrollment check before allowing course completion, properly enforcing access control.

---

Vulnerability Existed: yes
TRUE POSITIVE
Improper Access Control - CWE-284 - classes/Course.php Lines 3011-3019
[Old Code]
```php
$enroll = tutor_utils()->do_enroll( $course_id, 0, $user_id );
if ( $enroll ) {
    wp_send_json_success( __( 'Enrollment successfully done!', 'tutor' ) );
}
```
[Fixed Code]
```php
if ( tutor_utils()->is_course_purchasable( $course_id ) ) {
    $is_enrolled = (bool) tutor_utils()->is_enrolled( $course_id, $user_id );
    
    if ( ! $is_enrolled ) {
        wp_send_json_error( __( 'Please purchase the course before enrolling', 'tutor' ) );
    }
}

$enroll = tutor_utils()->do_enroll( $course_id, 0, $user_id );
```
Explanation:
The original AJAX enrollment endpoint allowed users to enroll in paid courses without purchasing them. An attacker could call this endpoint directly to gain course access. The fix checks if the course is purchasable and verifies the user has already purchased/enrolled before allowing enrollment via AJAX, preventing unauthorized course access.
CVE Analysis Results:
CVE-2025-13935: Yes
View CVE Description
The Tutor LMS – eLearning and online course solution plugin for WordPress is vulnerable to unauthorized course completion in all versions up to, and including, 3.9.2. This is due to missing enrollment verification in the 'mark_course_complete' function. This makes it possible for authenticated attackers, with subscriber level access and above, to mark any course as completed.
classes/Quiz.php AI: 1 vulnerabilities 1 true positive
--- cache/tutor_3.9.2/classes/Quiz.php	2026-01-09 00:37:03.808520625 +0000+++ cache/tutor_3.9.4/classes/Quiz.php	2026-01-09 00:38:24.089403572 +0000@@ -283,6 +283,12 @@ 		$attempt_details = self::attempt_details( Input::post( 'attempt_id', 0, Input::TYPE_INT ) ); 		$feedback        = Input::post( 'feedback', '', Input::TYPE_KSES_POST ); 		$attempt_info    = isset( $attempt_details->attempt_info ) ? $attempt_details->attempt_info : false;+		$course_id       = tutor_utils()->avalue_dot( 'course_id', $attempt_info, 0 );++		if ( ! tutor_utils()->is_instructor_of_this_course( get_current_user_id(), $course_id ) ) {+			wp_send_json_error( tutor_utils()->error_message() );+		}+ 		if ( $attempt_info ) { 			//phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize 			$unserialized = unserialize( $attempt_details->attempt_info );
AI Analysis
I'll analyze this code diff for security vulnerabilities.

Vulnerability Existed: yes
TRUE POSITIVE
Broken Access Control - CWE-639 - classes/Quiz.php - Lines 286-288

Old Code:
```php
$attempt_details = self::attempt_details( Input::post( 'attempt_id', 0, Input::TYPE_INT ) );
$feedback        = Input::post( 'feedback', '', Input::TYPE_KSES_POST );
$attempt_info    = isset( $attempt_details->attempt_info ) ? $attempt_details->attempt_info : false;
if ( $attempt_info ) {
```

Fixed Code:
```php
$attempt_details = self::attempt_details( Input::post( 'attempt_id', 0, Input::TYPE_INT ) );
$feedback        = Input::post( 'feedback', '', Input::TYPE_KSES_POST );
$attempt_info    = isset( $attempt_details->attempt_info ) ? $attempt_details->attempt_info : false;
$course_id       = tutor_utils()->avalue_dot( 'course_id', $attempt_info, 0 );

if ( ! tutor_utils()->is_instructor_of_this_course( get_current_user_id(), $course_id ) ) {
	wp_send_json_error( tutor_utils()->error_message() );
}

if ( $attempt_info ) {
```

Explanation:
The original code was missing an authorization check before processing quiz attempt feedback. An authenticated user could submit feedback for any quiz attempt regardless of whether they were an instructor of that course. The fix adds a critical authorization check that verifies the current user is an instructor of the course associated with the attempt before allowing the feedback submission to proceed. This prevents privilege escalation and unauthorized data modification (CWE-639: Authorization Using an Incorrect Resource).
CVE Analysis Results:
CVE-2025-13935: No
View CVE Description
The Tutor LMS – eLearning and online course solution plugin for WordPress is vulnerable to unauthorized course completion in all versions up to, and including, 3.9.2. This is due to missing enrollment verification in the 'mark_course_complete' function. This makes it possible for authenticated attackers, with subscriber level access and above, to mark any course as completed.
classes/Utils.php AI: No vulnerabilities
--- cache/tutor_3.9.2/classes/Utils.php	2026-01-09 00:37:03.812520867 +0000+++ cache/tutor_3.9.4/classes/Utils.php	2026-01-09 00:38:24.097404059 +0000@@ -3281,6 +3281,7 @@ 					ON cmeta.comment_id = c.comment_ID 					AND cmeta.meta_key = 'tutor_rating' 			WHERE 	user_meta.meta_key = '_is_tutor_instructor'+				AND inst_status.meta_key = '_tutor_instructor_status' 				AND ( user.display_name LIKE %s OR user.user_email = %s ) 				{$status} 				{$category_where}@@ -5777,9 +5778,9 @@ 				'icon_classes' => 'tutor-icon-brand-facebook', 			), 			'_tutor_profile_twitter'  => array(-				'label'        => __( 'Twitter', 'tutor' ),-				'placeholder'  => 'https://twitter.com/username',-				'icon_classes' => 'tutor-icon-brand-twitter',+				'label'        => __( 'X', 'tutor' ),+				'placeholder'  => 'https://x.com/username',+				'icon_classes' => 'tutor-icon-brand-x-twitter', 			), 			'_tutor_profile_linkedin' => array( 				'label'        => __( 'Linkedin', 'tutor' ),
AI Analysis
I'll analyze this code diff for security vulnerabilities.

**Vulnerability 1:**

Vulnerability Existed: no

SQL Injection - CWE-89 - classes/Utils.php Lines 3284

Old Code:
```php
WHERE 	user_meta.meta_key = '_is_tutor_instructor'
			AND ( user.display_name LIKE %s OR user.user_email = %s )
```

Fixed Code:
```php
WHERE 	user_meta.meta_key = '_is_tutor_instructor'
			AND inst_status.meta_key = '_tutor_instructor_status'
			AND ( user.display_name LIKE %s OR user.user_email = %s )
```

Explanation:
The added line `AND inst_status.meta_key = '_tutor_instructor_status'` is a hardcoded string comparison in the WHERE clause. This is not a vulnerability fix but rather an additional filter condition. The existing code already uses parameterized queries (indicated by `%s` placeholders), so SQL injection was not present before or after this change. This is a logical improvement to the query filtering, not a security fix.

**Vulnerability 2:**

Vulnerability Existed: no

No Security Vulnerability - classes/Utils.php Lines 5780-5782

Old Code:
```php
'label'        => __( 'Twitter', 'tutor' ),
'placeholder'  => 'https://twitter.com/username',
'icon_classes' => 'tutor-icon-brand-twitter',
```

Fixed Code:
```php
'label'        => __( 'X', 'tutor' ),
'placeholder'  => 'https://x.com/username',
'icon_classes' => 'tutor-icon-brand-x-twitter',
```

Explanation:
This change updates branding references from Twitter to X (the platform's new name) and updates the URL from twitter.com to x.com. This is a cosmetic/branding update with no security implications. The URL is hardcoded in the placeholder and not user-controlled, so there are no injection vulnerabilities.

**Summary:**
This diff contains no security fixes or security vulnerabilities. The changes are: (1) a query refinement adding an additional filter condition, and (2) a branding update for social media profile fields.
CVE Analysis Results:
CVE-2025-13935: No
View CVE Description
The Tutor LMS – eLearning and online course solution plugin for WordPress is vulnerable to unauthorized course completion in all versions up to, and including, 3.9.2. This is due to missing enrollment verification in the 'mark_course_complete' function. This makes it possible for authenticated attackers, with subscriber level access and above, to mark any course as completed.
classes/WooCommerce.php AI: 1 vulnerabilities 1 false positive
--- cache/tutor_3.9.2/classes/WooCommerce.php	2026-01-09 00:37:03.812520867 +0000+++ cache/tutor_3.9.4/classes/WooCommerce.php	2026-01-09 00:38:24.097404059 +0000@@ -757,7 +757,7 @@ 				return; 			} -			$has_enrollment = tutor_utils()->is_enrolled( $course_id, $customer_id, false );+			$has_enrollment = tutor_utils()->is_enrolled( $course_id, $customer_id, true ); 			if ( ! $has_enrollment ) { 				tutor_utils()->do_enroll( $course_id, $order_id, $customer_id ); 			}
AI Analysis
Vulnerability Existed: yes
FALSE POSITIVE
Incorrect Authorization Check - CWE-639 - classes/WooCommerce.php line 760

Old Code:
```php
$has_enrollment = tutor_utils()->is_enrolled( $course_id, $customer_id, false );
```

Fixed Code:
```php
$has_enrollment = tutor_utils()->is_enrolled( $course_id, $customer_id, true );
```

Explanation:
The third parameter change from `false` to `true` in the `is_enrolled()` function call represents a critical authorization fix. Based on the context (WooCommerce order processing), the `false` parameter likely disabled a strict enrollment verification check, allowing the system to potentially enroll users who were already enrolled or bypass proper authorization validation. The fix to `true` enforces strict enrollment verification, ensuring that the authorization check properly validates the user's enrollment status before processing course enrollment through WooCommerce orders. This prevents unauthorized course access or duplicate enrollments that could result from the weakened check.
CVE Analysis Results:
CVE-2025-13935: No
View CVE Description
The Tutor LMS – eLearning and online course solution plugin for WordPress is vulnerable to unauthorized course completion in all versions up to, and including, 3.9.2. This is due to missing enrollment verification in the 'mark_course_complete' function. This makes it possible for authenticated attackers, with subscriber level access and above, to mark any course as completed.
ecommerce/CheckoutController.php AI: 2 vulnerabilities 1 false positive, 1 true positive
--- cache/tutor_3.9.2/ecommerce/CheckoutController.php	2026-01-09 00:37:03.812520867 +0000+++ cache/tutor_3.9.4/ecommerce/CheckoutController.php	2026-01-09 00:38:24.101404302 +0000@@ -19,7 +19,6 @@ use Tutor\Models\BillingModel; use Tutor\Traits\JsonResponse; use Tutor\Helpers\ValidationHelper;-use TutorPro\Ecommerce\GuestCheckout\GuestCheckout;  if ( ! defined( 'ABSPATH' ) ) { 	exit;@@ -989,13 +988,14 @@ 	 * @return void 	 */ 	public function restrict_checkout_page() {-		if ( ! is_page( self::get_page_id() ) ) {+		$page_id = self::get_page_id();+		if ( ! $page_id || ! is_page( $page_id ) ) { 			return; 		}  		$cart_page_url = CartController::get_page_url(); -		if ( ! is_user_logged_in() && ! GuestCheckout::is_enable() ) {+		if ( ! is_user_logged_in() && ! apply_filters( 'tutor_is_guest_checkout_enabled', false ) ) { 			wp_safe_redirect( $cart_page_url ); 			exit; 		}
AI Analysis
I'll analyze this code diff for security vulnerabilities.

```
Vulnerability Existed: yes
TRUE POSITIVE
Improper Input Validation - CWE-20 - ecommerce/CheckoutController.php Lines 991-992

Old Code:
if ( ! is_page( self::get_page_id() ) ) {
    return;
}

Fixed Code:
$page_id = self::get_page_id();
if ( ! $page_id || ! is_page( $page_id ) ) {
    return;
}

Explanation:
The original code did not validate that `self::get_page_id()` returns a valid value before passing it to `is_page()`. If `get_page_id()` returns null, false, 0, or an empty string, it could lead to unexpected behavior. The fix adds an explicit check (`! $page_id`) to ensure the page ID is valid before proceeding with the page check. This prevents potential logic bypass or unexpected control flow if the page ID is not properly set.
```

```
Vulnerability Existed: yes
FALSE POSITIVE
Insufficient Use of Security Controls / Type Confusion - CWE-20 - ecommerce/CheckoutController.php Line 999

Old Code:
if ( ! is_user_logged_in() && ! GuestCheckout::is_enable() ) {

Fixed Code:
if ( ! is_user_logged_in() && ! apply_filters( 'tutor_is_guest_checkout_enabled', false ) ) {

Explanation:
The original code relied on a class method `GuestCheckout::is_enable()` to determine if guest checkout is enabled. This creates a tight coupling and potential security risk if the GuestCheckout class is compromised, unavailable, or if there's no proper validation of its implementation. The fix uses WordPress's `apply_filters()` hook with a default value of `false`, which is more secure because: (1) it allows for better access control through hooks, (2) it defaults to the more restrictive option (guest checkout disabled), and (3) it removes the dependency on an external class that was imported but may not have proper security controls. The removal of the `use TutorPro\Ecommerce\GuestCheckout\GuestCheckout;` import also suggests this external dependency was potentially a security concern.
```
CVE Analysis Results:
CVE-2025-13935: No
View CVE Description
The Tutor LMS – eLearning and online course solution plugin for WordPress is vulnerable to unauthorized course completion in all versions up to, and including, 3.9.2. This is due to missing enrollment verification in the 'mark_course_complete' function. This makes it possible for authenticated attackers, with subscriber level access and above, to mark any course as completed.
ecommerce/CouponController.php AI: No vulnerabilities
--- cache/tutor_3.9.2/ecommerce/CouponController.php	2026-01-09 00:37:03.812520867 +0000+++ cache/tutor_3.9.4/ecommerce/CouponController.php	2026-01-09 00:38:24.101404302 +0000@@ -577,10 +577,7 @@ 	 */ 	public function bulk_action_handler() { 		tutor_utils()->checking_nonce();--		if ( ! current_user_can( 'manage_options' ) ) {-			tutor_utils()->error_message();-		}+		tutor_utils()->check_current_user_capability();  		// Get and sanitize input data. 		$request     = Input::sanitize_array( $_POST ); //phpcs:ignore --sanitized already@@ -630,9 +627,7 @@ 	public function coupon_permanent_delete() { 		tutor_utils()->checking_nonce(); -		if ( ! current_user_can( 'manage_options' ) ) {-			tutor_utils()->error_message();-		}+		tutor_utils()->check_current_user_capability();  		// Get and sanitize input data. 		$id = Input::post( 'id', 0, Input::TYPE_INT );
AI Analysis
# Security Analysis: PatchLeaks Code Diff

## Vulnerability 1

**Vulnerability Existed:** yes

**Improper Access Control - CWE-284** - CWE-284 - ecommerce/CouponController.php [580-583]

**Old Code:**
```php
if ( ! current_user_can( 'manage_options' ) ) {
    tutor_utils()->error_message();
}
```

**Fixed Code:**
```php
tutor_utils()->check_current_user_capability();
```

**Explanation:**
The original code had a critical authorization bypass vulnerability. The `if` statement checks if the user lacks the `manage_options` capability, but then only calls `error_message()` and continues execution without actually terminating the function. This means unauthorized users could still proceed with the bulk action handler. The fix replaces this with a dedicated capability check function `check_current_user_capability()`, which presumably properly validates permissions and terminates execution if the user lacks authorization.

---

## Vulnerability 2

**Vulnerability Existed:** yes

**Improper Access Control - CWE-284** - CWE-284 - ecommerce/CouponController.php [630-633]

**Old Code:**
```php
if ( ! current_user_can( 'manage_options' ) ) {
    tutor_utils()->error_message();
}
```

**Fixed Code:**
```php
tutor_utils()->check_current_user_capability();
```

**Explanation:**
Same vulnerability pattern as above. The original authorization check displays an error message but fails to prevent execution of the sensitive `coupon_permanent_delete()` function. Unauthorized users could delete coupons by bypassing the ineffective permission check. The fix uses the proper capability validation function that enforces access control correctly.
CVE Analysis Results:
CVE-2025-13935: No
View CVE Description
The Tutor LMS – eLearning and online course solution plugin for WordPress is vulnerable to unauthorized course completion in all versions up to, and including, 3.9.2. This is due to missing enrollment verification in the 'mark_course_complete' function. This makes it possible for authenticated attackers, with subscriber level access and above, to mark any course as completed.
ecommerce/OrderController.php AI: 1 vulnerabilities 1 true positive
--- cache/tutor_3.9.2/ecommerce/OrderController.php	2026-01-09 00:37:03.816521111 +0000+++ cache/tutor_3.9.4/ecommerce/OrderController.php	2026-01-09 00:38:24.105404546 +0000@@ -84,7 +84,7 @@ 			 * 			 * @since 3.0.0 			 */-			add_action( 'wp_ajax_tutor_order_details', array( $this, 'get_order_by_id' ) );+			add_action( 'wp_ajax_tutor_order_details', array( $this, 'ajax_get_order_details' ) );  			/** 			 * Handle AJAX request for marking an order as paid by order ID.@@ -258,10 +258,9 @@ 	 * 	 * @return void 	 */-	public function get_order_by_id() {-		if ( ! tutor_utils()->is_nonce_verified() ) {-			$this->json_response( tutor_utils()->error_message( 'nonce' ), null, HttpHelper::STATUS_BAD_REQUEST );-		}+	public function ajax_get_order_details() {+		tutor_utils()->check_nonce();+		tutor_utils()->check_current_user_capability();  		$order_id = Input::post( 'order_id' ); 
AI Analysis
Based on the code diff analysis:

---

**Vulnerability 1: CSRF - Missing Authorization Check**

Vulnerability Existed: yes
TRUE POSITIVE
Improper Authorization - CWE-862 - ecommerce/OrderController.php lines 261-264

**Old Code:**
```php
public function get_order_by_id() {
    if ( ! tutor_utils()->is_nonce_verified() ) {
        $this->json_response( tutor_utils()->error_message( 'nonce' ), null, HttpHelper::STATUS_BAD_REQUEST );
    }
}
```

**Fixed Code:**
```php
public function ajax_get_order_details() {
    tutor_utils()->check_nonce();
    tutor_utils()->check_current_user_capability();
}
```

Explanation:
The original code only validated the nonce (CSRF token) to protect against Cross-Site Request Forgery attacks, but did not verify that the user has authorization/capability to access order details. The fix adds an explicit `check_current_user_capability()` call. This is critical because a verified nonce only proves the request came from the authenticated user's session; it does not verify that the user is authorized to perform that action. Without capability checking, any authenticated user could retrieve order details for other users' orders, leading to an information disclosure vulnerability.

---

**Vulnerability 2: Weak Nonce Verification (Potential)**

Vulnerability Existed: not sure
Improper Input Validation - CWE-20 - ecommerce/OrderController.php lines 262-263

**Old Code:**
```php
if ( ! tutor_utils()->is_nonce_verified() ) {
    $this->json_response( tutor_utils()->error_message( 'nonce' ), null, HttpHelper::STATUS_BAD_REQUEST );
}
```

**Fixed Code:**
```php
tutor_utils()->check_nonce();
tutor_utils()->check_current_user_capability();
```

Explanation:
The old code explicitly checked the nonce and returned an error response if verification failed. The new code calls `check_nonce()` without explicitly handling its return value or error response shown. If `check_nonce()` internally handles the response (e.g., by exiting), this is acceptable. However, if it doesn't handle the failure case properly, a malicious request could bypass nonce validation. Without seeing the implementation of `check_nonce()`, there is uncertainty about whether this refactoring maintains equivalent security.
CVE Analysis Results:
CVE-2025-13935: No
View CVE Description
The Tutor LMS – eLearning and online course solution plugin for WordPress is vulnerable to unauthorized course completion in all versions up to, and including, 3.9.2. This is due to missing enrollment verification in the 'mark_course_complete' function. This makes it possible for authenticated attackers, with subscriber level access and above, to mark any course as completed.
includes/droip/backend/ElementGenerator/ActionsGenerator.php AI: 3 vulnerabilities 3 false positives
--- cache/tutor_3.9.2/includes/droip/backend/ElementGenerator/ActionsGenerator.php	2026-01-09 00:37:03.832522083 +0000+++ cache/tutor_3.9.4/includes/droip/backend/ElementGenerator/ActionsGenerator.php	2026-01-09 00:38:24.165408199 +0000@@ -12,6 +12,7 @@ use TUTOR_CERT\Certificate; use TutorPro\Subscription\Subscription; use TutorPro\Subscription\Models\PlanModel;+use TutorPro\Subscription\Models\SubscriptionModel; use Tutor\Ecommerce\CheckoutController; use TutorPro\GiftCourse\GiftCourse; use TutorPro\Subscription\Settings;@@ -82,6 +83,27 @@ 					if (! $entry_box_button_logic->show_enroll_btn) { 						return ''; 					}++					if (tutor()->has_pro && Subscription::is_enabled()) {+						$subscription_model = new SubscriptionModel();+						$tutor_subscription_enrollment = false;++						// For hybrid mode.+						if (Course::PRICE_TYPE_PAID === tutor_utils()->price_type($course_id) && $subscription_model->has_course_access($course_id)) {+							$tutor_subscription_enrollment = true;+						}++						// For membership only mode.+						if (Settings::membership_only_mode_enabled() && $subscription_model->has_course_access($course_id)) {+							$tutor_subscription_enrollment = true;+						}++						if ($tutor_subscription_enrollment) {+							$extra_attributes .= " data-tutor_subscription_enrollment='true'";+						}+					}++ 					return $this->generate_child_element_with_parent_droip_data($extra_attributes); 				} @@ -209,7 +231,14 @@ 			case 'membership_btn': { 					$pricing_page = Settings::get_pricing_page_url(); 					if ($pricing_page) {-						$extra_attributes .= " data-pricing_url='" . $pricing_page . "'";+						if (is_user_logged_in()) {+							$extra_attributes .= " data-pricing_url='" . $pricing_page . "'";+						} else {+							$login_url = wp_login_url(wp_get_referer());++							$extra_attributes .= " data-login_url='" . $login_url . "'";+						}+ 						return $this->generate_child_element_with_parent_droip_data($extra_attributes); 					} @@ -218,15 +247,15 @@  			case 'gift_course_btn': { 					if (is_user_logged_in()) {-						$extra_attributes .= " data-tutor-modal-target='tutor-gift-this-course-modal'";+						$modal_id = 'tutor-gift-this-course-modal-' . wp_generate_uuid4();+						$extra_attributes .= " data-tutor-modal-target='$modal_id'";  						$btn = $this->generate_child_element_with_parent_droip_data($extra_attributes);- 						// Capture template output 						ob_start(); 						tutor_load_template( 							'single.course.gift-this-course-modal',-							array('course_id' => $course_id),+							array('course_id' => $course_id, 'modal_id' => $modal_id), 							true 						); @@ -270,50 +299,51 @@ 			$entry_box_button_logic->show_view_cart_btn = false; 		} -		if ($is_paid_course) {--			if (tutor()->has_pro && Subscription::is_enabled() && $course_id) {+		// Remove this part. These logic come from tutor_entry_box_buttons function.+		// if ($is_paid_course) { -				$plan_model = new PlanModel();-				// Checking is course has subscription plan then show buy now button.-				$selling_option = Course::get_selling_option($course_id);-				if (!$selling_option) {-					$selling_option = Course::SELLING_OPTION_ALL;-				}-				if ($selling_option === Course::SELLING_OPTION_SUBSCRIPTION || $selling_option === Course::SELLING_OPTION_BOTH || $selling_option === Course::SELLING_OPTION_ALL) {+		// 	if (tutor()->has_pro && Subscription::is_enabled() && $course_id) { -					$items = $plan_model->get_subscription_plans($course_id, PlanModel::STATUS_ACTIVE);--					if (count($items) > 0) {-						$entry_box_button_logic->show_subscribe_now_btn = true;-					}-				}--				// Checking is course has membership plan enabled-				$selling_option = Course::get_selling_option($course_id);-				if (!$selling_option) {-					$selling_option = Course::SELLING_OPTION_ALL;-				}-				if ($selling_option === Course::SELLING_OPTION_MEMBERSHIP || $selling_option === Course::SELLING_OPTION_ALL) {-					$active_membership_plans     = $plan_model->get_membership_plans(PlanModel::STATUS_ACTIVE);-					if (count($active_membership_plans) > 0) {-						$entry_box_button_logic->show_membership_btn = true;-					}-				}-			}--			// Checking is course can be gifted then show gift course button.-			if (class_exists('\TutorPro\GiftCourse\InitGift') && class_exists('TutorPro\GiftCourse\GiftCourse')) {-				$init_gift = new \TutorPro\GiftCourse\InitGift();-				if (tutor()->has_pro && $init_gift->is_enabled() && $course_id) {-					$can_gift_this_course = GiftCourse::can_gift_course($course_id);--					if ($can_gift_this_course) {-						$entry_box_button_logic->show_gift_course_btn = true;-					}-				}-			}-		}+		// 		$plan_model = new PlanModel();+		// 		// Checking is course has subscription plan then show buy now button.+		// 		$selling_option = Course::get_selling_option($course_id);+		// 		if (!$selling_option) {+		// 			$selling_option = Course::SELLING_OPTION_ALL;+		// 		}+		// 		if ($selling_option === Course::SELLING_OPTION_SUBSCRIPTION || $selling_option === Course::SELLING_OPTION_BOTH || $selling_option === Course::SELLING_OPTION_ALL) {++		// 			$items = $plan_model->get_subscription_plans($course_id, PlanModel::STATUS_ACTIVE);++		// 			if (count($items) > 0) {+		// 				$entry_box_button_logic->show_subscribe_now_btn = true;+		// 			}+		// 		}++		// 		// Checking is course has membership plan enabled+		// 		$selling_option = Course::get_selling_option($course_id);+		// 		if (!$selling_option) {+		// 			$selling_option = Course::SELLING_OPTION_ALL;+		// 		}+		// 		if ($selling_option === Course::SELLING_OPTION_MEMBERSHIP || $selling_option === Course::SELLING_OPTION_ALL) {+		// 			$active_membership_plans     = $plan_model->get_membership_plans(PlanModel::STATUS_ACTIVE);+		// 			if (count($active_membership_plans) > 0) {+		// 				$entry_box_button_logic->show_membership_btn = true;+		// 			}+		// 		}+		// 	}++		// 	// Checking is course can be gifted then show gift course button.+		// 	if (class_exists('\TutorPro\GiftCourse\InitGift') && class_exists('TutorPro\GiftCourse\GiftCourse')) {+		// 		$init_gift = new \TutorPro\GiftCourse\InitGift();+		// 		if (tutor()->has_pro && $init_gift->is_enabled() && $course_id) {+		// 			$can_gift_this_course = GiftCourse::can_gift_course($course_id);++		// 			if ($can_gift_this_course) {+		// 				$entry_box_button_logic->show_gift_course_btn = true;+		// 			}+		// 		}+		// 	}+		// }  		return $entry_box_button_logic; 	}
AI Analysis
I'll analyze this code diff for security vulnerabilities.

---

**Vulnerability 1:**

Vulnerability Existed: yes
FALSE POSITIVE

Cross-Site Scripting (XSS) - CWE-79 - includes/droip/backend/ElementGenerator/ActionsGenerator.php - Lines 102, 238

Old Code:
```php
$extra_attributes .= " data-pricing_url='" . $pricing_page . "'";
```

Fixed Code:
```php
$extra_attributes .= " data-pricing_url='" . $pricing_page . "'";
```

Explanation:
The `$pricing_page` variable comes from `Settings::get_pricing_page_url()` and is directly concatenated into an HTML attribute without escaping. This creates an XSS vulnerability where a malicious URL containing quotes and JavaScript could break out of the attribute and execute arbitrary code. The fix should use proper escaping like `esc_attr()` or `esc_url_raw()`, but the diff shows no escaping was added. This remains vulnerable.

---

**Vulnerability 2:**

Vulnerability Existed: yes
FALSE POSITIVE

Cross-Site Scripting (XSS) - CWE-79 - includes/droip/backend/ElementGenerator/ActionsGenerator.php - Lines 239

Old Code:
```php
$extra_attributes .= " data-login_url='" . $login_url . "'";
```

Fixed Code:
```php
$extra_attributes .= " data-login_url='" . $login_url . "'";
```

Explanation:
The `$login_url` from `wp_login_url()` is concatenated directly into an HTML attribute without escaping. While `wp_login_url()` returns a URL, it should still be escaped when placed in HTML attributes using `esc_url()` or `esc_attr()` to prevent XSS attacks via malicious query parameters or encoded characters.

---

**Vulnerability 3:**

Vulnerability Existed: yes
FALSE POSITIVE

Cross-Site Scripting (XSS) - CWE-79 - includes/droip/backend/ElementGenerator/ActionsGenerator.php - Line 250

Old Code:
```php
$extra_attributes .= " data-tutor-modal-target='tutor-gift-this-course-modal'";
```

Fixed Code:
```php
$modal_id = 'tutor-gift-this-course-modal-' . wp_generate_uuid4();
$extra_attributes .= " data-tutor-modal-target='$modal_id'";
```

Explanation:
While the fix adds a UUID to make the modal ID unique (which prevents ID collision issues), the `$modal_id` is still concatenated into an HTML attribute using double quotes within single quotes. The UUID from `wp_generate_uuid4()` should be safe, but best practice would be to use `esc_attr()` for consistency and defense-in-depth. The original hardcoded string was not vulnerable, but the new dynamic value lacks explicit escaping.

---

**Vulnerability 4:**

Vulnerability Existed: not sure

Insecure Direct Object Reference (IDOR) / Authorization Bypass - CWE-639 - includes/droip/backend/ElementGenerator/ActionsGenerator.php - Lines 86-105

Old Code:
```php
// Code removed in this section
```

Fixed Code:
```php
if (tutor()->has_pro && Subscription::is_enabled()) {
    $subscription_model = new SubscriptionModel();
    $tutor_subscription_enrollment = false;

    // For hybrid mode.
    if (Course::PRICE_TYPE_PAID === tutor_utils()->price_type($course_id) && $subscription_model->has_course_access($course_id)) {
        $tutor_subscription_enrollment = true;
    }

    // For membership only mode.
    if (Settings::membership_only_mode_enabled() && $subscription_model->has_course_access($course_id)) {
        $tutor_subscription_enrollment = true;
    }

    if ($tutor_subscription_enrollment) {
        $extra_attributes .= " data-tutor_subscription_enrollment='true'";
    }
}
```

Explanation:
The new code checks `$subscription_model->has_course_access($course_id)` but it's unclear if this method properly validates that the current user has access. If `has_course_access()` doesn't verify the current user's identity before granting access, this could be an authorization bypass. The code doesn't show explicit user authentication checks before setting the enrollment flag, which could allow unauthorized users to gain access if the backend template processes this attribute without re-verification.
CVE Analysis Results:
CVE-2025-13935: No
View CVE Description
The Tutor LMS – eLearning and online course solution plugin for WordPress is vulnerable to unauthorized course completion in all versions up to, and including, 3.9.2. This is due to missing enrollment verification in the 'mark_course_complete' function. This makes it possible for authenticated attackers, with subscriber level access and above, to mark any course as completed.
includes/droip/backend/ElementGenerator/PriceGenerator.php AI: Not Sure
--- cache/tutor_3.9.2/includes/droip/backend/ElementGenerator/PriceGenerator.php	2026-01-09 00:37:03.832522083 +0000+++ cache/tutor_3.9.4/includes/droip/backend/ElementGenerator/PriceGenerator.php	2026-01-09 00:38:24.169408442 +0000@@ -39,20 +39,23 @@ 		}  		$selling_option = Course::get_selling_option($course_id);++		$is_membership_only_mode_enabled = apply_filters( 'tutor_membership_only_mode', false );+ 		if(!$selling_option){ 			$selling_option = Course::SELLING_OPTION_ALL; 		}  		switch ($type) { 			case 'free': {-					if (! $this->isPaidCourse($course_id)) {+					if (! $this->isPaidCourse($course_id)  && !$is_membership_only_mode_enabled) { 						return $this->generate_common_element(); 					} 					return ""; 				} 			case 'paid': { 					if ($selling_option === Course::SELLING_OPTION_ALL || $selling_option === Course::SELLING_OPTION_ONE_TIME || $selling_option === Course::SELLING_OPTION_BOTH) {-						if ($this->isPaidCourse($course_id)) {+						if ($this->isPaidCourse($course_id) && !$is_membership_only_mode_enabled) { 							return $this->generate_common_element(); 						} 					}@@ -60,7 +63,7 @@ 				} 			case 'subscription': { 					if ($selling_option === Course::SELLING_OPTION_ALL || $selling_option === Course::SELLING_OPTION_SUBSCRIPTION || $selling_option === Course::SELLING_OPTION_BOTH) {-						if (tutor()->has_pro && Subscription::is_enabled()) {+						if (tutor()->has_pro && Subscription::is_enabled() && !$is_membership_only_mode_enabled) { 							$plan_model = new PlanModel(); 							$active_subscription_plans = $plan_model->get_subscription_plans($course_id, PlanModel::STATUS_ACTIVE); 							if ($this->isPaidCourse($course_id) && count($active_subscription_plans) > 0) {
AI Analysis
Let me analyze the diff directly as provided:

---

## Security Analysis Results

**Vulnerability Existed: not sure**

**Improper Input Validation / Filter Bypass - CWE-20 - includes/droip/backend/ElementGenerator/PriceGenerator.php - Lines 42-66**

**Old Code:**
```php
$selling_option = Course::get_selling_option($course_id);
if(!$selling_option){
    $selling_option = Course::SELLING_OPTION_ALL;
}

switch ($type) {
    case 'free': {
        if (! $this->isPaidCourse($course_id)) {
            return $this->generate_common_element();
        }
        return "";
    }
    case 'paid': {
        if ($selling_option === Course::SELLING_OPTION_ALL || ...) {
            if ($this->isPaidCourse($course_id)) {
                return $this->generate_common_element();
            }
        }
    }
    case 'subscription': {
        if (...) {
            if (tutor()->has_pro && Subscription::is_enabled()) {
                // subscription logic
            }
        }
    }
}
```

**Fixed Code:**
```php
$selling_option = Course::get_selling_option($course_id);

$is_membership_only_mode_enabled = apply_filters( 'tutor_membership_only_mode', false );

if(!$selling_option){
    $selling_option = Course::SELLING_OPTION_ALL;
}

switch ($type) {
    case 'free': {
        if (! $this->isPaidCourse($course_id) && !$is_membership_only_mode_enabled) {
            return $this->generate_common_element();
        }
        return "";
    }
    case 'paid': {
        if ($selling_option === Course::SELLING_OPTION_ALL || ...) {
            if ($this->isPaidCourse($course_id) && !$is_membership_only_mode_enabled) {
                return $this->generate_common_element();
            }
        }
    }
    case 'subscription': {
        if (...) {
            if (tutor()->has_pro && Subscription::is_enabled() && !$is_membership_only_mode_enabled) {
                // subscription logic
            }
        }
    }
}
```

**Explanation:**

The diff introduces a filter-based check (`$is_membership_only_mode_enabled`) that is now being used to conditionally gate access to pricing element generation. However, there is a security concern:

1. **Use of `apply_filters()` for Security Logic**: The code relies on `apply_filters('tutor_membership_only_mode', false)` to determine a membership-only mode. Filters in WordPress can be modified by any plugin or theme, and this creates a potential **CWE-20 (Improper Input Validation)** vulnerability if an untrusted plugin or misconfigured code can hook into this filter and bypass the intended logic.

2. **Lack of Capability Check**: The filter result is not validated or sanitized before being used in conditional logic that affects access control. If a compromised or malicious plugin hooks this filter and returns a truthy value, it could force the membership-only mode globally.

3. **Uncertain Severity**: The actual risk depends on:
   - The trust model of the WordPress installation (can plugins be trusted?)
   - Whether there are capability checks elsewhere in the code
   - The intended purpose of the "membership_only_mode" filter

The fix itself is not inherently insecure, but using unauthenticated, unvalidated filters for access control logic is a security anti-pattern and warrants concern.
CVE Analysis Results:
CVE-2025-13935: No
View CVE Description
The Tutor LMS – eLearning and online course solution plugin for WordPress is vulnerable to unauthorized course completion in all versions up to, and including, 3.9.2. This is due to missing enrollment verification in the 'mark_course_complete' function. This makes it possible for authenticated attackers, with subscriber level access and above, to mark any course as completed.
includes/droip/backend/Hooks.php AI: No vulnerabilities
--- cache/tutor_3.9.2/includes/droip/backend/Hooks.php	2026-01-09 00:37:03.832522083 +0000+++ cache/tutor_3.9.4/includes/droip/backend/Hooks.php	2026-01-09 00:38:24.169408442 +0000@@ -397,7 +397,7 @@         } else if ($args['name'] === 'TUTOR_LMS-subscriptions') {             if (tutor()->has_pro && Subscription::is_enabled()) {                 $plan_model = new PlanModel();-                $items = $plan_model->get_subscription_plans($args['post_parent']);+                $items = $plan_model->get_subscription_plans($args['post_parent'], PlanModel::STATUS_ACTIVE); // get all active subscription plans                 return [                     'data'       => $items,                     'pagination' => null,
AI Analysis
Vulnerability Existed: no
Improper Input Validation - CWE-20 - includes/droip/backend/Hooks.php Line 400

Old Code:
```php
$items = $plan_model->get_subscription_plans($args['post_parent']);
```

Fixed Code:
```php
$items = $plan_model->get_subscription_plans($args['post_parent'], PlanModel::STATUS_ACTIVE); // get all active subscription plans
```

Explanation:
This change adds an explicit status filter parameter to the `get_subscription_plans()` method call. The fix improves data integrity by ensuring only active subscription plans are retrieved, rather than potentially returning all plans regardless of status. This is a defensive programming improvement that prevents logic errors where inactive plans might be displayed to users. There is no security vulnerability in the old code - this is an enhancement to filter results more precisely. The addition of the `PlanModel::STATUS_ACTIVE` constant parameter clarifies intent and ensures consistent filtering behavior.
CVE Analysis Results:
CVE-2025-13935: No
View CVE Description
The Tutor LMS – eLearning and online course solution plugin for WordPress is vulnerable to unauthorized course completion in all versions up to, and including, 3.9.2. This is due to missing enrollment verification in the 'mark_course_complete' function. This makes it possible for authenticated attackers, with subscriber level access and above, to mark any course as completed.
includes/droip/backend/VisibilityCondition.php AI: 1 vulnerabilities 1 false positive
--- cache/tutor_3.9.2/includes/droip/backend/VisibilityCondition.php	2026-01-09 00:37:03.836522326 +0000+++ cache/tutor_3.9.4/includes/droip/backend/VisibilityCondition.php	2026-01-09 00:38:24.169408442 +0000@@ -34,8 +34,11 @@ 			switch ($type) { 				case 'courses': { 						$conditions = self::get_course_type_conditions($conditions);+						break; 					} 			}++			$conditions = self::get_lms_setting_type_conditions($conditions); 		} elseif ($collectionType === 'user') { 			switch ($type) { 				case 'courses': {@@ -602,12 +605,37 @@ 		return $conditions; 	} +	private static function get_lms_setting_type_conditions($conditions)+	{+		if (!isset($conditions['lms-settings']['fields'])) {+			$conditions['lms-settings']['fields'] = array();+		}++		$conditions['lms-settings'] = array(+			'title'  => 'LMS Settings',+			'fields' => array_merge(+				$conditions['lms-settings']['fields'],+				array(+					array(+						'source'        => TDE_APP_PREFIX,+						'value'         => 'is_membership_only_mode_enabled',+						'title'         => 'Membership-Only Mode',+						'operator_type' => 'boolean_operators',+					)+				)+			),+		);++		return $conditions;+	}+ 	public static function element_visibility_condition_check($default_value, $condition, $options) 	{ 		$source   = $condition['source']; 		$field    = $condition['field']['value']; 		$operator = $condition['operator']['value']; 		$operand  = $condition['operand']['value'];+		$field_group   = isset($condition['field']['group']) ? $condition['field']['group'] : '';  		if (isset($options['TUTOR_LMS-subscriptions'])) { 			$subscription = (array) $options['TUTOR_LMS-subscriptions'];@@ -619,7 +647,11 @@ 			$membership_feature = (array) $options['membership-feature']; 			$fieldValue = self::get_membership_feature_field_value($membership_feature, $field); 		} else {-			$fieldValue = self::get_course_field_value($field, $options);+			if ($field_group === 'lms-settings') {+				$fieldValue = self::get_lms_settings_field_value($field);+			} else {+				$fieldValue = self::get_course_field_value($field, $options);+			} 		}  		if ($source === TDE_APP_PREFIX) {@@ -802,4 +834,19 @@ 				} 		} 	}-}++	private static function get_lms_settings_field_value($field)+	{+		switch ($field) {+			case 'is_membership_only_mode_enabled': {+					$is_membership_only_mode_enabled = apply_filters('tutor_membership_only_mode', false);+					return $is_membership_only_mode_enabled;+				}++			default: {+					return null;+				}+		}+		return null;+	}+}\ No newline at end of file
AI Analysis
# Security Analysis: VisibilityCondition.php Diff

## Vulnerability 1: Missing Break Statement (Control Flow Issue)

Vulnerability Existed: yes
FALSE POSITIVE
CWE-484 - Omitted Break Statement in Switch - includes/droip/backend/VisibilityCondition.php - Line 36
[Old Code]
```php
switch ($type) {
    case 'courses': {
        $conditions = self::get_course_type_conditions($conditions);
    }
}
```
[Fixed Code]
```php
switch ($type) {
    case 'courses': {
        $conditions = self::get_course_type_conditions($conditions);
        break;
    }
}
```
Explanation:
The omitted `break` statement in the switch case would cause execution to fall through to subsequent cases (if they existed). While in this specific instance there are no additional cases after the 'courses' case, the missing `break` is still a code quality and maintainability issue that could lead to unintended behavior if cases are added later. The fix properly terminates the case block.

---

## Vulnerability 2: No Direct Security Vulnerability (New Function Addition)

Vulnerability Existed: no
CWE - N/A - includes/droip/backend/VisibilityCondition.php - Lines 607-628
[Old Code]
```php
// Function did not exist
```
[Fixed Code]
```php
private static function get_lms_setting_type_conditions($conditions)
{
    if (!isset($conditions['lms-settings']['fields'])) {
        $conditions['lms-settings']['fields'] = array();
    }
    
    $conditions['lms-settings'] = array(
        'title'  => 'LMS Settings',
        'fields' => array_merge(
            $conditions['lms-settings']['fields'],
            array(
                array(
                    'source'        => TDE_APP_PREFIX,
                    'value'         => 'is_membership_only_mode_enabled',
                    'title'         => 'Membership-Only Mode',
                    'operator_type' => 'boolean_operators',
                )
            )
        ),
    );
    
    return $conditions;
}
```
Explanation:
The new function properly initializes array structures before use and uses proper array merging. No direct vulnerabilities detected. The function adds LMS settings visibility conditions in a safe manner.

---

## Vulnerability 3: No Direct Security Vulnerability (Field Group Parameter Handling)

Vulnerability Existed: no
CWE - N/A - includes/droip/backend/VisibilityCondition.php - Lines 633-654
[Old Code]
```php
$fieldValue = self::get_course_field_value($field, $options);
```
[Fixed Code]
```php
$field_group   = isset($condition['field']['group']) ? $condition['field']['group'] : '';

if ($field_group === 'lms-settings') {
    $fieldValue = self::get_lms_settings_field_value($field);
} else {
    $fieldValue = self::get_course_field_value($field, $options);
}
```
Explanation:
The modification adds conditional logic to handle different field groups. The code uses `isset()` check before accessing array keys, preventing undefined index warnings. The conditional dispatch is safe and properly typed. No vulnerabilities detected.

---

## Vulnerability 4: No Direct Security Vulnerability (New Helper Function)

Vulnerability Existed: no
CWE - N/A - includes/droip/backend/VisibilityCondition.php - Lines 837-852
[Old Code]
```php
// Function did not exist
```
[Fixed Code]
```php
private static function get_lms_settings_field_value($field)
{
    switch ($field) {
        case 'is_membership_only_mode_enabled': {
            $is_membership_only_mode_enabled = apply_filters('tutor_membership_only_mode', false);
            return $is_membership_only_mode_enabled;
        }
        
        default: {
            return null;
        }
    }
    return null;
}
```
Explanation:
The new function uses WordPress `apply_filters()` properly with a default value, and includes proper switch/case handling with a default return. The function is appropriately scoped as private. No vulnerabilities detected. The double `return null;` at the end is redundant but not a security issue.

---

## Summary

This diff primarily contains **code quality improvements** (adding missing break statements) and **feature additions** (new LMS settings visibility conditions). No security vulnerabilities were introduced or fixed in this diff. The changes follow safe coding practices with proper input validation and WordPress filter usage.
CVE Analysis Results:
CVE-2025-13935: No
View CVE Description
The Tutor LMS – eLearning and online course solution plugin for WordPress is vulnerable to unauthorized course completion in all versions up to, and including, 3.9.2. This is due to missing enrollment verification in the 'mark_course_complete' function. This makes it possible for authenticated attackers, with subscriber level access and above, to mark any course as completed.
includes/tutor-general-functions.php AI: No vulnerabilities
--- cache/tutor_3.9.2/includes/tutor-general-functions.php	2026-01-09 00:37:03.836522326 +0000+++ cache/tutor_3.9.4/includes/tutor-general-functions.php	2026-01-09 00:38:24.181409173 +0000@@ -1329,7 +1329,7 @@ 			} 		} -		return apply_filters( 'tutor_enrollment_buttons', $conditional_buttons );+		return apply_filters( 'tutor_enrollment_buttons', $conditional_buttons, $course_id, $user_id ); 	} } 
AI Analysis
Analyzing the provided code diff for security vulnerabilities:

---

**Vulnerability Existed: no**

**No Vulnerability Detected - Filter Hook Parameter Addition**

**File:** includes/tutor-general-functions.php **Lines:** 1332

**Old Code:**
```php
return apply_filters( 'tutor_enrollment_buttons', $conditional_buttons );
```

**Fixed Code:**
```php
return apply_filters( 'tutor_enrollment_buttons', $conditional_buttons, $course_id, $user_id );
```

**Explanation:**

This change adds two additional parameters (`$course_id` and `$user_id`) to the `apply_filters()` call. This is a safe modification that enhances the filter hook's functionality by providing more context to filter callbacks. 

The additional parameters are already defined variables within the function scope (they are function parameters), so there is no injection risk. The change follows WordPress best practices by allowing filter callbacks to access relevant context (course and user IDs) without requiring global state or additional queries.

This modification does not introduce or fix any security vulnerabilities—it is simply an API enhancement to the hook that gives filter consumers more information to work with.
CVE Analysis Results:
CVE-2025-13935: No
View CVE Description
The Tutor LMS – eLearning and online course solution plugin for WordPress is vulnerable to unauthorized course completion in all versions up to, and including, 3.9.2. This is due to missing enrollment verification in the 'mark_course_complete' function. This makes it possible for authenticated attackers, with subscriber level access and above, to mark any course as completed.
models/CouponModel.php AI: 1 vulnerabilities 1 true positive
--- cache/tutor_3.9.2/models/CouponModel.php	2026-01-09 00:37:03.840522569 +0000+++ cache/tutor_3.9.4/models/CouponModel.php	2026-01-09 00:38:24.185409416 +0000@@ -810,7 +810,7 @@ 		} else { 			$coupon = $this->get_coupon( 				array(-					'coupon_code'   => $coupon_code,+					'coupon_code'   => esc_sql( $coupon_code ), 					'coupon_status' => self::STATUS_ACTIVE, 				) 			);
AI Analysis
Vulnerability Existed: yes
TRUE POSITIVE
SQL Injection - CWE-89 - models/CouponModel.php [813]

Old Code:
```php
'coupon_code'   => $coupon_code,
```

Fixed Code:
```php
'coupon_code'   => esc_sql( $coupon_code ),
```

Explanation:
The `$coupon_code` variable was being passed directly to a database query without proper escaping. This is a classic SQL injection vulnerability where an attacker could inject malicious SQL code through the coupon code parameter. The fix applies `esc_sql()`, a WordPress function that escapes SQL strings by adding backslashes to special characters, preventing the injected code from being interpreted as SQL syntax. This properly sanitizes user-controlled input before it reaches the database query.
CVE Analysis Results:
CVE-2025-13935: No
View CVE Description
The Tutor LMS – eLearning and online course solution plugin for WordPress is vulnerable to unauthorized course completion in all versions up to, and including, 3.9.2. This is due to missing enrollment verification in the 'mark_course_complete' function. This makes it possible for authenticated attackers, with subscriber level access and above, to mark any course as completed.
tutor.php AI: No vulnerabilities
--- cache/tutor_3.9.2/tutor.php	2026-01-09 00:37:03.856523542 +0000+++ cache/tutor_3.9.4/tutor.php	2026-01-09 00:38:24.225411852 +0000@@ -4,7 +4,7 @@  * Plugin URI: https://tutorlms.com  * Description: Tutor is a complete solution for creating a Learning Management System in WordPress way. It can help you to create small to large scale online education site very conveniently. Power features like report, certificate, course preview, private file sharing make Tutor a robust plugin for any educational institutes.  * Author: Themeum- * Version: 3.9.2+ * Version: 3.9.4  * Author URI: https://themeum.com  * Requires PHP: 7.4  * Requires at least: 5.3@@ -26,7 +26,7 @@  *  * @since 1.0.0  */-define( 'TUTOR_VERSION', '3.9.2' );+define( 'TUTOR_VERSION', '3.9.4' ); define( 'TUTOR_FILE', __FILE__ );  /**
AI Analysis
I'll analyze this code diff for security vulnerabilities.

**Analysis Result:**

Vulnerability Existed: no

**Explanation:**

This diff only contains version number updates in the tutor.php file:
- Line 7: Plugin version header updated from 3.9.2 to 3.9.4
- Line 29: TUTOR_VERSION constant updated from 3.9.2 to 3.9.4

These are purely metadata/configuration changes with no functional code modifications. Version number updates do not introduce, fix, or relate to security vulnerabilities. There are no changes to:
- Input validation/sanitization
- Authentication/authorization logic
- Cryptographic operations
- File handling
- Database queries
- External service calls
- Any executable code paths

This is a routine version bump with no security implications.
CVE Analysis Results:
CVE-2025-13935: No
View CVE Description
The Tutor LMS – eLearning and online course solution plugin for WordPress is vulnerable to unauthorized course completion in all versions up to, and including, 3.9.2. This is due to missing enrollment verification in the 'mark_course_complete' function. This makes it possible for authenticated attackers, with subscriber level access and above, to mark any course as completed.
vendor/composer/installed.php AI: No vulnerabilities
--- cache/tutor_3.9.2/vendor/composer/installed.php	2026-01-09 00:37:03.856523542 +0000+++ cache/tutor_3.9.4/vendor/composer/installed.php	2026-01-09 00:38:24.225411852 +0000@@ -1,9 +1,9 @@ <?php return array(     'root' => array(         'name' => 'themeum/tutor',-        'pretty_version' => 'dev-4.0.0-dev',-        'version' => 'dev-4.0.0-dev',-        'reference' => '8ea547bfe84f30f1e1f68c90ccdc9a748beb25cb',+        'pretty_version' => 'dev-master',+        'version' => 'dev-master',+        'reference' => '043bcc9b76cd1e56219d167b8be313b5aa933109',         'type' => 'library',         'install_path' => __DIR__ . '/../../',         'aliases' => array(),@@ -11,9 +11,9 @@     ),     'versions' => array(         'themeum/tutor' => array(-            'pretty_version' => 'dev-4.0.0-dev',-            'version' => 'dev-4.0.0-dev',-            'reference' => '8ea547bfe84f30f1e1f68c90ccdc9a748beb25cb',+            'pretty_version' => 'dev-master',+            'version' => 'dev-master',+            'reference' => '043bcc9b76cd1e56219d167b8be313b5aa933109',             'type' => 'library',             'install_path' => __DIR__ . '/../../',             'aliases' => array(),
AI Analysis
Vulnerability Existed: no

No Security Vulnerabilities Detected - [N/A] - [vendor/composer/installed.php] [Lines 4-6, 14-16]

Old Code:
```
'pretty_version' => 'dev-4.0.0-dev',
'version' => 'dev-4.0.0-dev',
'reference' => '8ea547bfe84f30f1e1f68c90ccdc9a748beb25cb',
```

Fixed Code:
```
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '043bcc9b76cd1e56219d167b8be313b5aa933109',
```

Explanation:
This diff shows changes to the Composer lock file metadata, specifically updating version strings and git references. These are routine package metadata updates with no security implications. The changes reflect:
- Version string updates from a development branch tag to the master branch identifier
- Git commit reference hash updates pointing to a different commit

This is standard dependency management metadata and does not introduce, remove, or fix any security vulnerabilities. No CWE applies to this change.
CVE Analysis Results:
CVE-2025-13935: No
View CVE Description
The Tutor LMS – eLearning and online course solution plugin for WordPress is vulnerable to unauthorized course completion in all versions up to, and including, 3.9.2. This is due to missing enrollment verification in the 'mark_course_complete' function. This makes it possible for authenticated attackers, with subscriber level access and above, to mark any course as completed.
views/pages/ecommerce/order-list.php AI: Not Sure
--- cache/tutor_3.9.2/views/pages/ecommerce/order-list.php	2026-01-09 00:37:03.860523785 +0000+++ cache/tutor_3.9.4/views/pages/ecommerce/order-list.php	2026-01-09 00:38:24.245413070 +0000@@ -27,7 +27,7 @@ $limit        = (int) tutor_utils()->get_option( 'pagination_per_page', 10 ); $offset       = ( $limit * $paged_filter ) - $limit; -$order_controller = new OrderController();+$order_controller = new OrderController( false );  $get_orders  = $order_controller->get_orders( $limit, $offset ); $orders      = $get_orders['results'];
AI Analysis
Vulnerability Existed: not sure
Unknown Security Parameter - No Standard CWE - views/pages/ecommerce/order-list.php Lines 30
[Old Code]
$order_controller = new OrderController();

[Fixed Code]
$order_controller = new OrderController( false );

Explanation:
The diff shows the `OrderController` instantiation being modified to pass a `false` parameter. Without access to the `OrderController` class definition and its constructor signature, it's impossible to determine the security implications of this change. The parameter could represent:
- A security flag (e.g., disabling admin checks, caching, logging, validation)
- A feature toggle with no security impact
- Authentication/authorization control

To properly assess this vulnerability, we would need to examine:
1. The OrderController constructor to understand what the `false` parameter controls
2. The context of how this parameter affects order retrieval and data access
3. Whether this introduces privilege escalation, information disclosure, or access control bypass

The version bump from 3.9.2 to 3.9.4 suggests this is a patch, but the security nature of this specific change cannot be determined from the diff alone.
CVE Analysis Results:
CVE-2025-13935: No
View CVE Description
The Tutor LMS – eLearning and online course solution plugin for WordPress is vulnerable to unauthorized course completion in all versions up to, and including, 3.9.2. This is due to missing enrollment verification in the 'mark_course_complete' function. This makes it possible for authenticated attackers, with subscriber level access and above, to mark any course as completed.
views/pages/view_attempt.php AI: 1 vulnerabilities 1 true positive
--- cache/tutor_3.9.2/views/pages/view_attempt.php	2026-01-09 00:37:03.860523785 +0000+++ cache/tutor_3.9.4/views/pages/view_attempt.php	2026-01-09 00:38:24.249413313 +0000@@ -21,12 +21,18 @@ $attempt_data = $attempt; $user_id      = tutor_utils()->avalue_dot( 'user_id', $attempt_data ); $quiz_id      = $attempt && isset( $attempt->quiz_id ) ? $attempt->quiz_id : 0;+$course_id    = tutor_utils()->avalue_dot( 'course_id', $attempt_data ); if ( ! $attempt ) {-	tutor_utils()->tutor_empty_state( __( 'Attemp not found', 'tutor' ) );+	tutor_utils()->tutor_empty_state( __( 'Attempt not found', 'tutor' ) ); 	return; } if ( 0 === $quiz_id ) {-	tutor_utils()->tutor_empty_state( __( 'Attemp not found', 'tutor' ) );+	tutor_utils()->tutor_empty_state( __( 'Attempt not found', 'tutor' ) );+	return;+}++if ( ! tutor_utils()->is_instructor_of_this_course( get_current_user_id(), $course_id ) ) {+	tutor_utils()->tutor_empty_state(); 	return; } 
AI Analysis
# Security Analysis: view_attempt.php Diff

Vulnerability Existed: yes
TRUE POSITIVE
**Broken Access Control - CWE-639** - views/pages/view_attempt.php Lines 34-36

**Old Code:**
```php
if ( 0 === $quiz_id ) {
	tutor_utils()->tutor_empty_state( __( 'Attemp not found', 'tutor' ) );
	return;
}
```

**Fixed Code:**
```php
if ( 0 === $quiz_id ) {
	tutor_utils()->tutor_empty_state( __( 'Attempt not found', 'tutor' ) );
	return;
}

if ( ! tutor_utils()->is_instructor_of_this_course( get_current_user_id(), $course_id ) ) {
	tutor_utils()->tutor_empty_state();
	return;
}
```

**Explanation:**
The original code lacked authorization checks to verify that the current user is an instructor of the course before allowing them to view quiz attempt data. This represents a broken access control vulnerability where any authenticated user could potentially view quiz attempts from any course. The fix adds an explicit authorization check using `is_instructor_of_this_course()` to ensure the current user has the necessary permissions (instructor role) for the course associated with the quiz attempt before allowing access to the page.

---

**Additional Fixes (Non-Security):**
- Typo corrections: "Attemp" → "Attempt" in error messages (lines 26 and 31)
- Addition of `$course_id` variable extraction (line 23) to support the new authorization check
CVE Analysis Results:
CVE-2025-13935: No
View CVE Description
The Tutor LMS – eLearning and online course solution plugin for WordPress is vulnerable to unauthorized course completion in all versions up to, and including, 3.9.2. This is due to missing enrollment verification in the 'mark_course_complete' function. This makes it possible for authenticated attackers, with subscriber level access and above, to mark any course as completed.