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/Modules/Payments/PaymentMethods/Stripe/ConnectConfig.php +26 -4 6.2.4 → 6.2.15 View file →
@@ -16,18 +16,22 @@
16 16
17 17 public static function getConnectConfig()
18 18 {
19 19 $configBase = self::$connectBase . 'stripe-connect';
20 - $hash = md5(site_url() . wp_generate_uuid4() . time());
20 + // SECURITY (FINDING-24): the fluentforms.com connect proxy sets its own OAuth `state`, so
21 + // our nonce can't ride there. Carry it in url_base — the proxy must redirect back to
22 + // url_base, so the nonce returns to us intact as ff_connect_nonce for CSRF verification.
23 + $hash = wp_create_nonce('ff_stripe_connect');
24 + $urlBase = rawurlencode(admin_url('admin.php?page=fluent_forms_settings&ff_connect_nonce=' . $hash));
21 25
22 26 $liveArgs = [
23 - 'url_base' => rawurlencode(admin_url('admin.php?page=fluent_forms_settings')),
27 + 'url_base' => $urlBase,
24 28 'mode' => 'live',
25 29 'hash' => $hash
26 30 ];
27 31
28 32 $testArgs = [
29 - 'url_base' => rawurlencode(admin_url('admin.php?page=fluent_forms_settings')),
33 + 'url_base' => $urlBase,
30 34 'mode' => 'test',
31 35 'hash' => $hash
32 36 ];
33 37
@@ -58,14 +62,32 @@
58 62 }
59 63
60 64 public static function verifyAuthorizeSuccess($data)
61 65 {
66 + // SECURITY (FINDING-24): require the settings-manager capability and a valid connect nonce
67 + // before exchanging the code. Otherwise a settings manager could be tricked (CSRF) into
68 + // loading a callback carrying the attacker's Stripe code, overwriting the site's live
69 + // Stripe credentials so all future payments settle into the attacker's account.
70 + if (!current_user_can('fluentform_settings_manager')) {
71 + return;
72 + }
73 + // The nonce is carried in url_base (see getConnectConfig) and returns as ff_connect_nonce,
74 + // not in the proxy-controlled `state`.
75 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- this IS the nonce check
76 + $connectNonce = isset($_GET['ff_connect_nonce']) ? sanitize_text_field(wp_unslash($_GET['ff_connect_nonce'])) : '';
77 + if (!$connectNonce || !wp_verify_nonce($connectNonce, 'ff_stripe_connect')) {
78 + echo '<div class="ff_message ff_message_error">' . esc_html__('Invalid or expired Stripe Connect request. Please start the connection again.', 'fluentform') . '</div>';
79 + return;
80 + }
81 +
82 + // SECURITY (FINDING-24 / PRO-10): enable TLS verification on the exchange that returns the
83 + // live Stripe secret key so a network-position attacker cannot read or substitute it.
62 84 $response = wp_remote_post(self::$connectBase . 'stripe-verify-code', [
63 85 'method' => 'POST',
64 86 'timeout' => 45,
65 87 'redirection' => 5,
66 88 'httpversion' => '1.0',
67 - 'sslverify' => false,
89 + 'sslverify' => true,
68 90 'blocking' => true,
69 91 'headers' => array(),
70 92 'body' => $data,
71 93 'cookies' => array()