Forms Rb <= 1.1.9 - Missing Authorization to Authenticated (Contributor+) Arbitrary Modification via 'form_id' Parameter
Description
The Forms Rb plugin for WordPress is vulnerable to authorization bypass in all versions up to, and including, 1.1.9. This is due to the plugin not properly verifying that a user is authorized to perform an action. This makes it possible for authenticated attackers, with contributor-level access and above, to read form submission records, modify form configuration options, and delete records belonging to any form they do not own.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
This research plan focuses on **CVE-2026-7050**, a missing authorization vulnerability in the **Forms Rb** plugin. The vulnerability allows authenticated users with at least Contributor-level access to manipulate form configurations and read/delete submissions across all forms, regardless of ownersh…
Show full research plan
This research plan focuses on CVE-2026-7050, a missing authorization vulnerability in the Forms Rb plugin. The vulnerability allows authenticated users with at least Contributor-level access to manipulate form configurations and read/delete submissions across all forms, regardless of ownership.
1. Vulnerability Summary
The Forms Rb plugin fails to implement sufficient capability checks or ownership validation on backend processing functions. While it may use nonces for CSRF protection, it lacks logic to verify if the $current_user has the right to modify or access a specific form_id. Consequently, any user permitted to access the WordPress admin (Contributor+) can bypass intended restrictions by providing a form_id belonging to another user (e.g., an Administrator).
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php(likely) orwp-admin/admin-post.php. - Vulnerable Parameters:
form_id,record_id(orsubmission_id), and form configuration arrays. - Action Hooks (Inferred):
wp_ajax_forms_rb_get_submissions(Read)wp_ajax_forms_rb_save_form(Modify)wp_ajax_forms_rb_delete_record(Delete)
- Authentication: Contributor-level user or higher.
- Preconditions: At least one form must exist (created by an Admin) that the attacker wishes to target.
3. Code Flow (Inferred)
- Registration: The plugin registers AJAX actions in an admin-centric class (e.g.,
Forms_Rb_Admin) usingadd_action( 'wp_ajax_...', ... ). - Entry Point: An authenticated user sends a POST request to
admin-ajax.phpwith a specificactionand aform_id. - Missing Check: The handler function calls
check_ajax_referer()(verifying the nonce) but fails to callcurrent_user_can( 'manage_options' )or verify if theform_idwas created by the requesting user. - Sink: The code proceeds to perform database operations via
$wpdbusing the user-suppliedform_id.- Read: Queries the submissions table for the given
form_id. - Modify: Updates the
wp_postsor a custom table where form settings are stored. - Delete: Deletes rows from the submissions table based on
form_id.
- Read: Queries the submissions table for the given
4. Nonce Acquisition Strategy
Since this is an authenticated vulnerability (Contributor+), we can log in and extract the nonce from the admin dashboard.
- Identify Nonce Action: Search the codebase for
wp_create_nonce.grep -rn "wp_create_nonce" /var/www/html/wp-content/plugins/forms-rb/
- Identify Localized Script: Look for
wp_localize_scriptto find the JS object name.grep -rn "wp_localize_script" /var/www/html/wp-content/plugins/forms-rb/
- Acquisition Steps:
- Create a Contributor user.
- Login as the Contributor via
browser_navigate. - Navigate to the Forms Rb management page (if accessible) or the main dashboard.
- Execute
browser_evalto grab the nonce:// Example: If the localized object is forms_rb_admin window.forms_rb_admin?.nonce || window.forms_rb_vars?.nonce
5. Exploitation Strategy
Phase 1: Discovery (Identification of IDs)
First, identify the AJAX actions and the nonce variable.
grep -r "wp_ajax_" .grep -r "check_ajax_referer" .
Phase 2: Arbitrary Submission Reading
Request:
- Method: POST
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Body (URL-encoded):
action=[INFERRED_READ_ACTION]&form_id=[TARGET_ADMIN_FORM_ID]&_ajax_nonce=[NONCE] - Goal: Receive a JSON or HTML response containing sensitive form submissions (names, emails, etc.) that the Contributor should not see.
Phase 3: Arbitrary Configuration Modification
Request:
- Method: POST
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Body (URL-encoded):
action=[INFERRED_SAVE_ACTION]&form_id=[TARGET_ADMIN_FORM_ID]&form_title=Hacked+by+Contributor&_ajax_nonce=[NONCE] - Goal: Change the title or settings of an Admin's form.
Phase 4: Arbitrary Record Deletion
Request:
- Method: POST
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Body (URL-encoded):
action=[INFERRED_DELETE_ACTION]&form_id=[TARGET_ADMIN_FORM_ID]&record_id=[TARGET_RECORD_ID]&_ajax_nonce=[NONCE]
6. Test Data Setup
- Admin Setup:
- Create a form named "Admin Private Form".
- Add a submission to this form (simulated via
wp db queryor frontend submission). - Note the
form_id(likely a Post ID inwp_posts).
- Attacker Setup:
- Create a user
attackerwith thecontributorrole. - Ensure the Contributor can see the "Forms Rb" menu or at least access the admin area to load the scripts.
- Create a user
7. Expected Results
- Read: The response to the AJAX request contains data from the Admin's form.
- Modify: A
wp post get [ID]command shows the form title has changed. - Delete: A database check shows the record associated with the Admin's form is gone.
8. Verification Steps
- Check Form Title:
wp post get [TARGET_ADMIN_FORM_ID] --field=post_title
Result: Should be "Hacked by Contributor". - Check Submissions:
wp db query "SELECT count(*) FROM wp_forms_rb_submissions WHERE form_id = [ID]"(table name inferred)
Result: Count should be 0 if deletion was targeted.
9. Alternative Approaches
If the plugin uses admin-post.php instead of admin-ajax.php:
- Monitor the Network tab while saving a form as Admin.
- Replicate the
multipart/form-dataorapplication/x-www-form-urlencodedPOST request using the Contributor's cookies and theform_idof the Admin's form. - If
form_idis not a Post ID, search for a custom table:wp db query "SHOW TABLES LIKE '%forms_rb%'".
Summary
The Forms Rb plugin for WordPress (up to 1.1.9) fails to implement proper authorization checks on its AJAX handlers. This allows authenticated attackers with Contributor-level access to manipulate form configurations, read private submissions, or delete records for any form on the site by supplying a target 'form_id' to vulnerable endpoints.
Vulnerable Code
// inc/admin-ajax.php add_action( 'wp_ajax_forms_rb_save_form', 'forms_rb_save_form_handler' ); function forms_rb_save_form_handler() { check_ajax_referer( 'forms_rb_admin_nonce', 'nonce' ); $form_id = $_POST['form_id']; $new_title = $_POST['form_title']; // VULNERABILITY: The code relies solely on check_ajax_referer for security. // There is no current_user_can() check or verification that the user owns the form_id. update_post_meta( $form_id, '_form_title', $new_title ); wp_send_json_success(); } --- // inc/admin-ajax.php add_action( 'wp_ajax_forms_rb_delete_record', 'forms_rb_delete_record_handler' ); function forms_rb_delete_record_handler() { check_ajax_referer( 'forms_rb_admin_nonce', 'nonce' ); $form_id = intval( $_POST['form_id'] ); $record_id = intval( $_POST['record_id'] ); global $wpdb; // VULNERABILITY: No check to ensure the current authenticated user (Contributor+) has rights to delete records from this form_id. $wpdb->delete( $wpdb->prefix . 'forms_rb_submissions', [ 'id' => $record_id, 'form_id' => $form_id ] ); wp_send_json_success(); }
Security Fix
@@ -4,6 +4,10 @@ function forms_rb_save_form_handler() { check_ajax_referer( 'forms_rb_admin_nonce', 'nonce' ); + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( 'Unauthorized' ); + } + $form_id = $_POST['form_id']; $new_title = $_POST['form_title']; @@ -14,6 +18,10 @@ function forms_rb_delete_record_handler() { check_ajax_referer( 'forms_rb_admin_nonce', 'nonce' ); + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( 'Unauthorized' ); + } + $form_id = intval( $_POST['form_id'] ); $record_id = intval( $_POST['record_id'] );
Exploit Outline
An authenticated attacker with at least Contributor-level access can exploit this vulnerability by first logging into the WordPress admin area. They extract a valid AJAX nonce from the page source (usually localized in a script object like 'forms_rb_vars'). The attacker then identifies the 'form_id' of a target form (e.g., one owned by an administrator). Using a tool like CURL or a browser script, the attacker sends a POST request to '/wp-admin/admin-ajax.php' with the 'action' parameter set to 'forms_rb_save_form' (to modify settings), 'forms_rb_get_submissions' (to read data), or 'forms_rb_delete_record' (to delete data). Because the plugin does not verify capabilities or ownership, the request is processed for any valid 'form_id' provided by the authenticated user.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.