PluginProbe
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell / 3.13.3
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell v3.13.3
3.13.3 3.13.2 3.13.1 3.13.0 3.12.13 3.12.12 3.12.11 3.12.10 3.12.9 3.12.8 3.12.7 3.12.6 3.12.5 3.12.4 3.12.3 3.12.1 3.12.2 3.12.0 3.11.1 3.11.0 3.10.9 3.10.8 3.10.7 3.10.6 2.8.16 All 261 releases
← All changes | includes/core/rest-api/Controllers/class-gutenberg-css-controller.php +119 -3 2.8.16 → 3.13.3 View file →
@@ -111,9 +111,9 @@
111 111 if ( ! $wp_filesystem ) {
112 112 require_once ABSPATH . 'wp-admin/includes/file.php';
113 113 }
114 114 $params = $request->get_params();
115 - $css = $params['css'];
115 + $css = $this->sanitize_css_content( $params['css'] );
116 116 $post_id = (int) sanitize_text_field( $params['post_id'] );
117 117 if ( $post_id ) {
118 118 $filename = "wpfnl-gb-css-{$post_id}.css";
119 119 $upload_dir = wp_upload_dir();
@@ -163,12 +163,12 @@
163 163 $post_id = (int) sanitize_text_field($params['post_id']);
164 164 $is_previewing = $params['isPreviewing'];
165 165
166 166 if ($params['is_remain']) {
167 - $qubely_block_css = $params['block_css'];
167 + $qubely_block_css = $this->sanitize_css_content($params['block_css']);
168 168 $filename = "wpfnl-css-{$post_id}.css";
169 169
170 - $qubely_block_json = $params['interaction'];
170 + $qubely_block_json = $this->sanitize_json_content($params['interaction']);
171 171 $jsonfilename = "wpfnl-json-{$post_id}.json";
172 172
173 173 $upload_dir = wp_upload_dir();
174 174 $dir = trailingslashit($upload_dir['basedir']) . 'wpfunnels/css/';
@@ -280,6 +280,122 @@
280 280 $get_css = implode( '', $fonts ) . $get_css;
281 281 }
282 282 }
283 283 return $get_css;
284 + }
285 +
286 + /**
287 + * Sanitize CSS content to prevent XSS attacks
288 + *
289 + * @param string $css The CSS content to sanitize
290 + * @return string Sanitized CSS content
291 + * @since 3.5.27
292 + */
293 + private function sanitize_css_content($css){
294 + if (!is_string($css)) {
295 + return '';
296 + }
297 +
298 + // Remove potentially dangerous CSS functions and properties
299 + $dangerous_patterns = array(
300 + '/javascript\s*:/i', // Remove javascript: URLs
301 + '/expression\s*\(/i', // Remove CSS expressions
302 + '/behavior\s*:/i', // Remove IE behavior property
303 + '/@import\s+(?!url\()/i', // Remove @import except url() imports
304 + '/binding\s*:/i', // Remove binding property
305 + '/-moz-binding\s*:/i', // Remove -moz-binding
306 + '/data\s*:\s*text\/html/i', // Remove data:text/html
307 + '/vbscript\s*:/i', // Remove vbscript: URLs
308 + '/on\w+\s*=/i', // Remove event handlers
309 + '/<script/i', // Remove script tags
310 + '/<\/script/i', // Remove closing script tags
311 + '/&lt;script/i', // Remove encoded script tags
312 + '/&lt;\/script/i', // Remove encoded closing script tags
313 + );
314 +
315 + // Apply sanitization patterns
316 + $sanitized_css = preg_replace($dangerous_patterns, '', $css);
317 +
318 + // Strip any remaining HTML/XML tags that might have sneaked in
319 + $sanitized_css = strip_tags($sanitized_css);
320 +
321 + // Additional validation for CSS structure
322 + $sanitized_css = $this->validate_css_structure($sanitized_css);
323 +
324 + return $sanitized_css;
325 + }
326 +
327 + /**
328 + * Validate CSS structure and remove potentially malicious content
329 + *
330 + * @param string $css The CSS content to validate
331 + * @return string Validated CSS content
332 + * @since 3.5.27
333 + */
334 + private function validate_css_structure($css){
335 + // Remove any content that looks like HTML/XML
336 + $css = preg_replace('/<[^>]*>/', '', $css);
337 +
338 + // Remove any remaining HTML entities that could be used for XSS
339 + $css = html_entity_decode($css, ENT_QUOTES | ENT_HTML5, 'UTF-8');
340 + $css = preg_replace('/&[#\w]+;/', '', $css);
341 +
342 + return $css;
343 + }
344 +
345 + /**
346 + * Sanitize JSON content to prevent XSS attacks
347 + *
348 + * @param mixed $json The JSON content to sanitize
349 + * @return string Sanitized JSON content
350 + * @since 3.5.27
351 + */
352 + private function sanitize_json_content($json){
353 + if (is_string($json)) {
354 + // Decode JSON to validate structure
355 + $decoded = json_decode($json, true);
356 + if (json_last_error() === JSON_ERROR_NONE) {
357 + // Recursively sanitize the decoded data
358 + $sanitized = $this->sanitize_json_data($decoded);
359 + return wp_json_encode($sanitized);
360 + }
361 + } elseif (is_array($json) || is_object($json)) {
362 + // Sanitize array/object data
363 + $sanitized = $this->sanitize_json_data($json);
364 + return wp_json_encode($sanitized);
365 + }
366 +
367 + return '{}'; // Return empty JSON object if invalid
368 + }
369 +
370 + /**
371 + * Recursively sanitize JSON data
372 + *
373 + * @param mixed $data The data to sanitize
374 + * @return mixed Sanitized data
375 + * @since 3.5.27
376 + */
377 + private function sanitize_json_data($data){
378 + if (is_array($data)) {
379 + $sanitized = array();
380 + foreach ($data as $key => $value) {
381 + $sanitized_key = sanitize_text_field($key);
382 + $sanitized[$sanitized_key] = $this->sanitize_json_data($value);
383 + }
384 + return $sanitized;
385 + } elseif (is_object($data)) {
386 + $sanitized = new \stdClass();
387 + foreach ($data as $key => $value) {
388 + $sanitized_key = sanitize_text_field($key);
389 + $sanitized->$sanitized_key = $this->sanitize_json_data($value);
390 + }
391 + return $sanitized;
392 + } elseif (is_string($data)) {
393 + // For strings, remove potential XSS vectors
394 + $data = wp_kses($data, array());
395 + $data = sanitize_text_field($data);
396 + return $data;
397 + }
398 +
399 + return $data;
284 400 }
285 401 }