VYPR
Moderate severityNVD Advisory· Published Dec 17, 2021· Updated Aug 3, 2024

Cross-site Scripting (XSS) - Stored in livehelperchat/livehelperchat

CVE-2021-4132

Description

livehelperchat is vulnerable to Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Live Helper Chat before a specific commit is vulnerable to stored XSS via user account fields that are not properly neutralized.

Vulnerability

Live Helper Chat (LHC), an open-source live support chat application, is vulnerable to stored Cross-Site Scripting (XSS) in user account fields due to improper neutralization of user-supplied input. The vulnerability exists in versions prior to the commit 55b1e3b. The affected fields include Email and possibly others, as the fix adds the ng-non-bindable attribute and htmlspecialchars() to prevent AngularJS template injection and HTML script execution [1], [2], [3].

Exploitation

An attacker who can modify user account fields, such as the Email address, can inject malicious JavaScript code. The injection occurs when the crafted input is rendered in a context where AngularJS evaluates the content. The attacker must have access to edit user account details, which can be achieved by compromising an operator account or, in some configurations, by a user with sufficient privileges [2], [4]. The injected script then executes when the page is rendered in an AngularJS environment, requiring no specific user interaction besides viewing the compromised profile or administration panel.

Impact

Successful exploitation allows the attacker to execute arbitrary JavaScript in the context of the victim's browser session. This can lead to session hijacking, credential theft, defacement of the Live Helper Chat interface, or redirecting users to malicious sites. The attack can potentially compromise all operators and administrators who view the affected user account fields, leading to a full takeover of the chat system [4].

Mitigation

The fix was implemented in commit 55b1e3b on an unspecified date before 2021-12-17 [2]. The mitigation adds the ng-non-bindable attribute to prevent AngularJS from evaluating the field content and applies htmlspecialchars() to escape HTML entities. Users should update their Live Helper Chat installation to the latest version that includes this commit or later. There is no known workaround for unpatched versions besides restricting write access to user account fields to trusted operators only [4].

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
remdex/livehelperchatPackagist
< 3.913.91

Affected products

3

Patches

1
55b1e3bf62c5

ng-non-bindable for user account fields

https://github.com/livehelperchat/livehelperchatRemigijus KiminasDec 17, 2021via ghsa
4 files changed · +37 37
  • lhc_web/design/defaulttheme/tpl/lhuser/edit.tpl.php+25 25 modified
    @@ -47,14 +47,14 @@
     	   <br />
     
     	   <form action="<?php echo erLhcoreClassDesign::baseurl('user/edit')?>/<?php echo $user->id?>#account" method="post" autocomplete="off" enctype="multipart/form-data">
    -	        
    +
     	        <?php include(erLhcoreClassDesign::designtpl('lhuser/account/above_new_account_form_multiinclude.tpl.php'));?>
    -	        
    +
     	        <div class="form-group">
         		  <label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('user/edit','Username');?>*</label>
         		  <input <?php if ($can_edit_groups === false) : ?>disabled="disabled"<?php endif;?> class="form-control" type="text" ng-non-bindable name="Username" value="<?php echo htmlspecialchars($user->username);?>" />
         		</div>
    -    		
    +
         		<div class="form-group">
             		<label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('user/edit','Password');?></label>
             		<input ng-non-bindable autocomplete="new-password" type="password" <?php if ($can_edit_groups === false) : ?>disabled="disabled"<?php endif;?> class="form-control" name="Password" value="<?php echo htmlspecialchars(isset($user->password_temp_1) ? $user->password_temp_1 : '');?>" />
    @@ -82,33 +82,33 @@
             		<label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('user/edit','E-mail');?></label>
             		<input type="text" ng-non-bindable <?php if ($can_edit_groups === false) : ?>disabled="disabled"<?php endif;?> class="form-control" name="Email" value="<?php echo $user->email;?>"/>
         		</div>
    -    		
    +
         		<div class="form-group">
     				<label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('user/edit','Chat nickname');?></label>
     				<input type="text" ng-non-bindable <?php if ($can_edit_groups === false) : ?>disabled="disabled"<?php endif;?> class="form-control" name="ChatNickname" value="<?php echo htmlspecialchars($user->chat_nickname);?>" />
     			</div>
    -			
    +
         		<div class="form-group">
         		  <label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('user/edit','Name');?></label>
         		  <input type="text" ng-non-bindable <?php if ($can_edit_groups === false) : ?>disabled="disabled"<?php endif;?> class="form-control" name="Name" value="<?php echo htmlspecialchars($user->name);?>"/>
         		</div>
    -    		
    +
         		<div class="form-group">
         		  <label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('user/edit','Surname');?></label>
         		  <input type="text" ng-non-bindable <?php if ($can_edit_groups === false) : ?>disabled="disabled"<?php endif;?> class="form-control" name="Surname" value="<?php echo htmlspecialchars($user->surname);?>"/>
         		</div>
    -    		
    +
         		<div class="form-group">
         		  <label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('user/account','Job title');?></label>
         		  <input type="text" ng-non-bindable <?php if ($can_edit_groups === false) : ?>disabled="disabled"<?php endif;?> class="form-control" name="JobTitle" value="<?php echo htmlspecialchars($user->job_title);?>"/>
         		</div>
    -    			    
    +
         		<?php include(erLhcoreClassDesign::designtpl('lhuser/parts/time_zone.tpl.php'));?>
    -    		
    +
         		<div class="row">
    -    		
    +
         		  <?php include(erLhcoreClassDesign::designtpl('lhuser/account/part/visibility_content.tpl.php'));?>
    -    		  
    +
         		  <?php include(erLhcoreClassDesign::designtpl('lhuser/account/part/after_visibility_content.tpl.php'));?>
     
                   <?php include(erLhcoreClassDesign::designtpl('lhuser/account/part/hidability.tpl.php'));?>
    @@ -119,9 +119,9 @@
             		  </div>
         		  </div>
         		</div>
    -    		
    +
         		<?php include(erLhcoreClassDesign::designtpl('lhuser/account/part/after_permission.tpl.php'));?>
    -    		
    +
         		<div class="row form-group">
         			<div class="col-md-6">
         				<label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('user/account','Skype');?></label>
    @@ -195,9 +195,9 @@
                 <hr>
         		<label><input type="checkbox" value="on" name="UserDisabled" <?php echo $user->disabled == 1 ? 'checked="checked"' : '' ?> />&nbsp;<?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('user/new','Disabled')?></label><br>
         		<?php endif; ?>
    -    		    		    		
    +
         		<?php include(erLhcoreClassDesign::designtpl('lhkernel/csfr_token.tpl.php'));?>
    -    		
    +
         		<?php include(erLhcoreClassDesign::designtpl('lhuser/account/below_account_edit_multiinclude.tpl.php'));?>
     
         		<div class="btn-group" role="group" aria-label="..." <?php if (empty($groupsRequired)) :?>ng-init="accval.validForm=true"<?php endif?> >
    @@ -208,8 +208,8 @@
                     <?php endif; ?>
     
         		    <input type="submit" class="btn btn-secondary" name="Cancel_account" value="<?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('user/edit','Cancel');?>"/>
    -        	</div>	
    -	
    +        	</div>
    +
     	   </form>
     	</div>
     
    @@ -226,8 +226,8 @@
     		<?php if (isset($account_updated_departaments) && $account_updated_departaments == 'done') : $msg = erTranslationClassLhTranslation::getInstance()->getTranslation('user/account','Account updated'); ?>
     			<?php include(erLhcoreClassDesign::designtpl('lhkernel/alert_success.tpl.php'));?>
     		<?php endif; ?>
    -		
    -		<?php 
    +
    +		<?php
     		  $userDepartaments = erLhcoreClassUserDep::getUserDepartamentsIndividual($user->id);
     		  $userDepartamentsRead = erLhcoreClassUserDep::getUserDepartamentsIndividual($user->id, true);
     		  $userDepartamentsGroup = erLhcoreClassModelDepartamentGroupUser::getUserGroupsIds($user->id);
    @@ -271,13 +271,13 @@
                   );
               }
     		?>
    -		
    +
     		<form action="<?php echo erLhcoreClassDesign::baseurl('user/edit')?>/<?php echo $user->id?>#departments" method="post" enctype="multipart/form-data">
    -		
    +
     		    <?php include(erLhcoreClassDesign::designtpl('lhuser/account/departments_assignment.tpl.php'));?>
    -		    
    +
     		    <input type="submit" class="btn btn-secondary" name="UpdateDepartaments_account" value="<?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('user/edit','Update');?>"/>
    -		</form> 
    +		</form>
         </div>
         <?php endif; ?>
     
    @@ -318,7 +318,7 @@
             <p><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('user/account','In order to change operator permissions you have to edit');?> <a href="<?php echo erLhcoreClassDesign::baseurl('permission/roles')?>"><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('user/account','roles');?></a>.</p>
     
             <input type="button" class="btn btn-secondary" name="UpdateSpeech_account" onclick="lhinst.showMyPermissions('<?php echo $user->id?>')" value="<?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('user/account','Show permissions');?>" />
    -		<div id="permissions-summary"></div>		
    +		<div id="permissions-summary"></div>
         </div>
     	<?php endif;?>
     
    @@ -350,5 +350,5 @@
         <?php endif; ?>
     
     	<?php include(erLhcoreClassDesign::designtpl('lhuser/menu_tabs_content/custom_multiinclude_tab.tpl.php'));?>
    -	
    +
     </div>
    
  • lhc_web/design/defaulttheme/tpl/lhuser/new.tpl.php+9 9 modified
    @@ -28,17 +28,17 @@
     		
     		<div class="form-group">
     		  <label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('user/new','E-mail');?></label>
    -		  <input type="text" class="form-control" name="Email" value="<?php echo htmlspecialchars($user->email);?>"/>
    +		  <input type="text" ng-non-bindable class="form-control" name="Email" value="<?php echo htmlspecialchars($user->email);?>"/>
     		</div>
     					
     		<div class="form-group">
     		  <label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('user/new','Password');?></label>
    -		  <input type="password" class="form-control" autocomplete="new-password" name="Password" value="<?php echo htmlspecialchars(isset($user->password_temp_1) ? $user->password_temp_1 : '');?>" />
    +		  <input type="password" ng-non-bindable class="form-control" autocomplete="new-password" name="Password" value="<?php echo htmlspecialchars(isset($user->password_temp_1) ? $user->password_temp_1 : '');?>" />
     		</div>
     		
     		<div class="form-group">
     		  <label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('user/new','Repeat the new password');?></label>
    -		  <input type="password" class="form-control" autocomplete="new-password" name="Password1" value="<?php echo htmlspecialchars(isset($user->password_temp_2) ? $user->password_temp_2 : '');?>" />
    +		  <input type="password" ng-non-bindable class="form-control" autocomplete="new-password" name="Password1" value="<?php echo htmlspecialchars(isset($user->password_temp_2) ? $user->password_temp_2 : '');?>" />
     		</div>
     
             <div class="form-group">
    @@ -47,22 +47,22 @@
     
     		<div class="form-group">
     			<label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('user/new','Chat nickname');?></label>
    -			<input type="text" class="form-control" name="ChatNickname" value="<?php echo htmlspecialchars($user->chat_nickname);?>" />
    +			<input type="text" class="form-control" ng-non-bindable name="ChatNickname" value="<?php echo htmlspecialchars($user->chat_nickname);?>" />
     		</div>
     		
     		<div class="form-group">
     		  <label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('user/new','Name');?></label>
    -		  <input class="form-control" type="text" name="Name" value="<?php echo htmlspecialchars($user->name);?>" />
    +		  <input class="form-control" ng-non-bindable type="text" name="Name" value="<?php echo htmlspecialchars($user->name);?>" />
     		</div>
     		
     		<div class="form-group">
     		  <label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('user/new','Surname');?></label>
    -		  <input class="form-control" type="text" name="Surname" value="<?php echo htmlspecialchars($user->surname);?>" />
    +		  <input class="form-control" ng-non-bindable type="text" name="Surname" value="<?php echo htmlspecialchars($user->surname);?>" />
     		</div>
     		
     		<div class="form-group">
     		  <label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('user/account','Job title');?></label>
    -		  <input type="text" class="form-control" name="JobTitle" value="<?php echo htmlspecialchars($user->job_title);?>"/>
    +		  <input type="text" ng-non-bindable class="form-control" name="JobTitle" value="<?php echo htmlspecialchars($user->job_title);?>"/>
     		</div>
     		
     		<?php include(erLhcoreClassDesign::designtpl('lhuser/parts/time_zone.tpl.php'));?>
    @@ -87,11 +87,11 @@
     		<div class="row form-group">
     			<div class="col-md-6">
     				<label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('user/account','Skype');?></label>
    -				<input class="form-control" type="text" name="Skype" value="<?php echo htmlspecialchars($user->skype);?>"/>
    +				<input class="form-control" ng-non-bindable maxlength="50" type="text" name="Skype" value="<?php echo htmlspecialchars($user->skype);?>"/>
     			</div>
     			<div class="col-md-6">
     				<label><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('user/account','XMPP username');?></label>
    -				<input class="form-control" type="text" name="XMPPUsername" value="<?php echo htmlspecialchars($user->xmpp_username);?>"/>
    +				<input class="form-control" ng-non-bindable type="text" name="XMPPUsername" value="<?php echo htmlspecialchars($user->xmpp_username);?>"/>
     			</div>
     		</div>
     
    
  • lhc_web/design/defaulttheme/tpl/lhuser/parts/avatar_build.tpl.php+1 1 modified
    @@ -1,4 +1,4 @@
    -<div class="row">
    +<div class="row" ng-non-bindable>
         <?php if (!(isset($can_edit_groups) && $can_edit_groups === false)) : ?>
         <div class="col-9">
             <div class="input-group mb-3">
    
  • lhc_web/lib/core/lhuser/lhuservalidator.php+2 2 modified
    @@ -177,7 +177,7 @@ public static function validateUser(& $userData, $params = array()) {
     		}
     		
     		if ( $form->hasValidData( 'Skype' ) && $form->Skype != '') {
    -			$userData->skype = $form->Skype;
    +			$userData->skype = mb_substr($form->Skype,0,50);
     		} else {
     			$userData->skype = '';
     		}
    @@ -915,7 +915,7 @@ public static function validateAccount(& $userData) {
     		
     		if ( erLhcoreClassUser::instance()->hasAccessTo('lhuser','changeskypenick') ) {
     			if ( $form->hasValidData( 'Skype' ) && $form->Skype != '' ) {
    -				$userData->skype = $form->Skype;
    +				$userData->skype = mb_substr($form->Skype,0,50);
     			} else {
     				$userData->skype = '';
     			}
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.