REPORT / 01
Analysis Report · Folder Analysis cache/tutor_3.9.3 → cache/tutor_3.9.4 — CVE-2025-13934
Shared security patch analysis results
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
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