Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/gutenverse/gutenverse.php
+++ b/gutenverse/gutenverse.php
@@ -4,7 +4,7 @@
* Description: Collection of easy to use and customizable blocks for WordPress Block Editor. Build a great website using block provided with Gutenverse.
* Plugin URI: https://gutenverse.com/
* Author: Jegstudio
- * Version: 3.4.6
+ * Version: 3.4.7
* Author URI: https://jegtheme.com/
* License: GPLv3
* Text Domain: gutenverse
@@ -15,7 +15,7 @@
use GutenverseGutenverse;
defined( 'GUTENVERSE' ) || define( 'GUTENVERSE', 'gutenverse' );
-defined( 'GUTENVERSE_VERSION' ) || define( 'GUTENVERSE_VERSION', '3.4.6' );
+defined( 'GUTENVERSE_VERSION' ) || define( 'GUTENVERSE_VERSION', '3.4.7' );
defined( 'GUTENVERSE_NOTICE_VERSION' ) || define( 'GUTENVERSE_NOTICE_VERSION', '3.4.0' );
defined( 'GUTENVERSE_NAME' ) || define( 'GUTENVERSE_NAME', 'Gutenverse' );
defined( 'GUTENVERSE_URL' ) || define( 'GUTENVERSE_URL', plugins_url( GUTENVERSE ) );
--- a/gutenverse/includes/block/class-archive-title.php
+++ b/gutenverse/includes/block/class-archive-title.php
@@ -31,8 +31,10 @@
$link_target = ! empty( $this->attributes['archiveLinkTarget'] ) ? '_blank' : '_self';
$link_rel = ! empty( $this->attributes['archiveLinkRel'] ) ? esc_attr( $this->attributes['archiveLinkRel'] ) : 'noreferrer';
+ $archive_title = esc_html( $archive_title );
+
if ( $category_url ) {
- $archive_title = "<a href='{$category_url}' target='{$link_target}' rel='{$link_rel}'>{$archive_title}</a>";
+ $archive_title = "<a href='" . esc_url( $category_url ) . "' target='{$link_target}' rel='{$link_rel}'>{$archive_title}</a>";
}
return "<{$html_tag}>{$archive_title}</{$html_tag}>";
--- a/gutenverse/includes/block/class-breadcrumb.php
+++ b/gutenverse/includes/block/class-breadcrumb.php
@@ -83,8 +83,8 @@
$is_not_last = $index < ( $data_length - 1 );
- $item_name = $data[ $index ]['name'];
- $item_url = $data[ $index ]['url'];
+ $item_name = esc_html( $data[ $index ]['name'] );
+ $item_url = esc_url( $data[ $index ]['url'] );
$position = $index + 1;
$link = ( $is_not_last || $this->attributes['hideCurrentTitle'] )
@@ -98,7 +98,11 @@
</li>";
if ( $is_not_last ) {
- $separator_icon = $this->render_icon( $this->attributes['separatorIconType'], $this->attributes['separatorIcon'], $this->attributes['separatorIconSVG'] );
+ $separator_icon_type = isset( $this->attributes['separatorIconType'] ) ? $this->attributes['separatorIconType'] : 'icon';
+ $the_icon = isset( $this->attributes['separatorIcon'] ) ? $this->attributes['separatorIcon'] : 'fas fa-chevron-right';
+ $separator_icon_svg = isset( $this->attributes['separatorIconSVG'] ) ? $this->attributes['separatorIconSVG'] : '';
+
+ $separator_icon = $this->render_icon( $separator_icon_type, $the_icon, $separator_icon_svg );
$component .= "
<li class='separator'>
{$separator_icon}
--- a/gutenverse/includes/block/class-nav-menu.php
+++ b/gutenverse/includes/block/class-nav-menu.php
@@ -107,7 +107,7 @@
$src = '';
$width = '';
$height = '';
- $loading = $lazy ? 'lazy' : 'eager';
+ $loading = ( 'lazy' === $lazy || true === $lazy ) ? 'lazy' : 'eager';
if ( ! empty( $media['sizes'][ $size ]['url'] ) ) {
$src = $media['sizes'][ $size ]['url'];
--- a/gutenverse/includes/block/class-post-featured-image.php
+++ b/gutenverse/includes/block/class-post-featured-image.php
@@ -45,11 +45,11 @@
if ( ! empty( $post_featured ) ) {
$content = get_the_post_thumbnail( $post_id, $image_size['value'], array( 'loading' => $image_load ) );
} elseif ( ! empty( $placeholder_img ) ) {
- $content = '<img loading="' . $image_load . '" alt="post thumbnail placeholder" src="' . esc_url( GUTENVERSE_URL . '/assets/img/img-placeholder.jpg' ) . '"/>';
+ $content = '<img loading="' . esc_attr( $image_load ) . '" alt="post thumbnail placeholder" src="' . esc_url( GUTENVERSE_URL . '/assets/img/img-placeholder.jpg' ) . '"/>';
}
if ( ! empty( $post_link ) && ! empty( $post_url ) ) {
- $content = '<a href="' . $post_url . '" class="' . $element_id . $display_classes . $animation_class . $custom_classes . ' guten-element guten-post-featured-image">' . $content . '</a>';
+ $content = '<a href="' . esc_url( $post_url ) . '" class="' . $element_id . $display_classes . $animation_class . $custom_classes . ' guten-element guten-post-featured-image">' . $content . '</a>';
} else {
$content = '<div class="' . $element_id . $display_classes . $animation_class . $custom_classes . ' guten-element guten-post-featured-image">' . $content . '</div>';
}
--- a/gutenverse/includes/block/class-post-title.php
+++ b/gutenverse/includes/block/class-post-title.php
@@ -28,11 +28,11 @@
$html_tag = esc_html( $this->check_tag( $this->attributes['htmlTag'], 'h2' ) );
$post_link = ! empty( $this->attributes['postLink'] ) ? $this->attributes['postLink'] : false;
$link_target = ! empty( $this->attributes['postLinkTarget'] ) ? '_blank' : '_self';
- $link_rel = ! empty( $this->attributes['postLinkRel'] ) ? esc_html( $this->attributes['postLinkRel'] ) : 'noreferrer';
- $post_title = $post_id ? get_the_title( $post_id ) : esc_html__( 'Post Title', 'gutenverse' );
+ $link_rel = ! empty( $this->attributes['postLinkRel'] ) ? esc_attr( $this->attributes['postLinkRel'] ) : 'noreferrer';
+ $post_title = $post_id ? esc_html( get_the_title( $post_id ) ) : esc_html__( 'Post Title', 'gutenverse' );
if ( $post_link ) {
- $post_url = get_permalink( $post_id );
+ $post_url = esc_url( get_permalink( $post_id ) );
$post_title = "<a href='{$post_url}' target='{$link_target}' rel='{$link_rel}'>{$post_title}</a>";
}
--- a/gutenverse/includes/block/class-search-result-title.php
+++ b/gutenverse/includes/block/class-search-result-title.php
@@ -25,8 +25,8 @@
*/
public function render_content() {
$html_tag = esc_html( $this->check_tag( $this->attributes['htmlTag'], 'h2' ) );
- $search_input = get_query_var( 's' );
- $static_text = $this->attributes['staticText'] ? $this->attributes['staticText'] : 'Search Result For:';
+ $search_input = esc_html( get_query_var( 's' ) );
+ $static_text = esc_html( $this->attributes['staticText'] ? $this->attributes['staticText'] : 'Search Result For:' );
return "<{$html_tag}>{$static_text} <span class='search-input-text'>{$search_input}</span></{$html_tag}>";
}
--- a/gutenverse/includes/style/class-post-list.php
+++ b/gutenverse/includes/style/class-post-list.php
@@ -41,8 +41,14 @@
$this->set_feature(
array(
- 'background' => null,
- 'border' => null,
+ 'background' => array(
+ 'normal' => ".{$this->element_id}.guten-element",
+ 'hover' => ".{$this->element_id}.guten-element:hover",
+ ),
+ 'border' => array(
+ 'normal' => ".{$this->element_id}.guten-element",
+ 'hover' => ".{$this->element_id}.guten-element:hover",
+ ),
'positioning' => null,
'animation' => null,
'advance' => null,
--- a/gutenverse/lib/dependencies/blocks.asset.php
+++ b/gutenverse/lib/dependencies/blocks.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('gutenverse-dep-animejs-script', 'react', 'react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-date', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-keycodes', 'wp-server-side-render', 'wp-url'), 'version' => '926983164eba563bfcc6');
+<?php return array('dependencies' => array('gutenverse-dep-animejs-script', 'react', 'react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-date', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-keycodes', 'wp-server-side-render', 'wp-url'), 'version' => 'c2a592b56e7570fd39ab');
--- a/gutenverse/lib/dependencies/frontend/animated-text.asset.php
+++ b/gutenverse/lib/dependencies/frontend/animated-text.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('gutenverse-dep-animejs-script'), 'version' => 'dabeff2bf92998238f75');
+<?php return array('dependencies' => array('gutenverse-dep-animejs-script'), 'version' => '2e0394cda1afc82161fc');
--- a/gutenverse/lib/dependencies/frontend/chart.asset.php
+++ b/gutenverse/lib/dependencies/frontend/chart.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array(), 'version' => '15b28e44d95b3c1182f4');
+<?php return array('dependencies' => array(), 'version' => 'a5bc3e81f50d12dbf649');
--- a/gutenverse/lib/dependencies/frontend/popup-builder.asset.php
+++ b/gutenverse/lib/dependencies/frontend/popup-builder.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array(), 'version' => '74ffbb7e5ba0e2453575');
+<?php return array('dependencies' => array(), 'version' => '93e9678c74e40f48facf');
--- a/gutenverse/lib/dependencies/frontend/team.asset.php
+++ b/gutenverse/lib/dependencies/frontend/team.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array(), 'version' => 'b8d08e372a7766b532b0');
+<?php return array('dependencies' => array(), 'version' => 'bea6f3f8ac91786baa96');
--- a/gutenverse/lib/dependencies/wizard.asset.php
+++ b/gutenverse/lib/dependencies/wizard.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-element', 'wp-i18n'), 'version' => '88cf039401e6f014f962');
+<?php return array('dependencies' => array('react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-element', 'wp-i18n'), 'version' => '125587a4e79ae4bcac51');
--- a/gutenverse/lib/framework/bootstrap.php
+++ b/gutenverse/lib/framework/bootstrap.php
@@ -15,7 +15,7 @@
return;
}
-defined( 'GUTENVERSE_FRAMEWORK_VERSION' ) || define( 'GUTENVERSE_FRAMEWORK_VERSION', '2.4.6' );
+defined( 'GUTENVERSE_FRAMEWORK_VERSION' ) || define( 'GUTENVERSE_FRAMEWORK_VERSION', '2.4.7' );
defined( 'GUTENVERSE_FRAMEWORK_ASSETS_VERSION' ) || define( 'GUTENVERSE_FRAMEWORK_ASSETS_VERSION', '2.1.0' );
defined( 'GUTENVERSE_FRAMEWORK_DIR' ) || define( 'GUTENVERSE_FRAMEWORK_DIR', __DIR__ );
defined( 'GUTENVERSE_FRAMEWORK_CLASS_DIR' ) || define( 'GUTENVERSE_FRAMEWORK_CLASS_DIR', GUTENVERSE_FRAMEWORK_DIR . '/includes' );
--- a/gutenverse/lib/framework/includes/block/class-block-abstract.php
+++ b/gutenverse/lib/framework/includes/block/class-block-abstract.php
@@ -272,6 +272,10 @@
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
$svg_data = base64_decode( $svg, true );
+ if ( ! gutenverse_is_svg_safe( $svg_data ) ) {
+ return '';
+ }
+
$gradients = '';
if ( $icon_gradient || $icon_gradient_hover ) {
if ( empty( $element_id ) ) {
--- a/gutenverse/lib/framework/includes/block/class-post-abstract.php
+++ b/gutenverse/lib/framework/includes/block/class-post-abstract.php
@@ -758,8 +758,8 @@
$next_text = $next_innet_text . ' ' . $this->render_icon( $next_icon_type, $next_icon, $next_icon_svg );
}
- $prev_link = 1 === $page ? '' : '<a href="#" class="btn-pagination prev ' . esc_attr( $prev ) . '" title="' . $prev_inner_text . '">' . $prev_text . '</a>';
- $next_link = $total <= $page ? '' : '<a href="#" class="btn-pagination next ' . esc_attr( $next ) . '" title="' . $next_innet_text . '">' . $next_text . '</a>';
+ $prev_link = 1 === $page ? '<a href="#" class="btn-pagination prev disabled ' . esc_attr( $prev ) . '" title="' . $prev_inner_text . '">' . $prev_text . '</a>' : '<a href="#" class="btn-pagination prev ' . esc_attr( $prev ) . '" title="' . $prev_inner_text . '">' . $prev_text . '</a>';
+ $next_link = $total <= $page ? '<a href="#" class="btn-pagination next disabled ' . esc_attr( $next ) . '" title="' . $next_innet_text . '">' . $next_text . '</a>' : '<a href="#" class="btn-pagination next ' . esc_attr( $next ) . '" title="' . $next_innet_text . '">' . $next_text . '</a>';
$output =
'<div class="guten_block_nav ' . esc_attr( 'additional_class' ) . '" data-page="' . $page . '">
@@ -781,6 +781,8 @@
if ( $page > 1 ) {
$output .= '<a href="#" class="btn-pagination prev" title="' . $prev_inner_text . "">{$prev_text}</a> ";
+ } else {
+ $output .= '<a href="#" class="btn-pagination prev disabled" title="' . $prev_inner_text . "">{$prev_text}</a> ";
}
if ( $page > 2 ) {
@@ -809,6 +811,8 @@
if ( $page < $total ) {
$output .= '<a href="#" class="btn-pagination next" title="' . esc_html__( 'Next', 'gutenverse' ) . "">{$next_text}</a>";
+ } else {
+ $output .= '<a href="#" class="btn-pagination next disabled" title="' . esc_html__( 'Next', 'gutenverse' ) . "">{$next_text}</a>";
}
$output .= '</div>';
@@ -830,7 +834,7 @@
$next_text = $next_innet_text . ' ' . $this->render_icon( $next_icon_type, $next_icon, $next_icon_svg );
}
- $prev_link = 1 === $page ? '' : sprintf(
+ $prev_link = sprintf(
'<a href="%s" class="btn-pagination prev %s" title="%s">%s</a>',
esc_url( $prev_url ),
esc_attr( $prev_class ),
@@ -838,7 +842,7 @@
$prev_text
);
- $next_link = $total <= $page ? '' : sprintf(
+ $next_link = sprintf(
'<a href="%s" class="btn-pagination next %s" title="%s">%s</a>',
esc_url( $next_url ),
esc_attr( $next_class ),
@@ -878,6 +882,12 @@
esc_attr( $prev_inner_text ),
$prev_text
);
+ } else {
+ $output .= sprintf(
+ '<a href="#" class="btn-pagination prev disabled" title="%s">%s</a> ',
+ esc_attr( $prev_inner_text ),
+ $prev_text
+ );
}
// First page + ellipsis.
@@ -936,6 +946,12 @@
esc_html__( 'Next', 'gutenverse' ),
$next_text
);
+ } else {
+ $output .= sprintf(
+ '<a href="#" class="btn-pagination next disabled" title="%s">%s</a>',
+ esc_html__( 'Next', 'gutenverse' ),
+ $next_text
+ );
}
$output .= '</div>';
--- a/gutenverse/lib/framework/includes/class-api.php
+++ b/gutenverse/lib/framework/includes/class-api.php
@@ -516,13 +516,17 @@
*/
public function install_theme( $request ) {
$theme = $this->gutenverse_api_esc_data( $request->get_param( 'slug' ), 'string' );
- $info = $this->gutenverse_api_esc_data( $request->get_param( 'info' ), 'string' );
+ $info = esc_url_raw( $request->get_param( 'info' ) );
$key = $this->gutenverse_api_esc_data( $request->get_param( 'key' ), 'string' );
if ( empty( $info ) ) {
$info = GUTENVERSE_FRAMEWORK_LIBRARY_URL . '/wp-json/gutenverse-server/v1/theme/information';
}
+ if ( ! wp_http_validate_url( $info ) ) {
+ return false;
+ }
+
$request = wp_remote_post(
$info,
array(
@@ -1770,7 +1774,7 @@
* @param object $request images.
*/
public function import_images( $request ) {
- $image = $request->get_param( 'imageUrl' );
+ $image = esc_url_raw( $request->get_param( 'imageUrl' ) );
$data = $this->check_image_exist( $image );
if ( ! $data ) {
@@ -1821,14 +1825,41 @@
* @return int|null
*/
public function handle_file( $url ) {
- $file_name = basename( $url );
- $upload = wp_upload_bits( $file_name, null, '' );
- $this->fetch_file( $url, $upload['file'] );
+ $url_path = wp_parse_url( $url, PHP_URL_PATH );
+ $file_name = basename( $url_path );
+
+ if ( empty( $file_name ) || strpos( $file_name, '.' ) === false ) {
+ $file_name = 'image.jpg';
+ }
- if ( $upload['file'] ) {
+ $upload = wp_upload_bits( $file_name, null, '' );
+ if ( ! $this->fetch_file( $url, $upload['file'] ) ) {
+ if ( ! empty( $upload['file'] ) && file_exists( $upload['file'] ) ) {
+ unlink( $upload['file'] );
+ }
+ return null;
+ }
+
+ if ( ! empty( $upload['file'] ) && file_exists( $upload['file'] ) ) {
$file_loc = $upload['file'];
- $file_name = basename( $upload['file'] );
- $file_type = wp_check_filetype( $file_name );
+ $file_type = wp_check_filetype( $file_loc );
+
+ // Ensure it's an allowed image type
+ $allowed_mimes = array( 'image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml' );
+ if ( ! in_array( $file_type['type'], $allowed_mimes, true ) ) {
+ unlink( $file_loc );
+ return null;
+ }
+
+ // For SVG, extra safety
+ if ( $file_type['type'] === 'image/svg+xml' ) {
+ // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
+ $svg_content = file_get_contents( $file_loc );
+ if ( ! gutenverse_is_svg_safe( $svg_content ) ) {
+ unlink( $file_loc );
+ return null;
+ }
+ }
$attachment = array(
'post_mime_type' => $file_type['type'],
@@ -1878,6 +1909,10 @@
* @return array|bool
*/
public function fetch_file( $url, $file_path, $endpoint = '' ) {
+ if ( ! wp_http_validate_url( $url ) ) {
+ return false;
+ }
+
$http = new WP_Http();
$response = $http->get(
add_query_arg(
--- a/gutenverse/lib/framework/includes/class-dashboard.php
+++ b/gutenverse/lib/framework/includes/class-dashboard.php
@@ -570,6 +570,10 @@
'plugin_version' => '3.4.6',
'framework_version' => '2.4.6',
),
+ array(
+ 'plugin_version' => '3.4.7',
+ 'framework_version' => '2.4.7',
+ ),
),
'gutenverse-form' => array(
array(
@@ -728,6 +732,10 @@
'plugin_version' => '2.4.5',
'framework_version' => '2.4.5',
),
+ array(
+ 'plugin_version' => '2.4.7',
+ 'framework_version' => '2.4.7',
+ ),
),
'gutenverse-news' => array(
array(
@@ -868,6 +876,10 @@
'plugin_version' => '2.4.5',
'framework_version' => '2.4.5',
),
+ array(
+ 'plugin_version' => '2.4.7',
+ 'framework_version' => '2.4.7',
+ ),
),
);
--- a/gutenverse/lib/framework/includes/class-options.php
+++ b/gutenverse/lib/framework/includes/class-options.php
@@ -89,7 +89,9 @@
*/
public function get_image_load( $old_option = 'lazy', $old_option_value = false, $attr = '' ) {
if ( isset( $attr ) && ! empty( $attr ) ) {
- return $attr;
+ if ( in_array( $attr, array( 'lazy', 'eager' ), true ) ) {
+ return $attr;
+ }
}
if ( ! $old_option ) {
return $this->default_image_load;
--- a/gutenverse/lib/framework/lib/dependencies/core.asset.php
+++ b/gutenverse/lib/framework/lib/dependencies/core.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('lodash', 'react', 'react-dom', 'react-jsx-runtime', 'wp-a11y', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-date', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-keycodes', 'wp-primitives', 'wp-rich-text', 'wp-url'), 'version' => 'a90b3a0c0023e2d8b149');
+<?php return array('dependencies' => array('lodash', 'react', 'react-dom', 'react-jsx-runtime', 'wp-a11y', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-date', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-keycodes', 'wp-primitives', 'wp-rich-text', 'wp-url'), 'version' => 'c42935e0fd23e697d8d8');