PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.15
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.15
6.2.15 6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 All 197 releases
← All changes | app/Services/FluentConversational/Classes/Form.php +27 -2 6.2.7 → 6.2.15 View file →
@@ -569,9 +569,12 @@
569 569 $instanceId = $form->instance_index;
570 570 $varName = 'fluent_forms_global_var_' . $instanceId;
571 571
572 572 $localizedVars = [
573 - 'fluent_forms_admin_nonce' => wp_create_nonce('fluent_forms_admin_nonce'),
573 + // SECURITY (H-01): do not emit the admin AJAX nonce on the public conversational form
574 + // page — the public form JS never uses it, and on a page an admin happens to view it
575 + // would embed that admin's own valid nonce. Emit it only for a viewer who could use it.
576 + 'fluent_forms_admin_nonce' => current_user_can('fluentform_dashboard_access') ? wp_create_nonce('fluent_forms_admin_nonce') : '',
574 577 'ajaxurl' => admin_url('admin-ajax.php'),
575 578 'nonce' => wp_create_nonce(),
576 579 'form' => $this->getLocalizedForm($form),
577 580 'assetBaseUrl' => FLUENT_CONVERSATIONAL_FORM_DIR_URL . 'public',
@@ -682,8 +685,27 @@
682 685 '_fluentform_' . $formId . '_fluentformnonce' => wp_create_nonce('fluentform-submit-form'),
683 686 '_wp_http_referer' => esc_attr(wp_unslash(wpFluentForm('request')->server('REQUEST_URI'))),
684 687 ];
685 688
689 + // SECURITY (FINDING-25): carry the anti-spam honeypot field (empty) and a freshly minted
690 + // token in the conversational submission. The conversational JS forwards every extra_input
691 + // into the submission payload, so these reach the server-side checks — which no longer skip
692 + // conversational forms — WITHOUT any client/JS change. This closes the bypass where adding
693 + // isFFConversational=1 disabled honeypot + token protection entirely.
694 + //
695 + // The token itself is disabled for conversational forms server-side (see the
696 + // fluentform/token_based_spam_protection_status filter in actions.php): its ~1h TTL cannot be
697 + // refreshed by the conversational JS, so behind a full-page cache the baked-in token would
698 + // expire and reject every submission. getConversationalTokenInput() therefore returns [] for
699 + // conversational forms; the honeypot (static empty field) still applies.
700 + $honeyPot = new \FluentForm\App\Modules\Form\HoneyPot(wpFluentForm());
701 + $inputs = array_merge($inputs, $honeyPot->getConversationalHoneypotInput($formId));
702 +
703 + $inputs = array_merge(
704 + $inputs,
705 + \FluentForm\App\Modules\Form\TokenBasedSpamProtection::getConversationalTokenInput($formId)
706 + );
707 +
686 708 return apply_filters('fluentform/conversational_extra_inputs', $inputs, $formId);
687 709 }
688 710
689 711 public function getRandomPhoto()
@@ -774,9 +796,12 @@
774 796
775 797 $designSettings = $this->getDesignSettings($formId);
776 798
777 799 $localizedVars = [
778 - 'fluent_forms_admin_nonce' => wp_create_nonce('fluent_forms_admin_nonce'),
800 + // SECURITY (H-01): do not emit the admin AJAX nonce on the public conversational form
801 + // page — the public form JS never uses it, and on a page an admin happens to view it
802 + // would embed that admin's own valid nonce. Emit it only for a viewer who could use it.
803 + 'fluent_forms_admin_nonce' => current_user_can('fluentform_dashboard_access') ? wp_create_nonce('fluent_forms_admin_nonce') : '',
779 804 'ajaxurl' => admin_url('admin-ajax.php'),
780 805 'nonce' => wp_create_nonce(),
781 806 'form' => $this->getLocalizedForm($form),
782 807 'form_id' => $form->id,