CVE-2021-21365: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Bootstrap Package is a theme for TYPO3. It has been discovered that rendering content in the website frontend is vulnerable to cross-site scripting. A valid backend user account is needed to exploit this vulnerability. Users of the extension, who have overwritten the affected templates with custom code must manually apply the security fix. Update to version 7.1.2, 8.0.8, 9.1.4, 10.0.10 or 11.0.3 of the Bootstrap Package that fix the problem described. Updated version are available from the TYPO3 extension manager, Packagist and at https://extensions.typo3.org/extension/download/bootstrap_package/.
CWE description: The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
CVSS v3 base score: 5.4
Published: 2021-04-27T20:15Z
Repository: https://github.com/benjaminkott/bootstrap_package
Language: HTML
Files changed: Resources/Private/Partials/ContentElements/Carousel/Item/CallToAction.html, Resources/Private/Partials/ContentElements/Carousel/Item/Header.html, Resources/Private/Partials/ContentElements/Carousel/Item/Text.html, Resources/Private/Partials/ContentElements/Carousel/Item/TextAndImage.html, Resources/Private/Partials/ContentElements/Header/SubHeader.html
Commit date: 2021-04-23 14:25:27 +0200
Commit message: [SECURITY] Ensure content element subheader is HTML encoded

Diff: diff --git a/Resources/Private/Partials/ContentElements/Carousel/Item/CallToAction.html b/Resources/Private/Partials/ContentElements/Carousel/Item/CallToAction.html
index e39c91fd..864839e0 100644
--- a/Resources/Private/Partials/ContentElements/Carousel/Item/CallToAction.html
+++ b/Resources/Private/Partials/ContentElements/Carousel/Item/CallToAction.html
@@ -2,13 +2,13 @@
     <div class="vcontainer">
         <div class="carousel-box">
             <f:if condition="{item.data.nav_title}">
                 <div>{item.data.nav_title}</div>
             </f:if>
-            <h{item.data.header_layout} class="carousel-item-header{f:if(condition: item.data.header_class, then: ' {item.data.header_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlentitiesDecode>{item.data.header}</f:format.htmlentitiesDecode></h{item.data.header_layout}>
+            <h{item.data.header_layout} class="carousel-item-header{f:if(condition: item.data.header_class, then: ' {item.data.header_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlspecialchars doubleEncode="false">{item.data.header}</f:format.htmlspecialchars></h{item.data.header_layout}>
             <f:if condition="{item.data.subheader}">
-                <h{item.data.subheader_layout} class="carousel-item-subheader{f:if(condition: item.data.subheader_class, then: ' {item.data.subheader_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlentitiesDecode>{item.data.subheader}</f:format.htmlentitiesDecode></h{item.data.subheader_layout}>
+                <h{item.data.subheader_layout} class="carousel-item-subheader{f:if(condition: item.data.subheader_class, then: ' {item.data.subheader_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlspecialchars doubleEncode="false">{item.data.subheader}</f:format.htmlspecialchars></h{item.data.subheader_layout}>
             </f:if>
             <f:if condition="{item.data.bodytext}">
                 <div class="carousel-item-bodytext">
                     <f:format.html>{item.data.bodytext}</f:format.html>
                 </div>
diff --git a/Resources/Private/Partials/ContentElements/Carousel/Item/Header.html b/Resources/Private/Partials/ContentElements/Carousel/Item/Header.html
index 8101e17e..4a06e1de 100644
--- a/Resources/Private/Partials/ContentElements/Carousel/Item/Header.html
+++ b/Resources/Private/Partials/ContentElements/Carousel/Item/Header.html
@@ -1,13 +1,13 @@
 <html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
 <f:link.typolink parameter="{item.data.link}" additionalAttributes="{draggable:'false'}">
     <div class="valign" {f:if(condition: item.data.text_color,then:'style="color: {item.data.text_color};"')}>
         <div class="vcontainer">
             <div class="carousel-text-inner">
-                <h{item.data.header_layout} class="carousel-header awesome{f:if(condition: item.data.header_class, then: ' {item.data.header_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlentitiesDecode>{item.data.header}</f:format.htmlentitiesDecode></h{item.data.header_layout}>
+                <h{item.data.header_layout} class="carousel-header awesome{f:if(condition: item.data.header_class, then: ' {item.data.header_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlspecialchars doubleEncode="false">{item.data.header}</f:format.htmlspecialchars></h{item.data.header_layout}>
                 <f:if condition="{item.data.subheader}">
-                    <h{item.data.subheader_layout} class="carousel-subheader awesome{f:if(condition: item.data.subheader_class, then: ' {item.data.subheader_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlentitiesDecode>{item.data.subheader}</f:format.htmlentitiesDecode></h{item.data.subheader_layout}>
+                    <h{item.data.subheader_layout} class="carousel-subheader awesome{f:if(condition: item.data.subheader_class, then: ' {item.data.subheader_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlspecialchars doubleEncode="false">{item.data.subheader}</f:format.htmlspecialchars></h{item.data.subheader_layout}>
                 </f:if>
             </div>
         </div>
     </div>
 </f:link.typolink>
diff --git a/Resources/Private/Partials/ContentElements/Carousel/Item/Text.html b/Resources/Private/Partials/ContentElements/Carousel/Item/Text.html
index 648bcb64..238a2f20 100644
--- a/Resources/Private/Partials/ContentElements/Carousel/Item/Text.html
+++ b/Resources/Private/Partials/ContentElements/Carousel/Item/Text.html
@@ -2,13 +2,13 @@
     <div class="vcontainer">
         <div class="carousel-text-inner">
             <f:if condition="{item.data.nav_title}">
                 <div>{item.data.nav_title}</div>
             </f:if>
-            <h{item.data.header_layout} class="carousel-item-header{f:if(condition: item.data.header_class, then: ' {item.data.header_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlentitiesDecode>{item.data.header}</f:format.htmlentitiesDecode></h{item.data.header_layout}>
+            <h{item.data.header_layout} class="carousel-item-header{f:if(condition: item.data.header_class, then: ' {item.data.header_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlspecialchars doubleEncode="false">{item.data.header}</f:format.htmlspecialchars></h{item.data.header_layout}>
             <f:if condition="{item.data.subheader}">
-                <h{item.data.subheader_layout} class="carousel-item-subheader{f:if(condition: item.data.subheader_class, then: ' {item.data.subheader_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlentitiesDecode>{item.data.subheader}</f:format.htmlentitiesDecode></h{item.data.subheader_layout}>
+                <h{item.data.subheader_layout} class="carousel-item-subheader{f:if(condition: item.data.subheader_class, then: ' {item.data.subheader_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlspecialchars doubleEncode="false">{item.data.subheader}</f:format.htmlspecialchars></h{item.data.subheader_layout}>
             </f:if>
             <f:if condition="{item.data.bodytext}">
                 <div class="carousel-item-bodytext">
                     <f:format.html>{item.data.bodytext}</f:format.html>
                 </div>
diff --git a/Resources/Private/Partials/ContentElements/Carousel/Item/TextAndImage.html b/Resources/Private/Partials/ContentElements/Carousel/Item/TextAndImage.html
index b942c2df..4e0a1af1 100644
--- a/Resources/Private/Partials/ContentElements/Carousel/Item/TextAndImage.html
+++ b/Resources/Private/Partials/ContentElements/Carousel/Item/TextAndImage.html
@@ -1,12 +1,12 @@
 <html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
 <f:link.typolink parameter="{item.data.link}" additionalAttributes="{draggable:'false'}">
     <div class="valign">
         <div class="carousel-text vcontainer" {f:if(condition: item.data.text_color,then: 'style="color: {item.data.text_color};"')}>
-            <h{item.data.header_layout} class="carousel-header{f:if(condition: item.data.header_class, then: ' {item.data.header_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlentitiesDecode>{item.data.header}</f:format.htmlentitiesDecode></h{item.data.header_layout}>
+        <h{item.data.header_layout} class="carousel-header{f:if(condition: item.data.header_class, then: ' {item.data.header_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlspecialchars doubleEncode="false">{item.data.header}</f:format.htmlspecialchars></h{item.data.header_layout}>
             <f:if condition="{item.data.subheader}">
-                <h{item.data.subheader_layout} class="carousel-subheader{f:if(condition: item.data.subheader_class, then: ' {item.data.subheader_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlentitiesDecode>{item.data.subheader}</f:format.htmlentitiesDecode></h{item.data.subheader_layout}>
+                <h{item.data.subheader_layout} class="carousel-subheader{f:if(condition: item.data.subheader_class, then: ' {item.data.subheader_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlspecialchars doubleEncode="false">{item.data.subheader}</f:format.htmlspecialchars></h{item.data.subheader_layout}>
             </f:if>
             <f:format.html>{item.data.bodytext}</f:format.html>
         </div>
         <div class="carousel-image vcontainer">
             <f:if condition="{item.images.0}">
diff --git a/Resources/Private/Partials/ContentElements/Header/SubHeader.html b/Resources/Private/Partials/ContentElements/Header/SubHeader.html
index 6e9c97fe..4e0c3a28 100644
--- a/Resources/Private/Partials/ContentElements/Header/SubHeader.html
+++ b/Resources/Private/Partials/ContentElements/Header/SubHeader.html
@@ -1,31 +1,31 @@
 <html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
 <f:if condition="{subheader}">
     <f:switch expression="{layout}">
         <f:case value="1">
             <h2 class="{class} {positionClass}">
-                <span><f:format.htmlentitiesDecode>{subheader}</f:format.htmlentitiesDecode></span>
+                <span><f:format.htmlspecialchars doubleEncode="false">{subheader}</f:format.htmlspecialchars></span>
             </h2>
         </f:case>
         <f:case value="2">
             <h3 class="{class} {positionClass}">
-                <span><f:format.htmlentitiesDecode>{subheader}</f:format.htmlentitiesDecode></span>
+                <span><f:format.htmlspecialchars doubleEncode="false">{subheader}</f:format.htmlspecialchars></span>
             </h3>
         </f:case>
         <f:case value="3">
             <h4 class="{class} {positionClass}">
-                <span><f:format.htmlentitiesDecode>{subheader}</f:format.htmlentitiesDecode></span>
+                <span><f:format.htmlspecialchars doubleEncode="false">{subheader}</f:format.htmlspecialchars></span>
             </h4>
         </f:case>
         <f:case value="4">
             <h5 class="{class} {positionClass}">
-                <span><f:format.htmlentitiesDecode>{subheader}</f:format.htmlentitiesDecode></span>
+                <span><f:format.htmlspecialchars doubleEncode="false">{subheader}</f:format.htmlspecialchars></span>
             </h5>
         </f:case>
         <f:case value="5">
             <h6 class="{class} {positionClass}">
-                <span><f:format.htmlentitiesDecode>{subheader}</f:format.htmlentitiesDecode></span>
+                <span><f:format.htmlspecialchars doubleEncode="false">{subheader}</f:format.htmlspecialchars></span>
             </h6>
         </f:case>
         <f:defaultCase>
             <f:if condition="{default}">
                 <f:render partial="Header/SubHeader" arguments="{

Vulnerable code:             <h{item.data.header_layout} class="carousel-item-header{f:if(condition: item.data.header_class, then: ' {item.data.header_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlentitiesDecode>{item.data.header}</f:format.htmlentitiesDecode></h{item.data.header_layout}>
                <h{item.data.subheader_layout} class="carousel-item-subheader{f:if(condition: item.data.subheader_class, then: ' {item.data.subheader_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlentitiesDecode>{item.data.subheader}</f:format.htmlentitiesDecode></h{item.data.subheader_layout}>
                <h{item.data.header_layout} class="carousel-header awesome{f:if(condition: item.data.header_class, then: ' {item.data.header_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlentitiesDecode>{item.data.header}</f:format.htmlentitiesDecode></h{item.data.header_layout}>
                    <h{item.data.subheader_layout} class="carousel-subheader awesome{f:if(condition: item.data.subheader_class, then: ' {item.data.subheader_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlentitiesDecode>{item.data.subheader}</f:format.htmlentitiesDecode></h{item.data.subheader_layout}>
            <h{item.data.header_layout} class="carousel-item-header{f:if(condition: item.data.header_class, then: ' {item.data.header_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlentitiesDecode>{item.data.header}</f:format.htmlentitiesDecode></h{item.data.header_layout}>
                <h{item.data.subheader_layout} class="carousel-item-subheader{f:if(condition: item.data.subheader_class, then: ' {item.data.subheader_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlentitiesDecode>{item.data.subheader}</f:format.htmlentitiesDecode></h{item.data.subheader_layout}>
            <h{item.data.header_layout} class="carousel-header{f:if(condition: item.data.header_class, then: ' {item.data.header_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlentitiesDecode>{item.data.header}</f:format.htmlentitiesDecode></h{item.data.header_layout}>
                <h{item.data.subheader_layout} class="carousel-subheader{f:if(condition: item.data.subheader_class, then: ' {item.data.subheader_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlentitiesDecode>{item.data.subheader}</f:format.htmlentitiesDecode></h{item.data.subheader_layout}>
                <span><f:format.htmlentitiesDecode>{subheader}</f:format.htmlentitiesDecode></span>
                <span><f:format.htmlentitiesDecode>{subheader}</f:format.htmlentitiesDecode></span>
                <span><f:format.htmlentitiesDecode>{subheader}</f:format.htmlentitiesDecode></span>
                <span><f:format.htmlentitiesDecode>{subheader}</f:format.htmlentitiesDecode></span>
                <span><f:format.htmlentitiesDecode>{subheader}</f:format.htmlentitiesDecode></span>
Fixed code:             <h{item.data.header_layout} class="carousel-item-header{f:if(condition: item.data.header_class, then: ' {item.data.header_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlspecialchars doubleEncode="false">{item.data.header}</f:format.htmlspecialchars></h{item.data.header_layout}>
                <h{item.data.subheader_layout} class="carousel-item-subheader{f:if(condition: item.data.subheader_class, then: ' {item.data.subheader_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlspecialchars doubleEncode="false">{item.data.subheader}</f:format.htmlspecialchars></h{item.data.subheader_layout}>
                <h{item.data.header_layout} class="carousel-header awesome{f:if(condition: item.data.header_class, then: ' {item.data.header_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlspecialchars doubleEncode="false">{item.data.header}</f:format.htmlspecialchars></h{item.data.header_layout}>
                    <h{item.data.subheader_layout} class="carousel-subheader awesome{f:if(condition: item.data.subheader_class, then: ' {item.data.subheader_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlspecialchars doubleEncode="false">{item.data.subheader}</f:format.htmlspecialchars></h{item.data.subheader_layout}>
            <h{item.data.header_layout} class="carousel-item-header{f:if(condition: item.data.header_class, then: ' {item.data.header_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlspecialchars doubleEncode="false">{item.data.header}</f:format.htmlspecialchars></h{item.data.header_layout}>
                <h{item.data.subheader_layout} class="carousel-item-subheader{f:if(condition: item.data.subheader_class, then: ' {item.data.subheader_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlspecialchars doubleEncode="false">{item.data.subheader}</f:format.htmlspecialchars></h{item.data.subheader_layout}>
        <h{item.data.header_layout} class="carousel-header{f:if(condition: item.data.header_class, then: ' {item.data.header_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlspecialchars doubleEncode="false">{item.data.header}</f:format.htmlspecialchars></h{item.data.header_layout}>
                <h{item.data.subheader_layout} class="carousel-subheader{f:if(condition: item.data.subheader_class, then: ' {item.data.subheader_class}')}{f:if(condition: item.data.header_position, then: ' text-{item.data.header_position}')}"><f:format.htmlspecialchars doubleEncode="false">{item.data.subheader}</f:format.htmlspecialchars></h{item.data.subheader_layout}>
                <span><f:format.htmlspecialchars doubleEncode="false">{subheader}</f:format.htmlspecialchars></span>
                <span><f:format.htmlspecialchars doubleEncode="false">{subheader}</f:format.htmlspecialchars></span>
                <span><f:format.htmlspecialchars doubleEncode="false">{subheader}</f:format.htmlspecialchars></span>
                <span><f:format.htmlspecialchars doubleEncode="false">{subheader}</f:format.htmlspecialchars></span>
                <span><f:format.htmlspecialchars doubleEncode="false">{subheader}</f:format.htmlspecialchars></span>