Easy Form Builder <= 3.9.3 - Missing Authorization to Authenticated (Subscriber+) Sensitive Form Response Data Exposure
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:NTechnical Details
<=3.9.3Source Code
WordPress.org SVN# 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 tofalsefor Subscribers, causing the entireANDcondition to fail and bypass thewp_die()call.
3. Code Flow
- Entry Point: The user sends a POST request to
admin-ajax.phpwith a vulnerableaction. - Hook Registration: The plugin registers AJAX handlers in
includes/class-easy-form-builder-ajax.php(inferred) usingadd_action( 'wp_ajax_...' ). - 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' ); } - Logic Failure:
- For a Subscriber:
current_user_can( 'manage_options' )isfalse, so! current_user_canistrue. is_user_logged_in()istrue, so! is_user_logged_in()isfalse.true && falseevaluates tofalse.- The
ifblock is skipped, and the code proceeds to fetch data from the database.
- For a Subscriber:
- 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.
- Identify Script Localization: Look for
wp_localize_scriptin the plugin's main files or admin classes. - Key Identifier: The JS variable name is often
efb_varorw_efb_nonce. - Extraction Steps:
- Create a page containing an Easy Form Builder shortcode to ensure the scripts are loaded.
- Use
browser_navigateas the Subscriber user to this page. - Execute
browser_evalto extract the nonce.
Verification Command (for agent):
// Example extraction
browser_eval("window.efb_var?.nonce || window.w_efb_nonce")
5. Exploitation Strategy
- Pre-requisite: An administrator must have at least one form with a submission.
- Session: Authenticate as a Subscriber user.
- Nonce: Obtain the nonce via
browser_evalfrom any page where EFB scripts are active. - 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]
- 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
- Create Form: Use WP-CLI to create a form or rely on default EFB setup.
- Create Submission: Simulate a form submission as a guest or admin to populate the
w_efb_responsestable.# 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\"}')" - Create Attacker: Create a user with the
subscriberrole.wp user create attacker attacker@example.com --role=subscriber --user_pass=password - 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 OKstatus and a JSON body containing the details of the submission (e.g.,{"status": "success", "data": {...}}). - Failure (Patched): The server returns a
403 Forbiddenorwp_diemessage "Unauthorized" or similar.
8. Verification Steps
- Check Response: Inspect the JSON response for sensitive fields (email, names, message body).
- Database Cross-Reference: Verify the returned ID and content match the entry in the
wp_w_efb_responsestable.wp db query "SELECT * FROM wp_w_efb_responses WHERE id=1"
9. Alternative Approaches
- Action Brute Force: If
efb_get_responses_by_idis not the exact name, check theincludes/class-easy-form-builder-ajax.phpfile for anyadd_action('wp_ajax_...', ...)registrations. - Admin Reply Exposure: Try the action
efb_get_messageswhich 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.
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
@@ -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.