Masteriyo LMS – LMS Course Builder, Quizzes & Certificates <= 2.1.8 - Missing Authorization
Description
The Masteriyo LMS – LMS Course Builder, Quizzes & Certificates plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 2.1.8. This makes it possible for unauthenticated attackers to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=2.1.8What Changed in the Fix
Changes introduced in v2.1.9
Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2026-42743 ## 1. Vulnerability Summary The **Masteriyo LMS** plugin (up to and including version 2.1.8) contains a **Missing Authorization** vulnerability. Specifically, several integration addons (Google Meet, Lemon Squeezy, Bricks, and Elementor) register action…
Show full research plan
Exploitation Research Plan - CVE-2026-42743
1. Vulnerability Summary
The Masteriyo LMS plugin (up to and including version 2.1.8) contains a Missing Authorization vulnerability. Specifically, several integration addons (Google Meet, Lemon Squeezy, Bricks, and Elementor) register actions or REST API endpoints that either lack capability checks or fail to properly verify the identity/permissions of the requester.
The most technical and impactful manifestation is likely in the Lemon Squeezy Integration Addon, where a webhook handler is registered via wp_ajax_nopriv_masteriyo_lemon_squeezy_webhook. If this handler processes order data (such as enrolling users in courses) without verifying the Lemon Squeezy signature, an unauthenticated attacker can forge payment notifications to gain unauthorized access to paid courses.
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php?action=masteriyo_lemon_squeezy_webhook - Alternative Endpoint: REST API routes under
wp-json/masteriyo/v1/(e.g.,google-meet,settings) if parent controllers lack default authorization. - HTTP Method:
POST - Authentication: None (unauthenticated).
- Payload Type: JSON (mimicking a Lemon Squeezy webhook event).
- Preconditions: The Lemon Squeezy integration must be active (or the attacker must trigger
Summary
Masteriyo LMS is vulnerable to unauthorized access due to missing and improper capability checks across several integrations. Unauthenticated attackers can spoof Lemon Squeezy payment webhooks to gain access to paid courses, while logged-in users can bypass restrictions on Google Meet content if their account role is not specifically identified as 'student'.
Vulnerable Code
/* addons/lemon-squeezy-integration/LemonSqueezyIntegrationAddon.php */ public function handle_webhook() { try { $payload = file_get_contents( 'php://input' ); $signature = $_SERVER['HTTP_X_SIGNATURE'] ?? ''; $event = json_decode( $payload, true ); if ( is_null( $event ) ) { throw new Exception( 'Event is null.', 400 ); } // Verify signature. $secret = Setting::get_webhook_secret(); $hash = hash_hmac( 'sha256', $payload, $secret ); if ( ! hash_equals( $hash, $signature ) ) { masteriyo_get_logger()->error( 'Invalid signature', array( 'source' => 'payment-lemon-squeezy' ) ); throw new Exception( 'Invalid signature.', 403 ); } --- /* addons/google-meet/RestApi/GoogleMeetController.php */ // (line 305 approx.) if ( is_user_logged_in() && masteriyo_is_current_user_student() && ! masteriyo_can_start_course( $course ) ) { return new \WP_Error( 'masteriyo_rest_cannot_start_course', __( 'Sorry, you have not bought the course.', 'learning-management-system' ), array( 'status' => rest_authorization_required_code(), ) ); }
Security Fix
@@ -305,7 +305,7 @@ return true; } - if ( is_user_logged_in() && masteriyo_is_current_user_student() && ! masteriyo_can_start_course( $course ) ) { + if ( is_user_logged_in() && ! masteriyo_is_current_user_admin() && ! masteriyo_is_current_user_instructor() && ! masteriyo_can_start_course( $course ) ) { return new \WP_Error( 'masteriyo_rest_cannot_start_course', __( 'Sorry, you have not bought the course.', 'learning-management-system' ), @@ -343,9 +373,21 @@ throw new Exception( 'Event is null.', 400 ); } + if ( empty( $signature ) ) { + masteriyo_get_logger()->error( 'Missing signature header', array( 'source' => 'payment-lemon-squeezy' ) ); + throw new Exception( 'Missing signature.', 403 ); + } + // Verify signature. $secret = Setting::get_webhook_secret(); - $hash = hash_hmac( 'sha256', $payload, $secret ); + + // Reject when no secret is configured — an empty key lets anyone forge a valid HMAC. + if ( empty( $secret ) ) { + masteriyo_get_logger()->error( 'Webhook secret is not configured', array( 'source' => 'payment-lemon-squeezy' ) ); + throw new Exception( 'Webhook secret is not configured.', 403 ); + } + + $hash = hash_hmac( 'sha256', $payload, $secret ); if ( ! hash_equals( $hash, $signature ) ) { masteriyo_get_logger()->error( 'Invalid signature', array( 'source' => 'payment-lemon-squeezy' ) ); throw new Exception( 'Invalid signature.', 403 );
Exploit Outline
The exploit targets the Lemon Squeezy webhook handler. An unauthenticated attacker sends a POST request to `wp-admin/admin-ajax.php?action=masteriyo_lemon_squeezy_webhook` with a JSON payload mimicking a successful purchase event (e.g., `order_created`). Because the plugin fails to enforce a configured 'Webhook Secret' and accepts empty signatures, an attacker can sign the payload using an empty key (`hash_hmac('sha256', $payload, '')`) and provide this value in the `X-Signature` header. The plugin validates this signature against the default empty secret, matches it, and processes the fake payment to enroll the attacker in any course.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.