CVE-2022-3975: Improper Neutralization (CWE-707)
value: A vulnerability, which was classified as problematic, has been found in NukeViet CMS. Affected by this issue is the function filterAttr of the file vendor/vinades/nukeviet/Core/Request.php of the component Data URL Handler. The manipulation of the argument attrSubSet leads to cross site scripting. The attack may be launched remotely. Upgrading to version 4.5 is able to address this issue. The name of the patch is 0b3197fad950bb3383e83039a8ee4c9509b3ce02. It is recommended to upgrade the affected component. VDB-213554 is the identifier assigned to this vulnerability.
CWE description: The product does not ensure or incorrectly ensures that structured messages or data are well-formed and that certain security properties are met before being read from an upstream component or sent to a downstream component.
CVSS v3 base score: 6.1
Published: 2022-11-13T10:15Z
Repository: https://github.com/nukeviet/nukeviet
Language: PHP
Files changed: vendor/vinades/nukeviet/Core/Request.php
Commit date: 2022-10-29 14:35:42 +0700
Commit message: Tiếp tục fix lỗi XSS

Diff: diff --git a/vendor/vinades/nukeviet/Core/Request.php b/vendor/vinades/nukeviet/Core/Request.php
index 0f7499813..77a6430a4 100644
--- a/vendor/vinades/nukeviet/Core/Request.php
+++ b/vendor/vinades/nukeviet/Core/Request.php
@@ -741,12 +741,14 @@ private function filterAttr($attrSet, $tagName, &$isvalid)
                 $attrSubSet[1] = preg_replace('/[ ]+/', ' ', $attrSubSet[1]);
                 $attrSubSet[1] = preg_replace('/^"(.*)"$/', '\\1', $attrSubSet[1]);
                 $attrSubSet[1] = preg_replace("/^\'(.*)\'$/", '\\1', $attrSubSet[1]);
                 $attrSubSet[1] = str_replace(['"', '&quot;'], "'", $attrSubSet[1]);
 
+                $value = $this->unhtmlentities($attrSubSet[1]);
+
                 // Security check Data URLs
-                if (preg_match('/^[\r\n\s\t]*d\s*a\s*t\s*a\s*\:([^\,]*?)\;*(base64)*?[\r\n\s\t]*\,[\r\n\s\t]*(.*?)[\r\n\s\t]*$/isu', $attrSubSet[1], $m)) {
+                if (preg_match('/^[\r\n\s\t]*d\s*a\s*t\s*a\s*\:([^\,]*?)\;*[\r\n\s\t]*(base64)*?[\r\n\s\t]*\,[\r\n\s\t]*(.*?)[\r\n\s\t]*$/isu', $value, $m)) {
                     if (empty($m[2])) {
                         $dataURLs = urldecode($m[3]);
                     } else {
                         $dataURLs = (string) base64_decode($m[3], true);
                     }
@@ -756,11 +758,14 @@ private function filterAttr($attrSet, $tagName, &$isvalid)
                     if (!$checkValid) {
                         continue;
                     }
                 }
 
-                $value = $this->unhtmlentities($attrSubSet[1]);
+                if (preg_replace('/\<\s*s\s*c\s*r\s*i\s*p\s*t([^\>]*)\>(.*)\<\s*\/\s*s\s*c\s*r\s*i\s*p\s*t\s*\>/isU', '', $value)) {
+                    continue;
+                }
+
                 $search = [
                     'javascript' => '/j\s*a\s*v\s*a\s*s\s*c\s*r\s*i\s*p\s*t/si',
                     'vbscript' => '/v\s*b\s*s\s*c\s*r\s*i\s*p\s*t/si',
                     'script' => '/s\s*c\s*r\s*i\s*p\s*t/si',
                     'applet' => '/a\s*p\s*p\s*l\s*e\s*t/si',
@@ -823,11 +828,11 @@ private function filterAttr($attrSet, $tagName, &$isvalid)
      * @return string
      */
     private function filterTags($source, &$isvalid = true)
     {
         $checkInvalid = 0;
-        $source = preg_replace('/\<script([^\>]*)\>(.*)\<\/script\>/isU', '', $source, -1, $checkInvalid);
+        $source = preg_replace('/\<\s*s\s*c\s*r\s*i\s*p\s*t([^\>]*)\>(.*)\<\s*\/\s*s\s*c\s*r\s*i\s*p\s*t\s*\>/isU', '', $source, -1, $checkInvalid);
         if ($checkInvalid > 0) {
             $isvalid = false;
         }
 
         $preTag = null;
@@ -934,11 +939,11 @@ private function filterTags($source, &$isvalid = true)
             $postTag = substr($postTag, ($tagLength + 2));
             $tagOpen_start = strpos($postTag, '<');
         }
 
         $preTag .= $postTag;
-        while (preg_match('/\<script([^\>]*)\>(.*)\<\/script\>/isU', $preTag)) {
+        while (preg_match('/\<\s*s\s*c\s*r\s*i\s*p\s*t([^\>]*)\>(.*)\<\s*\/\s*s\s*c\s*r\s*i\s*p\s*t\>/isU', $preTag)) {
             $preTag = preg_replace('/\<script([^\>]*)\>(.*)\<\/script\>/isU', '', $preTag);
         }
         $preTag = str_replace(["'", '"', '<', '>'], ['&#039;', '&quot;', '&lt;', '&gt;'], $preTag);
 
         return trim(str_replace(['[@{', '}@]', '{@[', ']@}'], ['"', '"', '<', '>'], $preTag));

Vulnerable code:                 if (preg_match('/^[\r\n\s\t]*d\s*a\s*t\s*a\s*\:([^\,]*?)\;*(base64)*?[\r\n\s\t]*\,[\r\n\s\t]*(.*?)[\r\n\s\t]*$/isu', $attrSubSet[1], $m)) {
                $value = $this->unhtmlentities($attrSubSet[1]);
        $source = preg_replace('/\<script([^\>]*)\>(.*)\<\/script\>/isU', '', $source, -1, $checkInvalid);
        while (preg_match('/\<script([^\>]*)\>(.*)\<\/script\>/isU', $preTag)) {
Fixed code:                 $value = $this->unhtmlentities($attrSubSet[1]);

                if (preg_match('/^[\r\n\s\t]*d\s*a\s*t\s*a\s*\:([^\,]*?)\;*[\r\n\s\t]*(base64)*?[\r\n\s\t]*\,[\r\n\s\t]*(.*?)[\r\n\s\t]*$/isu', $value, $m)) {
                if (preg_replace('/\<\s*s\s*c\s*r\s*i\s*p\s*t([^\>]*)\>(.*)\<\s*\/\s*s\s*c\s*r\s*i\s*p\s*t\s*\>/isU', '', $value)) {
                    continue;
                }

        $source = preg_replace('/\<\s*s\s*c\s*r\s*i\s*p\s*t([^\>]*)\>(.*)\<\s*\/\s*s\s*c\s*r\s*i\s*p\s*t\s*\>/isU', '', $source, -1, $checkInvalid);
        while (preg_match('/\<\s*s\s*c\s*r\s*i\s*p\s*t([^\>]*)\>(.*)\<\s*\/\s*s\s*c\s*r\s*i\s*p\s*t\>/isU', $preTag)) {