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/Integrations/Slack/Slack.php +41 -8 6.2.4 → 6.2.15 View file →
@@ -32,15 +32,15 @@
32 32
33 33 $inputs = FormFieldsParser::getEntryInputs($form);
34 34
35 35 $labels = FormFieldsParser::getAdminLabels($form, $inputs);
36 -
36 +
37 37 $labels = apply_filters_deprecated(
38 38 'fluentform_slack_field_label_selection',
39 39 [
40 40 $labels,
41 41 $settings,
42 - $form
42 + $form,
43 43 ],
44 44 FLUENTFORM_FRAMEWORK_UPGRADE,
45 45 'fluentform/slack_field_label_selection',
46 46 'Use fluentform/slack_field_label_selection instead of fluentform_slack_field_label_selection.'
@@ -67,9 +67,9 @@
67 67 }
68 68
69 69 $footerText = ArrayHelper::get($settings, 'footerText');
70 70 if ($footerText === '') {
71 - $footerText = "fluentform";
71 + $footerText = 'fluentform';
72 72 }
73 73
74 74 $fields = [];
75 75
@@ -105,15 +105,48 @@
105 105 'title' => $title,
106 106 'title_link' => $titleLink,
107 107 'fields' => $fields,
108 108 'footer' => $footerText,
109 - 'ts' => round(microtime(true) * 1000)
110 - ]
111 - ]
112 - ])
109 + 'ts' => round(microtime(true) * 1000),
110 + ],
111 + ],
112 + ]),
113 113 ];
114 114
115 - $result = wp_remote_post($slackHook, [
115 + // SECURITY (FINDING-15): the webhook URL is admin-supplied and was fetched with no egress
116 + // restriction — an SSRF with a logged status/error oracle (the response is written into the
117 + // feed log). wp_safe_remote_post (below) blocks private/loopback ranges; additionally pin
118 + // the host, since Slack incoming webhooks are always https://hooks.slack.com/... , so an
119 + // arbitrary external host cannot be used as the oracle target either.
120 + // COMPAT: filterable so a site using a Slack-compatible endpoint (Mattermost, Rocket.Chat,
121 + // an internal relay) can keep an existing feed working without patching. Site PHP only —
122 + // a form manager cannot reach it, so the default-deny posture is preserved.
123 + $defaultHookHosts = ['hooks.slack.com'];
124 + $allowedHookHosts = (array) apply_filters('fluentform/slack_allowed_webhook_hosts', $defaultHookHosts, $feed);
125 + $allowedHookHosts = array_map('strtolower', array_filter($allowedHookHosts, 'is_string'));
126 + // A filter returning nothing usable must not silently break every Slack feed — fall back
127 + // to the official host so the default keeps working no matter what the filter returns.
128 + if (!$allowedHookHosts) {
129 + $allowedHookHosts = $defaultHookHosts;
130 + }
131 +
132 + $parsedHook = wp_parse_url($slackHook);
133 + $hookHost = isset($parsedHook['host']) ? strtolower($parsedHook['host']) : '';
134 + $hookScheme = isset($parsedHook['scheme']) ? strtolower($parsedHook['scheme']) : '';
135 + if ('https' !== $hookScheme || !in_array($hookHost, $allowedHookHosts, true)) {
136 + $message = sprintf(
137 + // translators: %s is a comma-separated list of allowed webhook hosts.
138 + __('Invalid Slack webhook URL. It must be an https:// URL on: %s', 'fluentform'),
139 + implode(', ', $allowedHookHosts)
140 + );
141 + do_action('fluentform/integration_action_result', $feed, 'failed', $message);
142 + return [
143 + 'status' => 'failed',
144 + 'message' => $message,
145 + ];
146 + }
147 +
148 + $result = wp_safe_remote_post($slackHook, [
116 149 'method' => 'POST',
117 150 'timeout' => 30,
118 151 'redirection' => 5,
119 152 'httpversion' => '1.0',