CVE-2026-7050

Forms Rb <= 1.1.9 - Missing Authorization to Authenticated (Contributor+) Arbitrary Modification via 'form_id' Parameter

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
Unpatched
Patched in
N/A
Time to patch

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:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.1.9
PublishedMay 11, 2026
Last updatedMay 12, 2026
Affected pluginforms-rb
Research Plan
Unverified

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) or wp-admin/admin-post.php.
  • Vulnerable Parameters: form_id, record_id (or submission_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)

  1. Registration: The plugin registers AJAX actions in an admin-centric class (e.g., Forms_Rb_Admin) using add_action( 'wp_ajax_...', ... ).
  2. Entry Point: An authenticated user sends a POST request to admin-ajax.php with a specific action and a form_id.
  3. Missing Check: The handler function calls check_ajax_referer() (verifying the nonce) but fails to call current_user_can( 'manage_options' ) or verify if the form_id was created by the requesting user.
  4. Sink: The code proceeds to perform database operations via $wpdb using the user-supplied form_id.
    • Read: Queries the submissions table for the given form_id.
    • Modify: Updates the wp_posts or a custom table where form settings are stored.
    • Delete: Deletes rows from the submissions table based on form_id.

4. Nonce Acquisition Strategy

Since this is an authenticated vulnerability (Contributor+), we can log in and extract the nonce from the admin dashboard.

  1. Identify Nonce Action: Search the codebase for wp_create_nonce.
    • grep -rn "wp_create_nonce" /var/www/html/wp-content/plugins/forms-rb/
  2. Identify Localized Script: Look for wp_localize_script to find the JS object name.
    • grep -rn "wp_localize_script" /var/www/html/wp-content/plugins/forms-rb/
  3. 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_eval to 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

  1. Admin Setup:
    • Create a form named "Admin Private Form".
    • Add a submission to this form (simulated via wp db query or frontend submission).
    • Note the form_id (likely a Post ID in wp_posts).
  2. Attacker Setup:
    • Create a user attacker with the contributor role.
    • Ensure the Contributor can see the "Forms Rb" menu or at least access the admin area to load the scripts.

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

  1. Check Form Title:
    wp post get [TARGET_ADMIN_FORM_ID] --field=post_title
    Result: Should be "Hacked by Contributor".
  2. 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-data or application/x-www-form-urlencoded POST request using the Contributor's cookies and the form_id of the Admin's form.
  • If form_id is not a Post ID, search for a custom table: wp db query "SHOW TABLES LIKE '%forms_rb%'".
Research Findings
Static analysis — not yet PoC-verified

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

--- a/inc/admin-ajax.php
+++ b/inc/admin-ajax.php
@@ -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.