REPORT / 01

Analysis Report · Folder Analysis cache/tutor_3.9.3 → cache/tutor_3.9.4 — CVE-2025-13934

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-13934 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
classes/Course.php AI: 2 vulnerabilities 1 false positive, 1 true positive CVE-2025-13934
--- cache/tutor_3.9.3/classes/Course.php	2026-01-09 00:38:03.492149922 +0000+++ cache/tutor_3.9.4/classes/Course.php	2026-01-09 00:38:53.531196511 +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
# Security Analysis: classes/Course.php

## Vulnerability 1: Enrollment Bypass Prevention

Vulnerability Existed: yes
FALSE POSITIVE
**Broken Access Control - CWE-639** - classes/Course.php lines 2122-2124

**Old Code:**
```php
// No enrollment check existed before course completion
$can_complete = apply_filters( 'tutor_user_can_complete_course', true, $user_id, $course_id );
```

**Fixed Code:**
```php
if ( ! tutor_utils()->is_enrolled( $course_id, $user_id ) ) {
    die( esc_html__( 'User is not enrolled in course', 'tutor' ) );
}

$can_complete = apply_filters( 'tutor_user_can_complete_course', true, $user_id, $course_id );
```

**Explanation:**
A critical access control vulnerability existed where unauthenticated or non-enrolled users could mark a course as complete without actually being enrolled. The fix adds an enrollment verification check that terminates execution if the user is not enrolled in the course, preventing unauthorized course completion.

---

## Vulnerability 2: Paid Course Enrollment Bypass

Vulnerability Existed: yes
TRUE POSITIVE
**Broken Access Control / Improper Authorization - CWE-639** - classes/Course.php lines 3010-3020

**Old Code:**
```php
if ( $password_protected ) {
    wp_send_json_error( __( 'This course is password protected', 'tutor' ) );
}
// Directly enrolls user without checking if course is paid or user purchased it
$enroll = tutor_utils()->do_enroll( $course_id, 0, $user_id );
```

**Fixed Code:**
```php
if ( $password_protected ) {
    wp_send_json_error( __( 'This course is password protected', 'tutor' ) );
}

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:**
A significant authorization bypass vulnerability existed in the AJAX enrollment endpoint. Users could enroll in paid courses without purchasing them by directly calling the enrollment function. The fix adds a check to verify that if a course is purchasable (paid), the user must already be enrolled (which occurs automatically upon purchase). This prevents unauthorized enrollment in premium courses.
CVE Analysis Results:
CVE-2025-13934: Yes
View CVE Description
The Tutor LMS – eLearning and online course solution plugin for WordPress is vulnerable to unauthorized course enrollment in all versions up to, and including, 3.9.3. This is due to a missing capability check and purchasability validation in the `course_enrollment()` AJAX handler. This makes it possible for authenticated attackers, with subscriber level access and above, to enroll themselves in any course without going through the proper purchase flow.
Showing 1 to 1 of 1 results