CVE-2026-2306

Ninja Tables <= 5.2.6 - Missing Authorization to Authenticated (Subscriber+) Arbitrary Table Creation

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
5.2.7
Patched in
1d
Time to patch

Description

The Ninja Tables – Easy Data Table Builder plugin for WordPress is vulnerable to unauthorized database table creation due to missing authorization checks on the `createFluentCartTable` function in all versions up to, and including, 5.2.6. This makes it possible for authenticated attackers, with Subscriber-level access and above, to create arbitrary Ninja Tables in the database which can lead to database pollution and resource exhaustion.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=5.2.6
PublishedMay 5, 2026
Last updatedMay 6, 2026
Affected pluginninja-tables

What Changed in the Fix

Changes introduced in v5.2.7

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

## Vulnerability Summary The **Ninja Tables** plugin (versions up to 5.2.6) is vulnerable to unauthorized table creation. The vulnerability exists in the `createFluentCartTable` function within the `NinjaTables\App\Modules\FluentCart\Handlers\FluentCartHandler` class. Unlike other sensitive funct…

Show full research plan

Vulnerability Summary

The Ninja Tables plugin (versions up to 5.2.6) is vulnerable to unauthorized table creation. The vulnerability exists in the createFluentCartTable function within the NinjaTables\App\Modules\FluentCart\Handlers\FluentCartHandler class.

Unlike other sensitive functions in the same class (like getTableData or saveQuerySettings), createFluentCartTable lacks any capability checks (e.g., current_user_can()) or security nonces. Since this function is registered to an AJAX action accessible to any authenticated user (including those with the Subscriber role), an attacker can programmatically trigger the creation of an arbitrary number of "Ninja Tables" (which are custom post types of ninja-table). This can lead to database pollution, metadata manipulation, and resource exhaustion.

Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • AJAX Action: ninja_tables_admin_ajax (The standard dispatcher for Ninja Tables AJAX requests).
  • Route Parameter: create-fluent-cart-table (Routes to the vulnerable method).
  • HTTP Method: POST
  • Required Parameter: post_title (The name of the new table).
  • Authentication: Authenticated, Subscriber role or higher.
  • Vulnerable Sink: wp_insert_post() called via $this->saveTable().

Code Flow

  1. Entry Point: An authenticated user sends a POST request to admin-ajax.php with the action ninja_tables_admin_ajax.
  2. Dispatching: The plugin's AJAX handler identifies the route parameter as create-fluent-cart-table.
  3. Vulnerable Function Call: The dispatcher calls NinjaTables\App\Modules\FluentCart\Handlers\FluentCartHandler::createFluentCartTable().
  4. Input Processing: The function retrieves all inputs via App::getInstance('request')->all() (line 54).
  5. Lack of Authorization: The function proceeds directly to validation of the post_title without calling current_user_can() or verifying a nonce.
  6. Persistence:
    • It calls $this->saveTable() (line 69).
    • saveTable() (line 128) creates a new post with 'post_type' => 'ninja-table' and 'post_status' => 'publish' using wp_insert_post().
  7. Meta Manipulation: The function then updates multiple metadata keys for the new table (lines 71-92), such as _ninja_tables_data_provider set to wp_fct.
  8. Response: The server returns a 200 OK JSON response containing the new table_id.

Nonce Acquisition Strategy

Based on the source code of createFluentCartTable, no nonce verification is performed within the function. However, the plugin's global AJAX dispatcher might expect a nonce.

In Ninja Tables, nonces are typically localized in the WordPress admin dashboard. Even though the vulnerability allows Subscriber access, Subscribers cannot normally access the Ninja Tables dashboard.

Steps to attempt nonce-less exploitation first:

  1. Attempt the request without a nonce. If the framework does not enforce it globally for this specific route, it will succeed.

If a nonce is required:

  1. Check if the Subscriber can access the admin-ajax.php?action=rest-nonce to get a REST nonce (though likely not applicable here).
  2. If the plugin enqueues scripts for Subscribers on the frontend (e.g., via a shortcode), the nonce might be found there.
  3. Navigate to the dashboard as an admin, find the script localization for ninja_tables_admin_ajax, and check if the nonce is static or user-bound. If it's user-bound (standard for WP), a Subscriber must find a way to generate their own.

Likely Nonce Variable (if enforced): window.ninja_table_admin_object?.nonce

Exploitation Strategy

1. Pre-requisites

  • A Subscriber user account credentials.

2. The Exploit Request

The agent will send a POST request to create a table.

URL: http://<target>/wp-admin/admin-ajax.php
Content-Type: application/x-www-form-urlencoded
Body:

action=ninja_tables_admin_ajax&route=create-fluent-cart-table&post_title=Exploit_Table_DB_Pollution&query_selections[product-categories][]=1&query_conditions[order_by]=post_title

3. Payload Parameters

  • action: ninja_tables_admin_ajax (The AJAX handler).
  • route: create-fluent-cart-table (The route mapping to the vulnerable handler).
  • post_title: Any string (e.g., Vulnerable_Table_Creation).
  • query_selections: (Optional) Array used to populate metadata.
  • query_conditions: (Optional) Array used to populate metadata.

Test Data Setup

  1. Create Subscriber User:
    wp user create attacker attacker@example.com --role=subscriber --user_pass=password123
    
  2. Verify Plugin State:
    Ensure ninja-tables is active and version is <= 5.2.6.

Expected Results

  • HTTP Response: 200 OK.
  • Body: {"success":true,"data":{"table_id":<NEW_ID>,"message":"Table created successfully."}}.
  • Database Change: A new entry in wp_posts with post_type = 'ninja-table' and title Exploit_Table_DB_Pollution.

Verification Steps

After performing the HTTP request, verify the table was created using WP-CLI:

  1. Check for the new table post:

    wp post list --post_type=ninja-table --field=post_title
    

    Successful result: The output should contain "Exploit_Table_DB_Pollution".

  2. Verify the metadata was set (optional):

    wp post meta list <NEW_ID>
    

    Successful result: Look for _ninja_tables_data_provider set to wp_fct.

Alternative Approaches

If route=create-fluent-cart-table fails, the plugin might use a different routing convention for the FluentCartHandler.

  1. Try route=fluent-cart/create-table.
  2. Try route=create_fluent_cart_table (underscore instead of hyphen).
  3. Check if FluentCartHandler is registered as a standalone AJAX action:
    action=ninja_tables_fct_create_table. (Check grep -r "wp_ajax" . in the full plugin source if available).

Check if your site is affected.

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