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/FormBuilder/EditorShortcodeParser.php +36 -5 6.2.12 → 6.2.15 View file →
@@ -113,9 +113,9 @@
113 113 if (false !== strpos($handler, 'cookie.')) {
114 114 $scookieProperty = substr($handler, strlen('cookie.'));
115 115 $cookieValue = array_key_exists($scookieProperty, $_COOKIE) ? sanitize_text_field(wp_unslash($_COOKIE[$scookieProperty])) : '';
116 116
117 - return esc_attr($cookieValue);
117 + return static::escapeReflectedValue($cookieValue);
118 118 }
119 119
120 120 if (false !== strpos($handler, 'dynamic.')) {
121 121 $dynamicKey = substr($handler, strlen('dynamic.'));
@@ -175,12 +175,39 @@
175 175 if (null === $value || '' === $value) {
176 176 return '';
177 177 }
178 178
179 - return esc_attr(Helper::flattenRequestValue($value));
179 + return static::escapeReflectedValue(Helper::flattenRequestValue($value));
180 180 }
181 181
182 182 /**
183 + * Escape a visitor-supplied value ({get.x}, {cookie.x}) for the assembled form HTML.
184 + *
185 + * Smartcodes are substituted after Custom HTML was sanitized, so the value can land in
186 + * any attribute, including an iframe src or anchor href. esc_attr() leaves a javascript:
187 + * scheme intact and keeps existing entities (?p=java	script:...), so encode every
188 + * ampersand and drop values that would resolve to a script-capable URL.
189 + *
190 + * @param string $value
191 + *
192 + * @return string
193 + */
194 + public static function escapeReflectedValue($value)
195 + {
196 + $value = wp_check_invalid_utf8((string) $value);
197 +
198 + // Browsers strip control chars and whitespace from URLs before reading the scheme.
199 + $scheme = strtolower(preg_replace('/[\x00-\x20]+/', '', $value));
200 +
201 + if (preg_match('/^(javascript|vbscript|data):/', $scheme)) {
202 + return '';
203 + }
204 +
205 + // Encode braces too, so the value cannot plant a smartcode for a later replacement pass.
206 + return str_replace(['{', '}'], ['{', '}'], htmlspecialchars($value, ENT_QUOTES, 'UTF-8', true));
207 + }
208 +
209 + /**
183 210 * Parse the curly braced shortcode into array
184 211 *
185 212 * @param string $value
186 213 *
@@ -218,9 +245,9 @@
218 245
219 246 if (false !== strpos($prop, 'meta.')) {
220 247 $metaKey = substr($prop, strlen('meta.'));
221 248 $metaKey = sanitize_text_field($metaKey);
222 - if (empty($metaKey)) {
249 + if (empty($metaKey) || ShortCodeParser::isDeniedUserProperty($metaKey)) {
223 250 return '';
224 251 }
225 252 $userId = $user->ID;
226 253 $data = get_user_meta($userId, $metaKey, true);
@@ -230,8 +257,12 @@
230 257 }
231 258 return esc_html(implode(',', $data));
232 259 }
233 260
261 + if (ShortCodeParser::isDeniedUserProperty($prop)) {
262 + return '';
263 + }
264 +
234 265 return esc_html($user->{$prop});
235 266 }
236 267
237 268 return '';
@@ -255,9 +286,9 @@
255 286
256 287 if (false !== strpos($key, 'author.')) {
257 288 $authorProperty = substr($key, strlen('author.'));
258 289 $authorId = $post->post_author;
259 - if ($authorId) {
290 + if ($authorId && !ShortCodeParser::isDeniedUserProperty($authorProperty)) {
260 291 $data = get_the_author_meta($authorProperty, $authorId);
261 292 if (!is_array($data)) {
262 293 return esc_html($data);
263 294 }
@@ -286,9 +317,9 @@
286 317 if ('permalink' == $prop) {
287 318 return site_url(esc_attr(urldecode(wpFluentForm('request')->server('REQUEST_URI'))));
288 319 }
289 320
290 - if (property_exists($post, $prop)) {
321 + if ('post_password' !== $prop && property_exists($post, $prop)) {
291 322 return esc_html($post->{$prop});
292 323 }
293 324 return '';
294 325 }