CVE-2023-3084: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Cross-site Scripting (XSS) - Stored in GitHub repository nilsteampassnet/teampass prior to 3.0.9.
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: 8.1
Published: 2023-06-03T11:15Z
Repository: https://github.com/nilsteampassnet/teampass
Language: PHP
Files changed: includes/core/load.js.php, pages/items.js.php, pages/users.js.php, sources/identify.php
Commit date: 2023-06-03 11:44:52 +0200
Commit message: 3.0.9

Fix for XSS on FolderName

Diff: diff --git a/includes/core/load.js.php b/includes/core/load.js.php
index ccf3178717..c6e049034f 100755
--- a/includes/core/load.js.php
+++ b/includes/core/load.js.php
@@ -782,11 +782,11 @@ if (
     setTimeout(
         function() {
             $(".fade").removeClass("out");
 
             // Is user not ready
-            if (typeof store.get('teampassUser').is_ready_for_usage !== 'undefined' && parseInt(store.get('teampassUser').is_ready_for_usage) === 0) {
+            if (typeof store.get('teampassUser') !== 'undefined' && typeof store.get('teampassUser').is_ready_for_usage !== 'undefined' && parseInt(store.get('teampassUser').is_ready_for_usage) === 0) {
                 $('#user_not_ready').removeClass('hidden');
             }
         },
         5000
     );
diff --git a/pages/items.js.php b/pages/items.js.php
index af3f2ff8d9..104e3efd21 100755
--- a/pages/items.js.php
+++ b/pages/items.js.php
@@ -1677,17 +1677,34 @@ $var['hidden_asterisk'] = '<i class="fas fa-asterisk mr-2"></i><i class="fas fa-
 
         // Force user did a change to false
         userDidAChange = false;
         userUploadedFile = false;
 
+        // Sanitize text fields
+        let formLabel = fieldSanitizeStep1('#form-folder-add-label', false, false, false),
+            formIcon = fieldSanitizeStep1('#form-folder-add-icon', false, false, false),
+            formIconSelected = fieldSanitizeStep1('#form-folder-add-icon-selected', false, false, false);
+        if (formLabel === false || formIcon === false || formIconSelected === false) {
+            // Label is empty
+            toastr.remove();
+            toastr.warning(
+                'XSS attempt detected. Field has been emptied.',
+                'Error', {
+                    timeOut: 5000,
+                    progressBar: true
+                }
+            );
+            return false;
+        }
+
         var data = {
-            'title': DOMPurify.sanitize($('#form-folder-add-label').val(), {USE_PROFILES: {html: false}}),
+            'title': formLabel,
             'parentId': $('#form-folder-add-parent option:selected').val(),
             'complexity': $('#form-folder-add-complexicity option:selected').val(),
             //'access_rights_strategy': $('#form-folder-add-rights option:selected').val(),
-            'icon': DOMPurify.sanitize($('#form-folder-add-icon').val(), {USE_PROFILES: {html: false}}),
-            'iconSelected': DOMPurify.sanitize($('#form-folder-add-icon-selected').val(), {USE_PROFILES: {html: false}}),
+            'icon': formIcon,
+            'iconSelected': formIconSelected,
             'id': selectedFolderId,
         }
         if (debugJavascript === true) console.log(data);
 
         // Launch action
diff --git a/pages/users.js.php b/pages/users.js.php
index 499435ea4d..7b08685a66 100755
--- a/pages/users.js.php
+++ b/pages/users.js.php
@@ -882,11 +882,11 @@ if (checkUser($_SESSION['user_id'], $_SESSION['key'], 'folders', $SETTINGS) ===
 
             // Sanitize text fields
             let formLogin = fieldSanitizeStep1('#form-login', false, false, false),
                 formName = fieldSanitizeStep1('#form-name', false, false, false),
                 formLastname = fieldSanitizeStep1('#form-lastname', false, false, false),
-                formEmail = fieldSanitizeStep1('#form-email', false, false, false),
+                formEmail = fieldSanitizeStep1('#form-email', false, false, false);
             if (formLogin === false || formName === false || formLastname === false || formEmail === false) {
                 // Label is empty
                 toastr.remove();
                 toastr.warning(
                     'XSS attempt detected. Field has been emptied.',
diff --git a/sources/identify.php b/sources/identify.php
index 110faf014e..78686a196c 100755
--- a/sources/identify.php
+++ b/sources/identify.php
@@ -384,11 +384,15 @@ function identifyUser(string $sentData, array $SETTINGS): bool
             (string) $username
         );
         if ($userMfa['error'] === true) {
             echo prepareExchangedData(
                 $SETTINGS['cpassman_dir'],
-                $userMfa['mfaData'],
+                [
+                    'error' => true,
+                    'message' => $userMfa['mfaData']['message'],
+                    'mfaStatus' => $userMfa['mfaData']['mfaStatus'],
+                ],
                 'encode'
             );
             return false;
         } elseif ($userMfa['mfaQRCodeInfos'] === true) {
             // Case where user has initiated Google Auth

Vulnerable code:             if (typeof store.get('teampassUser').is_ready_for_usage !== 'undefined' && parseInt(store.get('teampassUser').is_ready_for_usage) === 0) {
            'title': DOMPurify.sanitize($('#form-folder-add-label').val(), {USE_PROFILES: {html: false}}),
            'icon': DOMPurify.sanitize($('#form-folder-add-icon').val(), {USE_PROFILES: {html: false}}),
            'iconSelected': DOMPurify.sanitize($('#form-folder-add-icon-selected').val(), {USE_PROFILES: {html: false}}),
                formEmail = fieldSanitizeStep1('#form-email', false, false, false),
                $userMfa['mfaData'],
Fixed code:             if (typeof store.get('teampassUser') !== 'undefined' && typeof store.get('teampassUser').is_ready_for_usage !== 'undefined' && parseInt(store.get('teampassUser').is_ready_for_usage) === 0) {
        // Sanitize text fields
        let formLabel = fieldSanitizeStep1('#form-folder-add-label', false, false, false),
            formIcon = fieldSanitizeStep1('#form-folder-add-icon', false, false, false),
            formIconSelected = fieldSanitizeStep1('#form-folder-add-icon-selected', false, false, false);
        if (formLabel === false || formIcon === false || formIconSelected === false) {
            // Label is empty
            toastr.remove();
            toastr.warning(
                'XSS attempt detected. Field has been emptied.',
                'Error', {
                    timeOut: 5000,
                    progressBar: true
                }
            );
            return false;
        }

            'title': formLabel,
            'icon': formIcon,
            'iconSelected': formIconSelected,
                formEmail = fieldSanitizeStep1('#form-email', false, false, false);
                [
                    'error' => true,
                    'message' => $userMfa['mfaData']['message'],
                    'mfaStatus' => $userMfa['mfaData']['mfaStatus'],
                ],