CVE-2025-14067

Easy Form Builder <= 3.9.3 - Missing Authorization to Authenticated (Subscriber+) Sensitive Form Response Data Exposure

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
3.9.4
Patched in
1d
Time to patch

Description

The Easy Form Builder plugin for WordPress is vulnerable to unauthorized access of data due to a missing capability check on multiple AJAX actions in all versions up to, and including, 3.9.3. This makes it possible for authenticated attackers, with Subscriber-level access and above, to retrieve sensitive form response data, including messages, admin replies, and user information due to a logic error in the authorization check that uses AND (&&) instead of OR (||).

CVSS Vector Breakdown

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

Technical Details

Affected versions<=3.9.3
PublishedFebruary 13, 2026
Last updatedFebruary 14, 2026
Affected plugineasy-form-builder

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2025-14067 ## 1. Vulnerability Summary The **Easy Form Builder** plugin (versions <= 3.9.3) contains a missing authorization vulnerability in several AJAX actions. The vulnerability stems from a logic error in the authorization check where the code uses a logical …

Show full research plan

Exploitation Research Plan - CVE-2025-14067

1. Vulnerability Summary

The Easy Form Builder plugin (versions <= 3.9.3) contains a missing authorization vulnerability in several AJAX actions. The vulnerability stems from a logic error in the authorization check where the code uses a logical AND (&&) instead of a logical OR (||) when verifying user capabilities. This error allows any authenticated user with at least Subscriber level permissions to bypass intended administrative restrictions and access sensitive form response data, including user-submitted messages, admin replies, and personal information.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Vulnerable AJAX Actions:
    • efb_get_responses_by_id (Inferred)
    • efb_get_messages (Inferred)
    • efb_get_report_details (Inferred)
  • Required Authentication: Subscriber-level user or higher.
  • Payload Parameters:
    • action: The vulnerable AJAX action (e.g., efb_get_responses_by_id).
    • id: The ID of the form submission or message to retrieve.
    • nonce: A valid security nonce (usually required for AJAX in this plugin).
  • Vulnerability Mechanism: The check if ( ! current_user_can( 'manage_options' ) && ! is_user_logged_in() ) (or similar) incorrectly permits any logged-in user to pass, as ! is_user_logged_in() evaluates to false for Subscribers, causing the entire AND condition to fail and bypass the wp_die() call.

3. Code Flow

  1. Entry Point: The user sends a POST request to admin-ajax.php with a vulnerable action.
  2. Hook Registration: The plugin registers AJAX handlers in includes/class-easy-form-builder-ajax.php (inferred) using add_action( 'wp_ajax_...' ).
  3. Authorization Check (The Sink):
    Inside the handler function (e.g., get_responses_by_id), the plugin performs a check similar to:
    if ( ! current_user_can( 'manage_options' ) && ! is_user_logged_in() ) {
        wp_die( 'Unauthorized' );
    }
    
  4. Logic Failure:
    • For a Subscriber: current_user_can( 'manage_options' ) is false, so ! current_user_can is true.
    • is_user_logged_in() is true, so ! is_user_logged_in() is false.
    • true && false evaluates to false.
    • The if block is skipped, and the code proceeds to fetch data from the database.
  5. Data Exposure: The function queries $wpdb->prefix . 'w_efb_responses' and returns the sensitive data as a JSON response.

4. Nonce Acquisition Strategy

The plugin typically enqueues a script and localizes it with a nonce for AJAX requests.

  1. Identify Script Localization: Look for wp_localize_script in the plugin's main files or admin classes.
  2. Key Identifier: The JS variable name is often efb_var or w_efb_nonce.
  3. Extraction Steps:
    • Create a page containing an Easy Form Builder shortcode to ensure the scripts are loaded.
    • Use browser_navigate as the Subscriber user to this page.
    • Execute browser_eval to extract the nonce.

Verification Command (for agent):

// Example extraction
browser_eval("window.efb_var?.nonce || window.w_efb_nonce")

5. Exploitation Strategy

  1. Pre-requisite: An administrator must have at least one form with a submission.
  2. Session: Authenticate as a Subscriber user.
  3. Nonce: Obtain the nonce via browser_eval from any page where EFB scripts are active.
  4. Target Request:
    • Method: POST
    • URL: http://localhost:8080/wp-admin/admin-ajax.php
    • Content-Type: application/x-www-form-urlencoded
    • Body:
      action=efb_get_responses_by_id&id=1&nonce=[EXTRACTED_NONCE]
      
  5. Observation: If successful, the response will be a JSON object containing the full content of submission ID 1, including potentially private fields like email, phone number, and message content.

6. Test Data Setup

  1. Create Form: Use WP-CLI to create a form or rely on default EFB setup.
  2. Create Submission: Simulate a form submission as a guest or admin to populate the w_efb_responses table.
    # Use the plugin's submission endpoint or insert directly via SQL if needed
    wp db query "INSERT INTO wp_w_efb_responses (form_id, content, user_info) VALUES (1, 'Sensitive Data', '{\"email\":\"victim@example.com\"}')"
    
  3. Create Attacker: Create a user with the subscriber role.
    wp user create attacker attacker@example.com --role=subscriber --user_pass=password
    
  4. Create Trigger Page:
    wp post create --post_type=page --post_status=publish --post_title="Forms" --post_content="[efb_form id='1']"
    

7. Expected Results

  • Success: The server returns a 200 OK status and a JSON body containing the details of the submission (e.g., {"status": "success", "data": {...}}).
  • Failure (Patched): The server returns a 403 Forbidden or wp_die message "Unauthorized" or similar.

8. Verification Steps

  1. Check Response: Inspect the JSON response for sensitive fields (email, names, message body).
  2. Database Cross-Reference: Verify the returned ID and content match the entry in the wp_w_efb_responses table.
    wp db query "SELECT * FROM wp_w_efb_responses WHERE id=1"
    

9. Alternative Approaches

  • Action Brute Force: If efb_get_responses_by_id is not the exact name, check the includes/class-easy-form-builder-ajax.php file for any add_action('wp_ajax_...', ...) registrations.
  • Admin Reply Exposure: Try the action efb_get_messages which is often used to display admin replies to specific form submissions.
  • Reporting Endpoint: Check for efb_get_form_report, which might expose aggregated form data.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Easy Form Builder plugin for WordPress is vulnerable to sensitive data exposure due to a logical error in its authorization checks for multiple AJAX actions. By incorrectly using a logical 'AND' instead of 'OR' when verifying administrative privileges, the plugin allows any authenticated user, such as a Subscriber, to retrieve private form submissions and response data.

Vulnerable Code

// Inferred from: includes/class-easy-form-builder-ajax.php

if ( ! current_user_can( 'manage_options' ) && ! is_user_logged_in() ) {
    wp_die( 'Unauthorized' );
}

---

// Impacted AJAX actions inferred from plugin logic:
// action=efb_get_responses_by_id
// action=efb_get_messages
// action=efb_get_report_details

Security Fix

--- a/includes/class-easy-form-builder-ajax.php
+++ b/includes/class-easy-form-builder-ajax.php
@@ -unknown,1 +unknown,1 @@
-if ( ! current_user_can( 'manage_options' ) && ! is_user_logged_in() )
+if ( ! current_user_can( 'manage_options' ) || ! is_user_logged_in() )

Exploit Outline

1. Authenticate to the WordPress site as a user with Subscriber-level permissions or higher. 2. Navigate to a page where Easy Form Builder scripts are loaded (usually a page containing a form) and extract the security nonce from the global JavaScript variable 'efb_var' or 'w_efb_nonce'. 3. Construct an AJAX request targeting '/wp-admin/admin-ajax.php' with the 'action' parameter set to 'efb_get_responses_by_id' and the 'id' parameter set to the ID of the submission to retrieve. 4. Include the extracted nonce in the 'nonce' parameter. 5. Send the POST request; due to the logic error (AND vs OR), the server will skip the authorization check and return a JSON object containing sensitive form submission data, including user emails and message content.

Check if your site is affected.

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