Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/easy-accordion-free/Blocks/Includes/Blocks_Query.php
+++ b/easy-accordion-free/Blocks/Includes/Blocks_Query.php
@@ -14,6 +14,7 @@
use ShapedPluginEasyAccordionBlocksIncludesBlocks_Query_Handler;
use ShapedPluginEasyAccordionBlocksIncludesBlocks_Helper;
+use ShapedPluginEasyAccordionBlocksIncludesUtilsEAB_Utils;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
@@ -580,7 +581,7 @@
'metaDisplayPosition' => $attributes['metaDisplayPosition'] ?? '',
'excerptLimit' => $attributes['excerptLimit'] ?? array(),
'excerptLength' => $attributes['excerptLength'] ?? '',
- 'accordionTitleTag' => $attributes['accordionTitleTag'] ?? 'h3',
+ 'accordionTitleTag' => EAB_Utils::title_tag( $attributes['accordionTitleTag'] ?? 'h3' ),
'animationEffect' => $attributes['animationEffect'] ?? 'none',
'toggleIconsSet' => $attributes['toggleIconsSet'] ?? array(),
'enableExpandAndCollapseIcon' => (bool) ( $attributes['enableExpandAndCollapseIcon'] ?? true ),
--- a/easy-accordion-free/Blocks/Includes/Render_Blocks_Template.php
+++ b/easy-accordion-free/Blocks/Includes/Render_Blocks_Template.php
@@ -16,6 +16,7 @@
use ShapedPluginEasyAccordionBlocksIncludesBlocks_Query;
use ShapedPluginEasyAccordionBlocksIncludesTemplate_parts;
use ShapedPluginEasyAccordionBlocksIncludesUtilsDynamicCssGenerator;
+use ShapedPluginEasyAccordionBlocksIncludesUtilsEAB_Utils;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
@@ -86,7 +87,7 @@
$parent_id = $attributes['parentId'] ?? '';
$template = $attributes['template'] ?? 'vertical-one';
$parent_block_name = $attributes['parentBlockName'] ?? 'vertical-accordion';
- $accordion_title_tag = $attributes['accordionTitleTag'] ?? 'h3';
+ $accordion_title_tag = EAB_Utils::title_tag( $attributes['accordionTitleTag'] ?? 'h3' );
$accordion_title = $attributes['accordionTitle'] ?? 'No Title';
$title_alignment = $attributes['titleAlignment'] ?? 'start';
$enable_toggle_icon = $attributes['enableExpandAndCollapseIcon'] ?? true;
@@ -97,7 +98,7 @@
ob_start();
?>
- <<?php echo esc_attr( $accordion_title_tag ); ?> class='<?php echo esc_attr( "sp-eab-accordion-heading sp-d-flex sp-align-center eab-heading-$parent_id" ); ?>'
+ <<?php echo tag_escape( $accordion_title_tag ); ?> class='<?php echo esc_attr( "sp-eab-accordion-heading sp-d-flex sp-align-center eab-heading-$parent_id" ); ?>'
<?php
if ( 'sidebar-tab-accordion' === $parent_block_name ) {
echo 'data-tabid="' . esc_attr( $unique_id ) . '"';
@@ -123,7 +124,7 @@
<?php endif; ?>
</span>
</span>
- </<?php echo esc_attr( $accordion_title_tag ); ?>>
+ </<?php echo tag_escape( $accordion_title_tag ); ?>>
<?php
return ob_get_clean();
}
@@ -300,7 +301,7 @@
$parent_settings = $attributes['parentSettings'] ?? array();
$content_alignment = $parent_settings['contentAlignment'] ?? 'center';
$template = $parent_settings['template'] ?? '';
- $accordion_tag = $parent_settings['accordionTitleTag'] ?? 'h3';
+ $accordion_tag = EAB_Utils::title_tag( $parent_settings['accordionTitleTag'] ?? 'h3' );
$show_title = ! empty( $parent_settings['showTitle'] );
$show_desc = ! empty( $parent_settings['showDescription'] );
$active_event = $parent_settings['activeEvent'] ?? 'click';
--- a/easy-accordion-free/Blocks/Includes/Template_parts.php
+++ b/easy-accordion-free/Blocks/Includes/Template_parts.php
@@ -17,6 +17,7 @@
}
use PhpMyAdminSqlParserStatement;
+use ShapedPluginEasyAccordionBlocksIncludesUtilsEAB_Utils;
class Template_parts {
@@ -550,7 +551,7 @@
*/
public static function eab_render_product_name( $title_data = array() ) {
$title = isset( $title_data['title'] ) ? $title_data['title'] : '';
- $title_tag = ! empty( $title_data['accordionTitleTag'] ) ? $title_data['accordionTitleTag'] : 'h3';
+ $title_tag = EAB_Utils::title_tag( $title_data['accordionTitleTag'] ?? 'h3' );
if ( empty( $title ) ) {
return;
@@ -673,14 +674,14 @@
<div class="sp-eab-accordion-item-wrapper">
<!-- Accordion Heading -->
- <<?php echo tag_escape( $context['accordionTitleTag'] ); ?>
+ <<?php echo tag_escape( EAB_Utils::title_tag( $context['accordionTitleTag'] ?? 'h3' ) ); ?>
class="sp-eab-accordion-heading sp-d-flex sp-align-center"
role="button"
tabindex="0">
<?php
echo self::accordion_post_header_renderer($header_data, $image_data); // phpcs:ignore
?>
- </<?php echo tag_escape( $context['accordionTitleTag'] ); ?>>
+ </<?php echo tag_escape( EAB_Utils::title_tag( $context['accordionTitleTag'] ?? 'h3' ) ); ?>>
<!-- Accordion Content -->
<div class="sp-eab-accordion-content">
--- a/easy-accordion-free/Blocks/Includes/Utils/EAB_Utils.php
+++ b/easy-accordion-free/Blocks/Includes/Utils/EAB_Utils.php
@@ -20,6 +20,54 @@
class EAB_Utils {
/**
+ * Allowed HTML tags for block titles.
+ *
+ * @var array
+ */
+ const ALLOWED_TITLE_TAGS = array( 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'span' );
+
+ /**
+ * Restrict a title tag to the allowed list.
+ *
+ * Block attributes are attacker controlled (post content can be crafted by
+ * any user who can edit a post), so the tag name must never be echoed
+ * without being matched against a whitelist.
+ *
+ * @param mixed $tag Tag name coming from block attributes.
+ * @param string $fallback Tag used when the given one is not allowed.
+ *
+ * @return string Safe tag name.
+ */
+ public static function title_tag( $tag, $fallback = 'h3' ) {
+ if ( ! is_string( $tag ) ) {
+ return $fallback;
+ }
+
+ $tag = strtolower( trim( $tag ) );
+
+ return in_array( $tag, self::ALLOWED_TITLE_TAGS, true ) ? $tag : $fallback;
+ }
+
+ /**
+ * Generate a title tag attribute definition.
+ *
+ * The enum makes WP_Block_Type::prepare_attributes_for_render() drop any
+ * tag name outside the allowed list, so the default is restored before the
+ * value ever reaches a render callback.
+ *
+ * @param string $value Default tag name.
+ *
+ * @return array Title tag attribute configuration.
+ */
+ public static function title_tag_attr( $value = 'h3' ) {
+ return array(
+ 'type' => 'string',
+ 'default' => $value,
+ 'enum' => self::ALLOWED_TITLE_TAGS,
+ );
+ }
+
+ /**
* Generate a colors attribute definition.
*
* @param string $normal Default normal color.
--- a/easy-accordion-free/Blocks/Includes/attributes.php
+++ b/easy-accordion-free/Blocks/Includes/attributes.php
@@ -37,7 +37,7 @@
* @var array
*/
$accordion_title_attributes = array(
- 'accordionTitleTag' => EAB_Utils::string( 'h3' ),
+ 'accordionTitleTag' => EAB_Utils::title_tag_attr( 'h3' ),
'titleAlignment' => EAB_Utils::string( 'left' ),
'accordionTitleTypography' => EAB_Utils::typography( '500' ),
'accordionTitleFontSize' => EAB_Utils::single_responsive( 18 ),
--- a/easy-accordion-free/Blocks/Includes/block-attributes.php
+++ b/easy-accordion-free/Blocks/Includes/block-attributes.php
@@ -29,7 +29,7 @@
'template' => EAB_Utils::string(),
'defaultOpen' => EAB_Utils::boolean(),
'schemaMarkup' => EAB_Utils::boolean(),
- 'accordionTitleTag' => EAB_Utils::string( 'h3' ),
+ 'accordionTitleTag' => EAB_Utils::title_tag_attr( 'h3' ),
'accordionTitle' => EAB_Utils::string( null ),
'titleAlignment' => EAB_Utils::string( 'left' ),
'enableExpandAndCollapseIcon' => EAB_Utils::boolean( true ),
@@ -98,7 +98,7 @@
'imgOverlayColor' => EAB_Utils::string( '#00000075' ),
'showTitle' => EAB_Utils::boolean( true ),
'accordionTitleColors' => EAB_Utils::string( '#fff' ),
- 'accordionTitleTag' => EAB_Utils::string( 'h3' ),
+ 'accordionTitleTag' => EAB_Utils::title_tag_attr( 'h3' ),
'showDescription' => EAB_Utils::boolean( true ),
'linkOpenInNewTab' => EAB_Utils::boolean(),
'contentAlignment' => EAB_Utils::string( 'center' ),
--- a/easy-accordion-free/plugin-main.php
+++ b/easy-accordion-free/plugin-main.php
@@ -7,7 +7,7 @@
* Author URI: https://shapedplugin.com/
* License: GPL-2.0+
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
- * Version: 3.1.8
+ * Version: 3.1.9
* Requires at least: 5.9
* Requires PHP: 7.4
* Text Domain: easy-accordion-free
@@ -63,7 +63,7 @@
*
* @var string
*/
- public $version = '3.1.8';
+ public $version = '3.1.9';
/**
* The name of the plugin.
--- a/easy-accordion-free/public/eap-frontend.php
+++ b/easy-accordion-free/public/eap-frontend.php
@@ -142,7 +142,7 @@
$eap_offset_to_scroll = apply_filters( 'eap_offset_to_scroll', 0 );
$eap_accordion_fillspace_height = isset( $shortcode_data['eap_accordion_fillspace_height']['all'] ) ? $shortcode_data['eap_accordion_fillspace_height']['all'] : '200';
- $eap_title_tag = isset( $shortcode_data['ea_title_heading_tag'] ) ? 'h' . $shortcode_data['ea_title_heading_tag'] : 'h3';
+ $eap_title_tag = isset( $shortcode_data['ea_title_heading_tag'] ) && in_array( (string) $shortcode_data['ea_title_heading_tag'], array( '1', '2', '3', '4', '5', '6' ), true ) ? 'h' . $shortcode_data['ea_title_heading_tag'] : 'h3';
$acc_section_title = isset( $shortcode_data['section_title'] ) ? $shortcode_data['section_title'] : '';
// Expand / Collapse Icon.
--- a/easy-accordion-free/public/templates/templates-parts/single-item.php
+++ b/easy-accordion-free/public/templates/templates-parts/single-item.php
@@ -15,7 +15,7 @@
<!-- Start accordion card div. -->
<div class="ea-card <?php echo esc_attr( $accordion_mode['expand_class'] . ' ' . $accordion_item_class ); ?>">
<!-- Start accordion header. -->
- <<?php echo esc_attr( $eap_title_tag ); ?> class="ea-header">
+ <<?php echo tag_escape( $eap_title_tag ); ?> class="ea-header">
<!-- Add anchor tag for header. -->
<a class="collapsed" id="ea-header-<?php echo esc_attr( $post_id . $key ); ?>" role="button" data-sptoggle="spcollapse" data-sptarget="<?php echo esc_attr( $data_sptarget ); ?>" aria-controls="collapse<?php echo esc_attr( $post_id . $key ); ?>" href="#" <?php echo esc_attr( $nofollow_link_text ); ?> aria-expanded="<?php echo esc_attr( $accordion_mode['aria_expanded'] ); ?>" tabindex="0">
<?php
@@ -23,7 +23,7 @@
echo wp_kses_post( $eap_icon_markup . $content_title );
?>
</a><!-- Close anchor tag for header. -->
- </<?php echo esc_attr( $eap_title_tag ); ?>> <!-- Close header tag. -->
+ </<?php echo tag_escape( $eap_title_tag ); ?>> <!-- Close header tag. -->
<!-- Start collapsible content div. -->
<div class="sp-collapse spcollapse <?php echo esc_attr( $accordion_mode['open_first'] ); ?>" id="collapse<?php echo esc_attr( $post_id . $key ); ?>" <?php echo wp_kses_post( $eap_single_collapse ); ?> role="region" aria-labelledby="ea-header-<?php echo esc_attr( $post_id . $key ); ?>"> <!-- Content div. -->
<div class="ea-body">