CVE-2021-25968: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: In “OpenCMS”, versions 10.5.0 to 11.0.2 are affected by a stored XSS vulnerability that allows low privileged application users to store malicious scripts in the Sitemap functionality. These scripts are executed in a victim’s browser when they open the page containing the vulnerable field.
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-10-19T09:15Z
Repository: https://github.com/alkacon/mercury-template
Language: Other
Files changed: alkacon.mercury.template/resources/system/modules/alkacon.mercury.template/formatters/navigation/breadcrumbs.jsp, alkacon.mercury.template/resources/system/modules/alkacon.mercury.template/formatters/navigation/main.jsp, alkacon.mercury.template/resources/system/modules/alkacon.mercury.template/formatters/navigation/side.jsp
Commit date: 2021-07-22 09:36:42 +0200
Commit message: Escaping of naviation text to prevent usage of script in nav elements.
Diff: diff --git a/alkacon.mercury.template/resources/system/modules/alkacon.mercury.template/formatters/navigation/breadcrumbs.jsp b/alkacon.mercury.template/resources/system/modules/alkacon.mercury.template/formatters/navigation/breadcrumbs.jsp
index efae8c64..b4af4319 100644
--- a/alkacon.mercury.template/resources/system/modules/alkacon.mercury.template/formatters/navigation/breadcrumbs.jsp
+++ b/alkacon.mercury.template/resources/system/modules/alkacon.mercury.template/formatters/navigation/breadcrumbs.jsp
@@ -40,12 +40,12 @@
 
                     <c:forEach var="navElem" items="${navItems}" varStatus="status">
                         <c:if test="${
                             ((breadcrumbsIncludeHidden or (status.last and not cms.detailRequest)) and (navElem.navPosition > 0))
                             or (navElem.info ne 'ignoreInDefaultNav')}">
-                            <c:set var="navText" value="${(empty navElem.navText or fn:startsWith(navElem.navText, '???'))
-                                ? navElem.title : navElem.navText}" />
+                            <c:set var="navText"><c:out value="${(empty navElem.navText or fn:startsWith(navElem.navText, '???'))
+                                ? navElem.title : navElem.navText}" /></c:set>
                             <c:if test="${!empty navText}">
                                 <c:set var="navLink"><cms:link>${navElem.resourceName}</cms:link></c:set>
                                 <c:if test="${breadcrumbsFullPath or (navLink ne lastNavLink)}">
                                     <c:set var="lastNavLink" value="${navLink}" />
                                     <c:out value='<li><a href="${navLink}">' escapeXml="false" />
diff --git a/alkacon.mercury.template/resources/system/modules/alkacon.mercury.template/formatters/navigation/main.jsp b/alkacon.mercury.template/resources/system/modules/alkacon.mercury.template/formatters/navigation/main.jsp
index de472b7e..abd77d80 100644
--- a/alkacon.mercury.template/resources/system/modules/alkacon.mercury.template/formatters/navigation/main.jsp
+++ b/alkacon.mercury.template/resources/system/modules/alkacon.mercury.template/formatters/navigation/main.jsp
@@ -186,12 +186,13 @@
             <c:set var="menuType" value="${empty menuType ? '' : ' class=\"'.concat(menuType).concat('\"')}" />
             <c:set var="menuType" value="${startSubMenu or hasMegaMenu ? menuType.concat(' aria-expanded=\"false\"') : menuType}" />
 
             <c:out value='<li${menuType}${megaMenu}>${empty menuType ? "" : nl}' escapeXml="false" />
 
-            <c:set var="navText" value="${(empty navElem.navText or fn:startsWith(navElem.navText, '???'))
-                ? navElem.title : navElem.navText}" />
+            <c:set var="navText"><c:out value="${(empty navElem.navText or fn:startsWith(navElem.navText, '???'))
+                ? navElem.title : navElem.navText}" /></c:set>
+
 
             <c:choose>
 
                 <c:when test="${startSubMenu and not navElem.navigationLevel}">
                     <%-- Navigation item with sub-menu and direct child pages --%>
diff --git a/alkacon.mercury.template/resources/system/modules/alkacon.mercury.template/formatters/navigation/side.jsp b/alkacon.mercury.template/resources/system/modules/alkacon.mercury.template/formatters/navigation/side.jsp
index de1c31cd..a460e57d 100644
--- a/alkacon.mercury.template/resources/system/modules/alkacon.mercury.template/formatters/navigation/side.jsp
+++ b/alkacon.mercury.template/resources/system/modules/alkacon.mercury.template/formatters/navigation/side.jsp
@@ -65,11 +65,11 @@
                     <c:otherwise>
                         <c:set var="navLink"><cms:link>${navElem.resourceName}</cms:link></c:set>
                     </c:otherwise>
                 </c:choose>
 
-                <c:set var="navText" value="${(empty navElem.navText or fn:startsWith(navElem.navText, '???')) ? navElem.title : navElem.navText}" />
+                <c:set var="navText"><c:out value="${(empty navElem.navText or fn:startsWith(navElem.navText, '???')) ? navElem.title : navElem.navText}" /></c:set>
 
                 <c:set var="menuType" value="${startSubMenu ? menuType.concat(' aria-expanded=\"false\"') : menuType}" />
 
                 <c:out value="<li${isCurrentPage ? ' class=\"currentpage'.concat(isFinalCurrentPage ? ' final\"' : '\"') : ''}>" escapeXml="false" />
 

Vulnerable code:                             <c:set var="navText" value="${(empty navElem.navText or fn:startsWith(navElem.navText, '???'))
                                ? navElem.title : navElem.navText}" />
            <c:set var="navText" value="${(empty navElem.navText or fn:startsWith(navElem.navText, '???'))
                ? navElem.title : navElem.navText}" />
                <c:set var="navText" value="${(empty navElem.navText or fn:startsWith(navElem.navText, '???')) ? navElem.title : navElem.navText}" />
Fixed code:                             <c:set var="navText"><c:out value="${(empty navElem.navText or fn:startsWith(navElem.navText, '???'))
                                ? navElem.title : navElem.navText}" /></c:set>
            <c:set var="navText"><c:out value="${(empty navElem.navText or fn:startsWith(navElem.navText, '???'))
                ? navElem.title : navElem.navText}" /></c:set>

                <c:set var="navText"><c:out value="${(empty navElem.navText or fn:startsWith(navElem.navText, '???')) ? navElem.title : navElem.navText}" /></c:set>