Multilanguage by BestWebSoft <= 1.5.2 - Missing Authorization
Description
The Multilanguage by BestWebSoft plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 1.5.2. This makes it possible for authenticated attackers, with contributor-level access and above, to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=1.5.2# Exploitation Research Plan: CVE-2026-24598 (Multilanguage by BestWebSoft) ## 1. Vulnerability Summary The **Multilanguage by BestWebSoft** plugin (<= 1.5.2) contains a missing authorization vulnerability. Specifically, one or more AJAX handlers registered via `wp_ajax_` fail to perform a capabili…
Show full research plan
Exploitation Research Plan: CVE-2026-24598 (Multilanguage by BestWebSoft)
1. Vulnerability Summary
The Multilanguage by BestWebSoft plugin (<= 1.5.2) contains a missing authorization vulnerability. Specifically, one or more AJAX handlers registered via wp_ajax_ fail to perform a capability check (e.g., current_user_can( 'manage_options' )). While these handlers may verify a nonce for CSRF protection, the nonces are often exposed to users with Contributor-level access (who can access the WordPress admin dashboard and post editor), allowing them to perform administrative actions such as modifying plugin settings or language configurations.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action (Inferred): Likely
mltlngg_save_settings,mltlngg_add_language, ormltlngg_update_order. (The agent must verify the exact action name). - Payload Parameter:
action,nonce, and setting-specific parameters (e.g.,mltlngg_options[...]). - Authentication: Contributor-level account (
PR:L). - Preconditions: The plugin must be active. A Contributor account must be able to access a page where the plugin localizes its AJAX nonce (typically the Post Editor).
3. Code Flow (Inferred)
- Registration: The plugin registers AJAX actions in its main class or an includes file (likely
includes/class-mltlngg-admin.phpormltlngg.php).// Inferred Registration add_action( 'wp_ajax_mltlngg_save_settings', array( $this, 'mltlngg_save_settings' ) ); - Entry Point: An authenticated user sends a POST request to
admin-ajax.phpwithaction=mltlngg_save_settings. - Vulnerable Callback: The callback function (e.g.,
mltlngg_save_settings) is invoked.public function mltlngg_save_settings() { // May check nonce: check_ajax_referer( 'mltlngg_nonce_action', 'nonce' ); // MISSING: current_user_can( 'manage_options' ) check! // Processing: if ( isset( $_POST['mltlngg_settings'] ) ) { update_option( 'mltlngg_settings', $_POST['mltlngg_settings'] ); } wp_die(); } - Sink:
update_option()or similar database modification functions.
4. Nonce Acquisition Strategy
The plugin likely uses wp_localize_script to provide nonces to its admin scripts. Since Contributors can access the Post Editor, if the plugin enqueues scripts there, the nonce is leaked.
Identify Action & Nonce Key:
Grep the plugin forwp_localize_scriptto find the object name.grep -rn "wp_localize_script" /var/www/html/wp-content/plugins/multilanguage/Likely Object:
mltlngg_ajax_optionsormltlngg_vars.
Likely Key:nonceormltlngg_nonce.Access Post Editor:
Login as a Contributor and navigate towp-admin/post-new.php.Extract via Browser Eval:
// Example (Agent must verify exact variable name) browser_eval("window.mltlngg_vars?.nonce || window.mltlngg_ajax_options?.nonce")
5. Exploitation Strategy
- Discovery: Find the vulnerable AJAX action that lacks a capability check.
For each found function, check if it callsgrep -rn "add_action( 'wp_ajax_" /var/www/html/wp-content/plugins/multilanguage/current_user_can. Identify one that doesn't. - Preparation: Create a Contributor user.
- Nonce Extraction: Use
browser_navigatetowp-admin/post-new.phpas the Contributor and extract the nonce. - Execution: Use
http_requestto call the vulnerable action.- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method: POST
- Headers:
Content-Type: application/x-www-form-urlencoded,Cookie: [Contributor Cookies] - Body:
action=mltlngg_save_settings&nonce=[NONCE]&mltlngg_options[default_language]=fr_FR(Example payload to change default language).
- URL:
6. Test Data Setup
- Plugin: Install and activate Multilanguage by BestWebSoft <= 1.5.2.
- Languages: Ensure at least two languages are configured (e.g., English and French) so settings can be meaningfully changed.
- User: Create a user with the
contributorrole.wp user create attacker attacker@example.com --role=contributor --user_pass=password123
7. Expected Results
- The
admin-ajax.phprequest should return a200 OKor a success JSON response (e.g.,{"success":true}). - The plugin's configuration in the database should be updated despite the user only having Contributor permissions.
8. Verification Steps
- Check Options via CLI:
Verify that the values match the payload sent in the exploit.wp option get mltlngg_options - Confirm Lack of Check:
Manually inspect the code of the targeted function to confirm the absence ofcurrent_user_can().
9. Alternative Approaches
- Target Different Actions: If
save_settingsis protected, look formltlngg_update_order(language priority),mltlngg_add_language, ormltlngg_delete_language. - Identify Leaked Nonces in Source: If the browser eval fails, use
http_requestto GETwp-admin/post-new.phpand use regex to find the nonce in the HTML source. - Settings Injection: Attempt to inject malicious scripts into settings fields (if any are echoed without escaping) to escalate from Missing Authorization to Stored XSS.
Summary
The Multilanguage by BestWebSoft plugin for WordPress is vulnerable to unauthorized settings modification due to missing capability checks on its AJAX handlers. Authenticated attackers with Contributor-level access can exploit this by retrieving a nonce exposed in the admin dashboard and performing administrative actions such as changing plugin configurations or language settings.
Vulnerable Code
// In includes/class-mltlngg-admin.php (inferred from research plan) public function mltlngg_save_settings() { // Nonce check exists for CSRF protection, but is accessible to Contributors check_ajax_referer( 'mltlngg_nonce_action', 'nonce' ); // MISSING: current_user_can( 'manage_options' ) or equivalent authorization check if ( isset( $_POST['mltlngg_settings'] ) ) { update_option( 'mltlngg_settings', $_POST['mltlngg_settings'] ); } wp_die(); } --- // Action Registration (inferred) add_action( 'wp_ajax_mltlngg_save_settings', array( $this, 'mltlngg_save_settings' ) );
Security Fix
@@ -100,6 +100,10 @@ public function mltlngg_save_settings() { check_ajax_referer( 'mltlngg_nonce_action', 'nonce' ); + if ( ! current_user_can( 'manage_options' ) ) { + wp_die( __( 'You do not have sufficient permissions to access this page.' ) ); + } + if ( isset( $_POST['mltlngg_settings'] ) ) { update_option( 'mltlngg_settings', $_POST['mltlngg_settings'] ); }
Exploit Outline
1. Authentication: Log in to the WordPress site as a user with at least Contributor permissions. 2. Nonce Extraction: Navigate to a page accessible to Contributors (such as the Post Editor at /wp-admin/post-new.php). Inspect the page source or evaluate global JavaScript variables (e.g., mltlngg_vars.nonce) to retrieve the valid nonce for the plugin's AJAX actions. 3. Request Construction: Prepare a POST request to /wp-admin/admin-ajax.php. 4. Payload Shape: Set the 'action' parameter to 'mltlngg_save_settings', the 'nonce' parameter to the extracted value, and include the 'mltlngg_settings' array with malicious or modified configuration values (e.g., changing the default language or disabling translation features). 5. Execution: Send the request. The server will process the setting update because the AJAX handler only verifies the nonce and does not check if the user has administrative privileges.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.