CVE-2023-4189: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Cross-site Scripting (XSS) - Reflected in GitHub repository instantsoft/icms2 prior to 2.16.1-git.
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: 4.8
Published: 2023-08-05T20:15Z
Repository: https://github.com/instantsoft/icms2
Language: PHP
Files changed: system/controllers/admin/actions/menu_tree_ajax.php, system/controllers/tags/actions/autocomplete.php, system/core/user.php, system/fields/string.php, system/libs/template.helper.php, templates/admincoreui/assets/ui/form.tpl.php, templates/admincoreui/assets/ui/grid-perms.tpl.php, templates/admincoreui/controllers/admin/menu.tpl.php, templates/default/assets/ui/confirm.tpl.php, templates/default/assets/ui/filter-panel.tpl.php, templates/default/assets/ui/form.tpl.php, templates/default/assets/ui/grid-perms.tpl.php, templates/modern/assets/ui/filter-panel.tpl.php, templates/modern/assets/ui/form.tpl.php
Commit date: 2023-08-05 15:30:12 +0300
Commit message: Vulnerabilities fixed, thanks to huntr.dev
Diff: diff --git a/system/controllers/admin/actions/menu_tree_ajax.php b/system/controllers/admin/actions/menu_tree_ajax.php
index 2654c536..122007fa 100755
--- a/system/controllers/admin/actions/menu_tree_ajax.php
+++ b/system/controllers/admin/actions/menu_tree_ajax.php
@@ -23,11 +23,11 @@ class actionAdminMenuTreeAjax extends cmsAction {
         $tree_nodes = [];
 
         if ($items) {
             foreach ($items as $item) {
                 $tree_nodes[] = [
-                    'title'  => $item['title'],
+                    'title'  => html($item['title'], false),
                     'key'    => "{$menu_id}.{$item['id']}",
                     'isLazy' => ($item['childs_count'] > 0)
                 ];
             }
         }
diff --git a/system/controllers/tags/actions/autocomplete.php b/system/controllers/tags/actions/autocomplete.php
index 05a394a9..500c0923 100755
--- a/system/controllers/tags/actions/autocomplete.php
+++ b/system/controllers/tags/actions/autocomplete.php
@@ -10,17 +10,17 @@ class actionTagsAutocomplete extends cmsAction {
             return cmsCore::error404();
         }
 
         $result = [];
 
-        $term = $this->request->get('term', '');
+        $term = strip_tags($this->request->get('term', ''));
         if (!$term) {
             return $this->cms_template->renderJSON($result);
         }
 
         $tags = $this->model->filterLike('tag', "%{$term}%")->
-                select("(LEFT(`tag`, " . mb_strlen($term) . ") = '{$term}')", 'tag_order')->
+                select("(LEFT(`tag`, " . mb_strlen($term) . ") = '".$this->model->db->escape($term)."')", 'tag_order')->
                 orderByList([
                     ['by' => 'tag_order', 'to' => 'desc', 'strict' => true],
                     ['by' => 'tag', 'to' => 'asc']
                 ])->
                 getTags();
diff --git a/system/core/user.php b/system/core/user.php
index 7ea671a0..408665f4 100755
--- a/system/core/user.php
+++ b/system/core/user.php
@@ -275,17 +275,19 @@ class cmsUser {
      * @param string $password
      * @param boolean $remember
      * @param boolean $complete_login
      * @return integer|array
      */
-    public static function login($email, $password, $remember = false, $complete_login = true) {
+    public static function login($email, $password, $remember = false, $complete_login = true, $model = null) {
 
         if (!$email || !$password) {
             return 0;
         }
 
-        $model = cmsCore::getModel('users');
+        if($model === null) {
+            $model = cmsCore::getModel('users');
+        }
 
         $user = $model->getUserByAuth($email, $password);
 
         if (!$user) {
             $user = cmsEventsManager::hook('user_auth_error', ['email' => $email, 'password' => $password]);
diff --git a/system/fields/string.php b/system/fields/string.php
index ae897dd3..4a1d2f21 100755
--- a/system/fields/string.php
+++ b/system/fields/string.php
@@ -138,10 +138,19 @@ class fieldString extends cmsFormField {
         if (is_empty_value($value)) {
             return '';
         }
 
         if ($this->getProperty('is_clean_disable') === true) {
+
+            // Разрешены HTML теги, - прогоняем через типограф
+            $value = cmsEventsManager::hook('html_filter', [
+                'text'                => $value,
+                'is_auto_br'          => false,
+                'build_smiles'        => false,
+                'build_redirect_link' => false
+            ]);
+
             return trim($value, " \0");
         }
 
         return trim(strip_tags($value), " \0");
     }
diff --git a/system/libs/template.helper.php b/system/libs/template.helper.php
index 2ee85c09..61851ebe 100755
--- a/system/libs/template.helper.php
+++ b/system/libs/template.helper.php
@@ -61,11 +61,11 @@ function html_pagebar($page, $perpage, $total, $base_uri = false, $query = [], $
  * @param array $attributes Атрибуты тега название=>значение
  * @return string
  */
 function html_input($type = 'text', $name = '', $value = '', $attributes = []) {
 
-    if ($type === 'password') {
+    if ($type === 'password' && empty($attributes['autocomplete'])) {
         $attributes['autocomplete'] = 'off';
     }
     $attributes['type']  = $type;
     $attributes['name']  = $name;
     $attributes['value'] = $value;
diff --git a/templates/admincoreui/assets/ui/form.tpl.php b/templates/admincoreui/assets/ui/form.tpl.php
index 2819175d..870f8d06 100755
--- a/templates/admincoreui/assets/ui/form.tpl.php
+++ b/templates/admincoreui/assets/ui/form.tpl.php
@@ -2,11 +2,11 @@
 <?php $this->addTplJSNameFromContext('form-translate'); ?>
 <?php if ((!isset($attributes['toolbar']) || $attributes['toolbar']) && $this->isToolbar() && empty($attributes['hide_toolbar'])){ ?>
     <?php $this->toolbar('menu-toolbar'); ?>
 <?php } ?>
 
-<form id="<?php html($attributes['form_id']); ?>" action="<?php echo $attributes['action']; ?>"
+<form id="<?php html($attributes['form_id']); ?>" action="<?php html($attributes['action']); ?>"
       method="<?php echo $attributes['method']; ?>"
       class="<?php html($attributes['form_class']); ?><?php if ($this->controller->request->isAjax()){ ?> ajax-form<?php } ?>"
       enctype="multipart/form-data"
       accept-charset="utf-8">
 
diff --git a/templates/admincoreui/assets/ui/grid-perms.tpl.php b/templates/admincoreui/assets/ui/grid-perms.tpl.php
index 9562d1f6..e9632e6a 100755
--- a/templates/admincoreui/assets/ui/grid-perms.tpl.php
+++ b/templates/admincoreui/assets/ui/grid-perms.tpl.php
@@ -1,10 +1,10 @@
 <?php if ($this->isToolbar()){ ?>
     <?php $this->toolbar('menu-toolbar'); ?>
 <?php } ?>
 
-<form action="<?php echo $submit_url; ?>" method="post">
+<form action="<?php html($submit_url); ?>" method="post">
 
     <div class="datagrid_wrapper perms_grid table-responsive dataTables_wrapper dt-bootstrap4">
         <table id="datagrid" class="datagrid table table-striped table-bordered dataTable bg-white">
             <thead>
                 <tr>
diff --git a/templates/admincoreui/controllers/admin/menu.tpl.php b/templates/admincoreui/controllers/admin/menu.tpl.php
index 21093047..4f9c62f7 100755
--- a/templates/admincoreui/controllers/admin/menu.tpl.php
+++ b/templates/admincoreui/controllers/admin/menu.tpl.php
@@ -26,11 +26,11 @@
         <a class="quickview-toggle close" data-toggle="quickview" data-toggle-element="#left-quickview" href="#"><span>×</span></a>
         <div id="datatree" class="card-body bg-white h-100 pt-3">
             <ul id="treeData" class="skeleton-tree">
                 <?php foreach ($menus as $id => $menu) { ?>
                     <li id="<?php echo $menu['id'];?>.0" class="lazy folder">
-                        <?php echo $menu['title']; ?>
+                        <?php html($menu['title']); ?>
                     </li>
                 <?php } ?>
             </ul>
         </div>
     </div>
diff --git a/templates/default/assets/ui/confirm.tpl.php b/templates/default/assets/ui/confirm.tpl.php
index d30885a1..1880ef7f 100755
--- a/templates/default/assets/ui/confirm.tpl.php
+++ b/templates/default/assets/ui/confirm.tpl.php
@@ -1,8 +1,8 @@
 <div class="modal_padding">
     <h3><?php echo $confirm_title; ?></h3>
-    <form action="<?php echo $confirm_action; ?>" method="post" onsubmit="$(this).find('.button-submit').addClass('disabled is-busy');">
+    <form action="<?php html($confirm_action); ?>" method="post" onsubmit="$(this).find('.button-submit').addClass('disabled is-busy');">
         <?php echo html_csrf_token(); ?>
         <?php echo html_input('hidden', 'back', $this->controller->request->get('back', '')); ?>
         <?php echo html_submit(LANG_CONFIRM); ?>
         <?php echo html_button(LANG_CANCEL, 'cancel', 'icms.modal.close()'); ?>
     </form>
diff --git a/templates/default/assets/ui/filter-panel.tpl.php b/templates/default/assets/ui/filter-panel.tpl.php
index 026007cf..9023dd3c 100755
--- a/templates/default/assets/ui/filter-panel.tpl.php
+++ b/templates/default/assets/ui/filter-panel.tpl.php
@@ -8,11 +8,11 @@
     </div>
     <div class="filter-container" <?php if(!$filters && !$is_expanded){ ?>style="display:none"<?php } ?>>
 		<div class="filter-close">
             <a href="javascript:toggleFilter();"><span><?php echo LANG_CLOSE; ?></span></a>
         </div>
-        <form action="<?php echo $form_url; ?>" method="get" id="<?php echo $form_id; ?>" accept-charset="utf-8">
+        <form action="<?php html($form_url); ?>" method="get" id="<?php echo $form_id; ?>" accept-charset="utf-8">
             <?php echo html_input('hidden', 'page', 1); ?>
             <?php if(!empty($ext_hidden_params)){ ?>
                 <?php foreach($ext_hidden_params as $fname => $fvalue){ ?>
                     <?php echo html_input('hidden', $fname, $fvalue); ?>
                     <?php if($filters){ $filters[$fname] = $fvalue; } ?>
diff --git a/templates/default/assets/ui/form.tpl.php b/templates/default/assets/ui/form.tpl.php
index 862fe462..a56348c6 100755
--- a/templates/default/assets/ui/form.tpl.php
+++ b/templates/default/assets/ui/form.tpl.php
@@ -3,11 +3,11 @@
     <div class="cp_toolbar">
         <?php $this->toolbar(); ?>
     </div>
 <?php } ?>
 
-<form id="<?php html($attributes['form_id']); ?>" action="<?php echo $attributes['action']; ?>"
+<form id="<?php html($attributes['form_id']); ?>" action="<?php html($attributes['action']); ?>"
       method="<?php echo $attributes['method']; ?>"
       <?php if ($this->controller->request->isAjax()){ ?>
         class="modal"
       <?php } ?>
       enctype="multipart/form-data"
diff --git a/templates/default/assets/ui/grid-perms.tpl.php b/templates/default/assets/ui/grid-perms.tpl.php
index 06a27e09..2da30853 100755
--- a/templates/default/assets/ui/grid-perms.tpl.php
+++ b/templates/default/assets/ui/grid-perms.tpl.php
@@ -3,11 +3,11 @@
     <?php $this->toolbar(); ?>
 </div>
 <?php } ?>
 
 
-<form action="<?php echo $submit_url; ?>" method="post">
+<form action="<?php html($submit_url); ?>" method="post">
 
     <div class="datagrid_wrapper perms_grid">
         <table id="datagrid" class="datagrid" cellpadding="0" cellspacing="0" border="0">
             <thead>
                 <tr>
diff --git a/templates/modern/assets/ui/filter-panel.tpl.php b/templates/modern/assets/ui/filter-panel.tpl.php
index 326a852d..ec294827 100755
--- a/templates/modern/assets/ui/filter-panel.tpl.php
+++ b/templates/modern/assets/ui/filter-panel.tpl.php
@@ -14,11 +14,11 @@ $form_url_sep = strpos($form_url, '?') === false ? '?' : '&';
 
     <div class="icms-filter-container p-3 bg-light position-relative <?php if(!$filters && !$is_expanded){ ?>d-none<?php } ?>">
         <button type="button" class="close position-absolute icms-filter-link__close" title="<?php echo LANG_CLOSE; ?>">
             <span>&times;</span>
         </button>
-        <form action="<?php echo $form_url; ?>" method="get" id="<?php echo $form_id; ?>" accept-charset="utf-8">
+        <form action="<?php html($form_url); ?>" method="get" id="<?php html($form_id); ?>" accept-charset="utf-8">
             <?php echo html_input('hidden', 'page', 1); ?>
             <?php if(!empty($ext_hidden_params)){ ?>
                 <?php foreach($ext_hidden_params as $fname => $fvalue){ ?>
                     <?php echo html_input('hidden', $fname, $fvalue); ?>
                     <?php if($filters){ $filters[$fname] = $fvalue; } ?>
diff --git a/templates/modern/assets/ui/form.tpl.php b/templates/modern/assets/ui/form.tpl.php
index 04f40524..b2868822 100755
--- a/templates/modern/assets/ui/form.tpl.php
+++ b/templates/modern/assets/ui/form.tpl.php
@@ -1,11 +1,11 @@
 <?php $this->addTplJSNameFromContext('jquery-cookie'); ?>
 <?php if ((!isset($attributes['toolbar']) || $attributes['toolbar']) && $this->isToolbar() && empty($attributes['hide_toolbar'])){ ?>
     <?php $this->toolbar('menu-toolbar'); ?>
 <?php } ?>
 
-<form id="<?php html($attributes['form_id']); ?>" action="<?php echo $attributes['action']; ?>"
+<form id="<?php html($attributes['form_id']); ?>" action="<?php html($attributes['action']); ?>"
       method="<?php echo $attributes['method']; ?>"
       class="<?php html($attributes['form_class']); ?><?php if ($this->controller->request->isAjax()){ ?> ajax-form<?php } ?>"
       enctype="multipart/form-data"
       accept-charset="utf-8">
 

Vulnerable code:                     'title'  => $item['title'],
        $term = $this->request->get('term', '');
                select("(LEFT(`tag`, " . mb_strlen($term) . ") = '{$term}')", 'tag_order')->
    public static function login($email, $password, $remember = false, $complete_login = true) {
        $model = cmsCore::getModel('users');
    if ($type === 'password') {
<form id="<?php html($attributes['form_id']); ?>" action="<?php echo $attributes['action']; ?>"
<form action="<?php echo $submit_url; ?>" method="post">
                        <?php echo $menu['title']; ?>
    <form action="<?php echo $confirm_action; ?>" method="post" onsubmit="$(this).find('.button-submit').addClass('disabled is-busy');">
        <form action="<?php echo $form_url; ?>" method="get" id="<?php echo $form_id; ?>" accept-charset="utf-8">
<form id="<?php html($attributes['form_id']); ?>" action="<?php echo $attributes['action']; ?>"
<form action="<?php echo $submit_url; ?>" method="post">
        <form action="<?php echo $form_url; ?>" method="get" id="<?php echo $form_id; ?>" accept-charset="utf-8">
<form id="<?php html($attributes['form_id']); ?>" action="<?php echo $attributes['action']; ?>"
Fixed code:                     'title'  => html($item['title'], false),
        $term = strip_tags($this->request->get('term', ''));
                select("(LEFT(`tag`, " . mb_strlen($term) . ") = '".$this->model->db->escape($term)."')", 'tag_order')->
    public static function login($email, $password, $remember = false, $complete_login = true, $model = null) {
        if($model === null) {
            $model = cmsCore::getModel('users');
        }

            // Разрешены HTML теги, - прогоняем через типограф
            $value = cmsEventsManager::hook('html_filter', [
                'text'                => $value,
                'is_auto_br'          => false,
                'build_smiles'        => false,
                'build_redirect_link' => false
            ]);

    if ($type === 'password' && empty($attributes['autocomplete'])) {
<form id="<?php html($attributes['form_id']); ?>" action="<?php html($attributes['action']); ?>"
<form action="<?php html($submit_url); ?>" method="post">
                        <?php html($menu['title']); ?>
    <form action="<?php html($confirm_action); ?>" method="post" onsubmit="$(this).find('.button-submit').addClass('disabled is-busy');">
        <form action="<?php html($form_url); ?>" method="get" id="<?php echo $form_id; ?>" accept-charset="utf-8">
<form id="<?php html($attributes['form_id']); ?>" action="<?php html($attributes['action']); ?>"
<form action="<?php html($submit_url); ?>" method="post">
        <form action="<?php html($form_url); ?>" method="get" id="<?php html($form_id); ?>" accept-charset="utf-8">
<form id="<?php html($attributes['form_id']); ?>" action="<?php html($attributes['action']); ?>"