weForms <= 1.6.25 - Missing Authorization
Description
The weForms – Easy Drag & Drop Contact Form Builder For WordPress plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 1.6.25. 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.6.25Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2025-69028 (weForms <= 1.6.25) ## 1. Vulnerability Summary The **weForms** plugin for WordPress is vulnerable to **Missing Authorization** in its AJAX handling logic. Specifically, certain administrative or state-changing functions are registered via the `wp_ajax_…
Show full research plan
Exploitation Research Plan - CVE-2025-69028 (weForms <= 1.6.25)
1. Vulnerability Summary
The weForms plugin for WordPress is vulnerable to Missing Authorization in its AJAX handling logic. Specifically, certain administrative or state-changing functions are registered via the wp_ajax_nopriv_ hook (allowing unauthenticated access) or wp_ajax_ (allowing any logged-in user) without performing an internal capability check (current_user_can()).
Based on the CVSS score (I:L, C:N), the vulnerability likely allows an unauthenticated attacker to modify a minor plugin state, such as dismissing administrative notices or toggling non-critical settings. A prime candidate for this is the weforms_dismiss_review_notice action.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
weforms_dismiss_review_notice(inferred based on CVSSI:L/C:N) - Method: POST
- Required Parameter:
action=weforms_dismiss_review_notice,_wpnonce - Authentication: None required (unauthenticated).
- Preconditions: A valid WordPress nonce for the action must be obtained from the frontend.
3. Code Flow
- The attacker sends a POST request to
/wp-admin/admin-ajax.phpwithaction=weforms_dismiss_review_notice. - WordPress triggers the hook
wp_ajax_nopriv_weforms_dismiss_review_notice. - The handler function
dismiss_review_notice(likely located inincludes/class-ajax.phporincludes/admin/class-review-notice.php) is executed. - The function verifies the nonce using
check_ajax_refererorwp_verify_nonce. - Vulnerability: The function fails to call
current_user_can( 'manage_options' )to ensure the requester is an administrator. - The function updates the WordPress option (e.g.,
update_option( 'weforms_review_notice_dismissed', 'yes' )), affecting the site globally.
4. Nonce Acquisition Strategy
The weforms plugin enqueues a frontend script on any page where a form is displayed. This script contains the necessary nonce.
- Identify Shortcode: The plugin uses the shortcode
[weforms id="FORM_ID"]. - Setup Page: Create a public page containing any weForm.
- Extraction:
- Navigate to the page using
browser_navigate. - The plugin localizes data into a global JavaScript object named
weforms(inferred). - Use
browser_evalto extract the nonce:browser_eval("weforms.nonce").
- Navigate to the page using
5. Exploitation Strategy
Step 1: Obtain a valid Nonce
- Create a test form using WP-CLI:
wp weforms create --title="Test Form"(Note: use actual weForms CLI if available, or just create manually in the UI). - Create a page with the shortcode:
wp post create --post_type=page --post_status=publish --post_content='[weforms id="123"]' --post_title='Exploit Page' - Extract nonce via
browser_eval:// Target the window object variable localized by weForms const nonce = window.weforms?.nonce;
Step 2: Trigger the Unauthorized Action
Send an unauthenticated POST request to admin-ajax.php.
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=weforms_dismiss_review_notice&_wpnonce=[EXTRACTED_NONCE]
6. Test Data Setup
- Plugin Version: Ensure
weformsversion 1.6.25 is installed. - Form Creation: Create at least one form so the shortcode is functional.
- Notice State: Ensure the
weforms_review_notice_dismissedoption is either not set or set tono(standard state for a new installation).
7. Expected Results
- HTTP Response: The server should return a
200 OKorwp_send_json_success(usually{"success":true}). - Integrity Change: The administrative review notice should be permanently dismissed for all administrators, even though the request was made by an unauthenticated user.
8. Verification Steps
After the exploit, use WP-CLI to check the state of the option that tracks the notice dismissal:
wp option get weforms_review_notice_dismissed
# Expected output: 'yes' or '1'
Alternatively, log in as an admin and verify that the review notice (usually a banner asking for a rating) is gone.
9. Alternative Approaches
If weforms_dismiss_review_notice is not the vulnerable action, search for other AJAX handlers in includes/class-ajax.php that lack capability checks:
- Check for other actions:
grep -rn "wp_ajax_nopriv" wp-content/plugins/weforms/ | grep "add_action" - Analyze found handlers: Check if they use
current_user_can(). - Potential Action:
weforms_form_export(if configured to be unauthenticated). If this is the target, the CVSSC:Nmight be an error in the initial report, and the exploit would leak user entry data.- Payload:
action=weforms_form_export&form_id=[ID]&_wpnonce=[NONCE] - Verification: Check if a CSV file is returned in the response body.
- Payload:
Summary
The weForms plugin for WordPress is vulnerable to unauthorized access due to a missing capability check in its AJAX handling logic. Specifically, administrative actions like dismissing review notices are exposed via AJAX hooks without verifying if the requester has the 'manage_options' capability, allowing unauthenticated attackers to modify minor site settings.
Vulnerable Code
// wp-content/plugins/weforms/includes/admin/class-review-notice.php add_action( 'wp_ajax_weforms_dismiss_review_notice', array( $this, 'dismiss_review_notice' ) ); add_action( 'wp_ajax_nopriv_weforms_dismiss_review_notice', array( $this, 'dismiss_review_notice' ) ); /** * Dismiss review notice * * @return void */ public function dismiss_review_notice() { if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'weforms-review-notice' ) ) { wp_send_json_error( __( 'Invalid nonce', 'weforms' ) ); } update_option( 'weforms_review_notice_dismissed', 'yes' ); wp_send_json_success(); }
Security Fix
@@ -45,6 +45,10 @@ wp_send_json_error( __( 'Invalid nonce', 'weforms' ) ); } + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( __( 'Permission denied', 'weforms' ) ); + } + update_option( 'weforms_review_notice_dismissed', 'yes' ); wp_send_json_success();
Exploit Outline
The exploit methodology targets the 'weforms_dismiss_review_notice' AJAX action. An unauthenticated attacker first obtains a valid security nonce by visiting any public page where a weForm is displayed (via shortcode); the nonce is typically localized in the 'weforms' global JavaScript object. The attacker then sends an unauthenticated POST request to '/wp-admin/admin-ajax.php' with the parameters 'action=weforms_dismiss_review_notice' and the extracted nonce. Because the handler function lacks a 'current_user_can()' authorization check, the server updates the 'weforms_review_notice_dismissed' option in the database, resulting in the permanent dismissal of the review notice for all site administrators.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.