CVE-2026-25320

FormsDB – Save Elementor Forms to Google Sheets & Post Type <= 2.1.3 - Missing Authorization

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
2.1.4
Patched in
97d
Time to patch

Description

The FormsDB – Save Elementor Forms to Google Sheets & Post Type plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 2.1.3. 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:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=2.1.3
PublishedJanuary 28, 2026
Last updatedMay 4, 2026

What Changed in the Fix

Changes introduced in v2.1.4

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - FormsDB (CVE-2026-25320) ## 1. Vulnerability Summary The **FormsDB – Save Elementor Forms to Google Sheets & Post Type** plugin (version <= 2.1.3) is vulnerable to **Missing Authorization**. Specifically, several administrative AJAX functions registered in the `FDBGP_…

Show full research plan

Exploitation Research Plan - FormsDB (CVE-2026-25320)

1. Vulnerability Summary

The FormsDB – Save Elementor Forms to Google Sheets & Post Type plugin (version <= 2.1.3) is vulnerable to Missing Authorization. Specifically, several administrative AJAX functions registered in the FDBGP_Loader class (and associated helper classes) lack proper capability checks (e.g., current_user_can( 'manage_options' )). This allows unauthenticated attackers to perform unauthorized actions, such as disconnecting Google API services, modifying plugin settings, or potentially exposing form submission data.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Actions: The vulnerability likely affects multiple AJAX actions. Based on the plugin's functionality (handling Google Sheets and form submissions), the primary candidates for unauthorized access are:
    • fdbgp_disconnect_google_api (Disconnects the Google account)
    • fdb_get_gsheet_list (Lists Google Sheets from the connected account)
    • fdb_get_gsheet_tabs (Lists tabs within a spreadsheet)
    • sb_fdb_export_sub or fdb_export_submissions (Exports form entries)
  • Authentication: Unauthenticated (the actions are likely registered via both wp_ajax_ and wp_ajax_nopriv_ hooks without capability
Research Findings
Static analysis — not yet PoC-verified

Summary

The FormsDB plugin for WordPress is vulnerable to unauthorized access and CSRF because it lacks capability checks on several AJAX actions and fails to implement state/nonce verification during the Google OAuth callback process. This allows unauthenticated attackers to disconnect Google API services, modify plugin settings, or manipulate the authentication flow.

Vulnerable Code

// sb_elementor_contact_form_db.php
public function setting_redirect(){
    // Handle OAuth callback
    if ( ! is_user_logged_in() || ! current_user_can('manage_options') ) {
        return;
    }

    // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    if(!isset($_GET['page'])){
        return;
    }

    // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    $code = isset($_GET['code']) && !empty($_GET['code']) ? sanitize_text_field(wp_unslash($_GET['code'])) : '';
    
    if(!empty($code)){
        // ... (truncated: saves code to settings without verifying state/nonce)
    }
}

---

// includes/lib-helpers/class-fdbgp-google-api-functions.php ~ line 170
// The OAuth client creation does not set a state (CSRF token) for verification
try {
    if ( empty( $auth_token ) ) {
        $auth_url = $client->createAuthUrl();
        return $auth_url;
    }
}

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/sb-elementor-contact-form-db/2.1.3/includes/lib-helpers/class-fdbgp-google-api-functions.php /home/deploy/wp-safety.org/data/plugin-versions/sb-elementor-contact-form-db/2.1.4/includes/lib-helpers/class-fdbgp-google-api-functions.php
--- /home/deploy/wp-safety.org/data/plugin-versions/sb-elementor-contact-form-db/2.1.3/includes/lib-helpers/class-fdbgp-google-api-functions.php	2025-12-30 06:17:46.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/sb-elementor-contact-form-db/2.1.4/includes/lib-helpers/class-fdbgp-google-api-functions.php	2026-01-29 10:27:56.000000000 +0000
@@ -170,6 +170,8 @@
 		// Load previously authorized credentials from a database.
 		try {
 			if ( empty( $auth_token ) ) {
+				$state = wp_create_nonce( 'fdbgp_google_oauth' );
+				$client->setState( $state );
 				$auth_url = $client->createAuthUrl();
 				return $auth_url;
 			}
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/sb-elementor-contact-form-db/2.1.3/sb_elementor_contact_form_db.php /home/deploy/wp-safety.org/data/plugin-versions/sb-elementor-contact-form-db/2.1.4/sb_elementor_contact_form_db.php
--- /home/deploy/wp-safety.org/data/plugin-versions/sb-elementor-contact-form-db/2.1.3/sb_elementor_contact_form_db.php	2026-01-23 09:16:20.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/sb-elementor-contact-form-db/2.1.4/sb_elementor_contact_form_db.php	2026-01-29 10:27:56.000000000 +0000
@@ -65,7 +65,7 @@
 			}
 
 			add_action( 'plugins_loaded', array( $this, 'FDBGP_plugins_loaded' ) );
-			add_action( 'plugins_loaded', array( $this, 'setting_redirect' ));
+			add_action( 'admin_init', array( $this, 'setting_redirect' ));
 			add_filter( 'plugin_row_meta', array( $this, 'fdbgp_plugin_row_meta' ), 10, 2 );
 			add_action( 'activated_plugin', array( $this, 'fdbgp_plugin_redirection' ) );
 
@@ -119,7 +119,14 @@
 			}
 
 			// phpcs:ignore WordPress.Security.NonceVerification.Recommended
-			if(!isset($_GET['page'])){
+			if(!isset($_GET['page']) || 'formsdb' !== sanitize_text_field(wp_unslash($_GET['page']))){
+				return;
+			}
+
+			// Verify state (nonce) returned from Google
+			// phpcs:ignore WordPress.Security.NonceVerification.Recommended
+			$state = isset($_GET['state']) ? sanitize_text_field(wp_unslash($_GET['state'])) : '';
+			if ( empty($state) || ! wp_verify_nonce($state, 'fdbgp_google_oauth') ) {
 				return;
 			}

Exploit Outline

1. **AJAX Unauthorized Action**: An attacker sends a POST request to `/wp-admin/admin-ajax.php` with an `action` parameter set to administrative functions such as `fdbgp_disconnect_google_api` or `fdb_get_gsheet_list`. Because these actions are registered via `wp_ajax_nopriv_` (or lack capability checks in the handler), the plugin executes the logic even for unauthenticated users. 2. **OAuth CSRF/State Manipulation**: An attacker can initiate a Google OAuth callback to `/wp-admin/admin.php?page=formsdb&code=[EXPLOIT_CODE]` without providing a valid `state` parameter. In versions <= 2.1.3, the plugin processes the `code` and updates the `fdbgp_google_settings` option without verifying that the request originated from a legitimate administrative session, allowing an attacker to force-connect the plugin to their own Google account.

Check if your site is affected.

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