CVE-2022-1728: Integer Overflow or Wraparound (CWE-190)
value: Allowing long password leads to denial of service in polonel/trudesk in GitHub repository polonel/trudesk prior to 1.2.2. This vulnerability can be abused by doing a DDoS attack for which genuine users will not able to access resources/applications.
CWE description: The product performs a calculation that can
         produce an integer overflow or wraparound when the logic
         assumes that the resulting value will always be larger than
         the original value. This occurs when an integer value is
         incremented to a value that is too large to store in the
         associated representation. When this occurs, the value may
         become a very small or negative number.
CVSS v3 base score: 6.5
Published: 2022-05-16T15:15Z
Repository: https://github.com/polonel/trudesk
Language: JavaScript
Files changed: src/models/user.js, src/public/js/angularjs/controllers/profile.js, src/views/subviews/profile.hbs
Commit date: 2022-05-15 11:51:25 -0400
Commit message: fix(account): security fix
Diff: diff --git a/src/models/user.js b/src/models/user.js
index 5132b8472..0c52c9fb1 100644
--- a/src/models/user.js
+++ b/src/models/user.js
@@ -98,10 +98,12 @@ userSchema.pre('save', function (next) {
 
   if (!user.isModified('password')) {
     return next()
   }
 
+  if (user.password.toString().length > 255) user.password = utils.applyMaxTextLength(user.password)
+
   bcrypt.genSalt(SALT_FACTOR, function (err, salt) {
     if (err) return next(err)
 
     bcrypt.hash(user.password, salt, function (err, hash) {
       if (err) return next(err)
diff --git a/src/public/js/angularjs/controllers/profile.js b/src/public/js/angularjs/controllers/profile.js
index f57b8b0ff..65eb52db2 100644
--- a/src/public/js/angularjs/controllers/profile.js
+++ b/src/public/js/angularjs/controllers/profile.js
@@ -43,17 +43,36 @@ define([
             }
           })
         }, 0)
       }
 
+      function validateEmail (email) {
+        return String(email)
+          .toLowerCase()
+          .match(
+            /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
+          )
+      }
+
       $scope.updateUser = function ($event) {
         $event.preventDefault()
 
         var id = $('div[data-user_id]').attr('data-user_id')
         if (_.isUndefined(id)) return
         var data = getFormData()
 
+        if (
+          data.fullname.toString().length > 25 ||
+          data.password.toString().length > 255 ||
+          data.cPassword.toString().length > 255 ||
+          data.email.toString().length > 255 ||
+          !validateEmail(data.email.toString())
+        ) {
+          helpers.UI.showSnackbar('Form data invalid.', true)
+          return false
+        }
+
         $http
           .put('/api/v1/users/' + data.username, {
             aId: id,
             aFullname: data.fullname,
             aPass: data.password,
diff --git a/src/views/subviews/profile.hbs b/src/views/subviews/profile.hbs
index a9972498d..e58e87eec 100644
--- a/src/views/subviews/profile.hbs
+++ b/src/views/subviews/profile.hbs
@@ -90,19 +90,19 @@
                                             <label for="aFullname">Name</label>
                                             <input id="aFullname" class="md-input md-input-width-medium" name="aFullname" type="text" value="{{data.account.fullname}}" />
                                         </div>
                                         <div class="uk-margin-medium-bottom">
                                             <label for="aPass">Password</label>
-                                            <input id="aPass" class="md-input" name="aPass" type="password" />
+                                            <input id="aPass" class="md-input" name="aPass" type="password" data-validation="length" data-validation-length="max255" data-validation-error-msg="Password too long. Maximum length is 25 characters." />
                                         </div>
                                         <div class="uk-margin-medium-bottom">
                                             <label for="aPassConfirm">Confirm Password</label>
-                                            <input id="aPassConfirm" class="md-input" name="aPassConfirm" type="password" />
+                                            <input id="aPassConfirm" class="md-input" name="aPassConfirm" type="password" data-validation="length" data-validation-length="max255" data-validation-error-msg="Password too long. Maximum length is 25 characters." />
                                         </div>
                                         <div class="uk-margin-medium-bottom">
                                             <label for="aEmail">Email</label>
-                                            <input id="aEmail" class="md-input" name="aEmail" type="email" value="{{data.account.email}}"/>
+                                            <input id="aEmail" class="md-input" name="aEmail" type="email" value="{{data.account.email}}" data-validation="email" data-validation-error-msg="Please enter a valid email address."/>
                                         </div>
                                         <div class="uk-clearfix">
                                             <button type="submit" class="uk-float-right md-btn md-btn-small md-btn-success md-btn-wave-light" ng-click="updateUser($event)">Save</button>
                                         </div>
                                     </div>

Vulnerable code:                                             <input id="aPass" class="md-input" name="aPass" type="password" />
                                            <input id="aPassConfirm" class="md-input" name="aPassConfirm" type="password" />
                                            <input id="aEmail" class="md-input" name="aEmail" type="email" value="{{data.account.email}}"/>
Fixed code:   if (user.password.toString().length > 255) user.password = utils.applyMaxTextLength(user.password)

      function validateEmail (email) {
        return String(email)
          .toLowerCase()
          .match(
            /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
          )
      }

        if (
          data.fullname.toString().length > 25 ||
          data.password.toString().length > 255 ||
          data.cPassword.toString().length > 255 ||
          data.email.toString().length > 255 ||
          !validateEmail(data.email.toString())
        ) {
          helpers.UI.showSnackbar('Form data invalid.', true)
          return false
        }

                                            <input id="aPass" class="md-input" name="aPass" type="password" data-validation="length" data-validation-length="max255" data-validation-error-msg="Password too long. Maximum length is 25 characters." />
                                            <input id="aPassConfirm" class="md-input" name="aPassConfirm" type="password" data-validation="length" data-validation-length="max255" data-validation-error-msg="Password too long. Maximum length is 25 characters." />
                                            <input id="aEmail" class="md-input" name="aEmail" type="email" value="{{data.account.email}}" data-validation="email" data-validation-error-msg="Please enter a valid email address."/>