| @@ -47,12 +47,14 @@ | ||
| 47 | 47 | } |
| 48 | 48 | |
| 49 | 49 | public function verify($insertData, $requestData, $formId) |
| 50 | 50 | { |
| 51 | - if (!$this->isEnabled($formId) || ( | |
| 52 | - Helper::isConversionForm($formId) && | |
| 53 | - ArrayHelper::isTrue($requestData, 'isFFConversational') | |
| 54 | - )) { | |
| 51 | + // SECURITY (FINDING-25): do NOT skip the check for conversational forms based on the | |
| 52 | + // client-supplied isFFConversational flag. The conversational renderer now injects the | |
| 53 | + // honeypot field (empty) into the submission (getConversationalHoneypotInput via | |
| 54 | + // extra_inputs), so the "present and empty" check passes for legitimate conversational | |
| 55 | + // submissions and the control can no longer be bypassed with a single flag. | |
| 56 | + if (!$this->isEnabled($formId)) { | |
| 55 | 57 | return; |
| 56 | 58 | } |
| 57 | 59 | |
| 58 | 60 | $honeyPotName = $this->getFieldName($formId); |
| @@ -75,8 +77,27 @@ | ||
| 75 | 77 | { |
| 76 | 78 | $option = get_option('_fluentform_global_form_settings'); |
| 77 | 79 | $status = 'yes' == ArrayHelper::get($option, 'misc.honeypotStatus'); |
| 78 | 80 | return apply_filters('fluentform/honeypot_status', $status, $formId); |
| 81 | + } | |
| 82 | + | |
| 83 | + /** | |
| 84 | + * SECURITY (FINDING-25): the conversational form is a JS app that never renders the DOM | |
| 85 | + * honeypot field, so verify() previously had to be skipped for it (via the client-controlled | |
| 86 | + * isFFConversational flag). Return the honeypot field pre-filled EMPTY so the conversational | |
| 87 | + * JS carries it in the submission and the "present and empty" check passes for a legitimate | |
| 88 | + * submission while the control is enforced server-side rather than bypassable by a flag. | |
| 89 | + * | |
| 90 | + * @param int $formId | |
| 91 | + * @return array | |
| 92 | + */ | |
| 93 | + public function getConversationalHoneypotInput($formId) | |
| 94 | + { | |
| 95 | + if (!$this->isEnabled($formId)) { | |
| 96 | + return []; | |
| 97 | + } | |
| 98 | + | |
| 99 | + return [$this->getFieldName($formId) => '']; | |
| 79 | 100 | } |
| 80 | 101 | |
| 81 | 102 | private function getFieldName($formId) |
| 82 | 103 | { |