Database for Contact Form 7, WPforms, Elementor forms <= 1.4.9 - Missing Authorization to Authenticated (Contributor+) Sensitive Information Exposure via Shortcode
Description
The Database for Contact Form 7, WPforms, Elementor forms plugin for WordPress is vulnerable to unauthorized access of data due to a missing capability check on the entries_shortcode() function in all versions up to, and including, 1.4.9. This makes it possible for authenticated attackers, with Contributor-level access and above, to extract all form submissions - including names, emails, phone numbers.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:NTechnical Details
<=1.4.9What Changed in the Fix
Changes introduced in v1.5.0
Source Code
WordPress.org SVN# Research Plan: CVE-2026-3831 - Sensitive Information Exposure via Shortcode ## 1. Vulnerability Summary The **Database for Contact Form 7, WPforms, Elementor forms** plugin (up to version 1.4.9) is vulnerable to sensitive information exposure. The plugin registers a shortcode `[vx-entries]` via t…
Show full research plan
Research Plan: CVE-2026-3831 - Sensitive Information Exposure via Shortcode
1. Vulnerability Summary
The Database for Contact Form 7, WPforms, Elementor forms plugin (up to version 1.4.9) is vulnerable to sensitive information exposure. The plugin registers a shortcode [vx-entries] via the entries_shortcode() function in the vxcf_form class. This function fails to perform any authorization checks (e.g., current_user_can()) to verify if the user viewing the rendered shortcode has the permissions to access form submissions. Consequently, any user with Contributor level access (who can create posts and use shortcodes) can display and extract all form entries (names, emails, phone numbers) from the database by placing the shortcode in a post and previewing it.
2. Attack Vector Analysis
- Target Endpoint: Frontend post rendering (typically via a Post Preview or a published page).
- Shortcode:
[vx-entries] - Required Authentication: Contributor-level user.
- Vulnerability Type: Missing Authorization.
- Impact: Full exposure of all form submissions captured by the plugin from various sources (Contact Form 7, WPForms, Elementor, etc.).
3. Code Flow
- Registration: In
contact-form-entries.php, thesetup_main()method registers the shortcode:add_shortcode('vx-entries', array($this, 'entries_shortcode')); - Execution: When a post containing
[vx-entries]is rendered (e.g., duringthe_contentfilter), WordPress calls theentries_shortcode()method in thevxcf_formclass. - Vulnerable Sink: Inside
entries_shortcode(), the code queries the database for records in the entries table (likelywp_vxcf_leadsor similar, based onself::$id = 'vxcf_leads') and returns an HTML table of the results. - Missing Check: The function lacks a check for capabilities such as
vxcf_leads_read_entries(defined inincludes/install.php) before returning the data.
4. Nonce Acquisition Strategy
This vulnerability does not require a nonce.
- Shortcodes are processed by the WordPress core engine during content rendering.
- An attacker simply needs to be able to create or edit a post and then view the output.
- Since the goal is to view data rendered on the page, the only "token" needed is a valid session cookie for a Contributor-level user.
5. Exploitation Strategy
- Authentication: Authenticate as a user with the Contributor role.
- Post Creation: Create a new post (draft) containing the payload
[vx-entries]. - Preview Trigger: Obtain the preview URL for the newly created post.
- Data Extraction: Perform a
GETrequest to the preview URL. The response will contain an HTML table with all form entries stored in the database.
6. Test Data Setup
To verify the exploit, the database must contain at least one form entry.
- Create Dummy Entry: Use WP-CLI to simulate a form submission. The plugin hooks into various form events. We can trigger the internal
crmperks_forms_new_submissionfilter or manually insert a row.# Create a dummy entry via the plugin's own logic (vxcf_form::create_entry_vf) wp eval 'apply_filters("crmperks_forms_new_submission", array("first_name" => "Secret", "last_name" => "User", "email" => "vulnerable@example.com"), "manual_test", array());' - Create Contributor User:
wp user create attacker attacker@example.com --role=contributor --user_pass=password123
7. Expected Results
- The
GETrequest to the post preview will return a200 OKresponse. - The response body will contain the sensitive dummy data (e.g., "vulnerable@example.com") inside a table structure.
- The data will be accessible despite the Contributor user lacking the
vxcf_leads_read_entriescapability.
8. Verification Steps
- Login and Session: Use
http_requestto login asattacker. - Create Post:
# Example using WP-CLI to create the post for the attacker wp post create --post_type=post --post_status=draft --post_author=$(wp user get attacker --field=ID) --post_content='[vx-entries]' --post_title='Leaked Entries' - Retrieve ID and Preview:
POST_ID=$(wp post list --post_author=$(wp user get attacker --field=ID) --post_status=draft --format=ids) - Access Preview: Use
http_requestas theattackerto:GET /index.php?p=$POST_ID&preview=true - Confirm Leak: Check if "vulnerable@example.com" exists in the HTML.
9. Alternative Approaches
- ID-specific Leak: If the shortcode supports an
idattribute (e.g.,[vx-entries id="1"]), try to target specific forms if "show all" is not the default. - Block Editor: If the classic editor is disabled, use the REST API to create the post with the shortcode blocks.
- Direct AJAX/CSV: If the shortcode renders a "Download CSV" button (referenced in
readme.txt), check if the CSV generation logic ininit():
also lacks authorization. This would allow for a much cleaner data exfiltration. Theif(!empty($_GET['vx_crm_form_action']) && $_GET['vx_crm_form_action'] == 'download_csv'){ ... }init()hook check fordownload_csvincontact-form-entries.phpappears to only check for avx_crm_keybut not for capabilities.
Summary
The Database for Contact Form 7, WPforms, Elementor forms plugin for WordPress fails to implement proper authorization checks within its shortcode handler. This allows authenticated users with Contributor-level access to view all captured form submissions (including sensitive data like emails and phone numbers) by embedding the [vx-entries] shortcode into a post and previewing or viewing it.
Vulnerable Code
// contact-form-entries.php line 204 public function entries_shortcode($atts){ if(is_preview() && !current_user_can(vxcf_form::$id.'_read_entries')){ return; } $form_id=''; if(!empty($atts['form-id'])){ // ... (subsequent code queries and returns all database entries) ...
Security Fix
@@ -202,8 +202,13 @@ update_option(vxcf_form::$type."_version", self::$version); } public function entries_shortcode($atts){ - if(is_preview() && !current_user_can(vxcf_form::$id.'_read_entries')){ - return; + $post = get_post(); + if ( ! $post ) { + return ''; + } + // Check if the POST AUTHOR has the _read_entries capability + if ( ! user_can( $post->post_author, vxcf_form::$id . '_read_entries' ) ) { //is_preview() + return ''; } $form_id=''; if(!empty($atts['form-id'])){
Exploit Outline
To exploit this vulnerability, an attacker requires at least Contributor-level privileges, which allow for post creation and shortcode usage. The attacker creates a new post or draft and inserts the '[vx-entries]' shortcode into the content. Because the plugin only performed a weak capability check restricted to the 'is_preview()' condition (and even then, improperly), viewing the resulting post or its preview renders a table containing all form submissions from the database. No special nonces or complex payloads are required beyond the shortcode itself.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.