CVE-2018-12030: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Chevereto Free before 1.0.13 has XSS.
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: 5.4
Published: 2018-06-15T16:29Z
Repository: https://github.com/Chevereto/Chevereto-Free
Language: PHP
Files changed: app/app.php, app/install/installer.php, app/routes/route.settings.php, app/themes/Peafowl/views/settings.php
Commit date: 2018-06-06 17:00:33 -0400
Commit message: v1.0.13

Fixed post handling in /settings (name, bio)

Diff: diff --git a/app/app.php b/app/app.php
index 78d313b..ac1960e 100644
--- a/app/app.php
+++ b/app/app.php
@@ -1,7 +1,7 @@
 <?php
 define('G_APP_NAME', 'Chevereto Free');
-define('G_APP_VERSION', '1.0.12');
+define('G_APP_VERSION', '1.0.13');
 define('G_APP_GITHUB_OWNER', 'Chevereto');
 define('G_APP_GITHUB_REPO', 'Chevereto-Free');
 define('G_APP_GITHUB_REPO_URL', 'https://github.com/' . G_APP_GITHUB_OWNER . '/' . G_APP_GITHUB_REPO);
 define('CHEVERETO_INSTALLER_DOWNLOAD_URL', 'https://chevereto.com/download/file/installer');
\ No newline at end of file
diff --git a/app/install/installer.php b/app/install/installer.php
index 1f90b03..e6e7a2b 100644
--- a/app/install/installer.php
+++ b/app/install/installer.php
@@ -242,10 +242,11 @@
 			'enable_plugin_route' => 1,
 			'sdk_pup_url' => NULL,
 		],
 		'1.0.11' => NULL,
 		'1.0.12' => NULL,
+		'1.0.13' => NULL,
 	];
 	// Settings that must be renamed from NAME to NEW NAME and DELETE old NAME
 	$settings_rename = [];
 
 	// Settings that must be renamed from NAME to NEW NAME and doesn't delete old NAME
diff --git a/app/routes/route.settings.php b/app/routes/route.settings.php
index 71f7ac4..9911dae 100644
--- a/app/routes/route.settings.php
+++ b/app/routes/route.settings.php
@@ -7,86 +7,86 @@
 
   @author	Rodolfo Berrios A. <http://rodolfoberrios.com/>
 			<inbox@rodolfoberrios.com>
 
   Copyright (C) Rodolfo Berrios A. All rights reserved.
-  
+
   BY USING THIS SOFTWARE YOU DECLARE TO ACCEPT THE CHEVERETO EULA
   http://chevereto.com/license
 
   --------------------------------------------------------------------- */
 
 $route = function($handler) {
 	try {
-		
+
 		if($_POST and !$handler::checkAuthToken($_REQUEST['auth_token'])) {
 			$handler->template = 'request-denied';
 			return;
 		}
-		
+
 		$logged_user = CHV\Login::getUser();
-		
+
 		if(!$logged_user) {
 			G\redirect('login');
 		}
-		
+
 		// User status override redirect
 		CHV\User::statusRedirect($logged_user['status']);
-		
+
 		// Dashboard hack
 		$handler->template = 'settings';
 		$is_dashboard_user = $handler::getCond('dashboard_user');
-		
+
 		// Request log
 		if(!$is_dashboard_user) {
 			$request_log = CHV\Requestlog::getCounts('account-edit', 'fail');
 		}
-		
+
 		// Editable values
 		$allowed_to_edit = ['name', 'username', 'email', 'avatar_filename', 'website', 'background_filename', 'timezone', 'language', 'status', 'is_admin', 'image_keep_exif', 'image_expiration', 'newsletter_subscribe', 'bio', 'show_nsfw_listings', 'is_private'];
-		
+
         if(CHV\getSetting('enable_expirable_uploads')) {
             unset($allowed_to_edit['image_expiration']);
         }
-        
+
 		// User handle
 		$user = $is_dashboard_user ? CHV\User::getSingle($handler->request[1], 'id') : $logged_user;
 		$is_owner = $user['id'] == CHV\Login::getUser()['id'];
-		
+
 		// Update the lang displayed on change
 		if(in_array('language', $allowed_to_edit) and isset($_POST['language']) and $logged_user['language'] !== $_POST['language'] and $logged_user['id'] == $user['id'] and array_key_exists($_POST['language'], CHV\L10n::getEnabledLanguages())) {
 			CHV\L10n::processTranslation($_POST['language']);
 		}
-		
+
 		// Settings routes
 		$routes = [
 			'account'			=> _s('Account'),
 			'profile'		  	=> _s('Profile'),
 			'password'		  	=> _s('Password'),
 			'homepage' 			=> _s('Homepage')
 		];
 		$default_route = 'account';
-		
+
 		if(CHV\getSetting('website_mode') == 'personal' and CHV\getSetting('website_mode_personal_routing') !== '/' and $logged_user['id'] == CHV\getSetting('website_mode_personal_uid')) {
 			$route_homepage = TRUE;
 		}
-		
+
 		$is_email_required = TRUE;
 		// Don't require email for admin when editing users
 		if($handler::getCond('admin') AND !$is_owner) {
 			$is_email_required = FALSE;
 		}
-		
+
 		$doing_level = $is_dashboard_user ? 2 : 0;
 		$doing = $handler->request[$doing_level];
 
 		if(!$user or $handler->request[$doing_level+1] or (!is_null($doing) and !array_key_exists($doing, $routes))) {
 			return $handler->issue404();
 		}
-		
+
 		if($doing == '') $doing = $default_route;
-		
+
 		// Populate the routes
 		foreach($routes as $route => $label) {
 			$aux = str_replace('_', '-', $route);
 			$handler::setCond('settings_'.$aux, $doing == $aux);
 			if($handler::getCond('settings_'.$aux)) {
@@ -99,105 +99,105 @@
 				'label' => $label,
 				'url'	=> G\get_base_url(($is_dashboard_user ? ('dashboard/user/' . $user['id']) : 'settings') . ($route == $default_route ? '' : '/'.$route)),
 				'current' => $handler::getCond('settings_'.$aux)
 			);
 		}
-		
+
 		$handler::setVar('settings_menu', $settings_menu);
-		
+
 		if(!array_key_exists($doing, $routes)) {
 			return $handler->issue404();
 		}
-		
+
 		// Safe print $_POST
-		$SAFE_POST = $handler::getVar('safe_post');	
-		
+		$SAFE_POST = $handler::getVar('safe_post');
+
 		// conds
 		$is_error = false;
 		$is_changed = false;
 		$captcha_needed = false;
-		
+
 		// vars
 		$input_errors = array();
 		$error_message = NULL;
 		$changed_email_message = NULL;
-		
+
 		if($_POST) {
-			
+
 			$field_limits = 255;
-			
+
 			foreach($allowed_to_edit as $k) {
 				if($_POST[$k]) {
 					$_POST[$k] = substr($_POST[$k], 0, $field_limits);
 				}
 			}
-			
+
 			// Input validations
 			switch($doing) {
-				
+
 				case NULL:
 				case 'account':
-					
+
 					$checkboxes = ['upload_image_exif', 'newsletter_subscribe', 'show_nsfw_listings', 'is_private'];
 					foreach($checkboxes as $k) {
 						if(!isset($_POST[$k])) {
 							continue;
 						}
 						$_POST[$k] = in_array($_POST[$k], ['On', 1]) ? 1 : 0;
 					}
-					
+
 					G\nullify_string($_POST['image_expiration']);
-                    
+
 					$__post = [];
 					$__safe_post = [];
 					foreach(['username', 'email'] as $v) {
 						if(isset($_POST[$v])) {
 							$_POST[$v] = $v == 'email' ? trim($_POST[$v]) : strtolower(trim($_POST[$v]));
 							$__post[$v] = $_POST[$v];
 							$__safe_post[$v] = G\safe_html($_POST[$v]);
 						}
 					}
-					
+
 					$handler::updateVar('post', $__post);
 					$handler::updateVar('safe_post', $__safe_post);
-					
+
 					if(!CHV\User::isValidUsername($_POST['username'])) {
 						$input_errors['username'] = _s('Invalid username');
 					}
-					
+
 					if($is_email_required and !filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
 						$input_errors['email'] = _s('Invalid email');
 					}
-                    
+
                     if(CHV\getSetting('enable_expirable_uploads')) {
                         // Image expire time
                         if($_POST['image_expiration'] !== NULL && (!G\dateinterval($_POST['image_expiration']) || !array_key_exists($_POST['image_expiration'], CHV\Image::getAvailableExpirations()))) {
                             $input_errors['image_expiration'] = _s('Invalid image expiration: %s', $_POST['image_expiration']);
                         }
                     }
-                    
+
 					if(!array_key_exists($_POST['language'], CHV\get_available_languages())) {
 						$_POST['language'] = CHV\getSetting('default_language');
 					}
 					if(!in_array($_POST['timezone'], timezone_identifiers_list())) {
 						$_POST['timezone'] = date_default_timezone_get();
 					}
 
 					if(count($input_errors) > 0) {
 						$is_error = true;
 					}
-					
+
 					if(!$is_error) {
-						
+
 						$user_db = CHV\DB::get('users', ['username' => $_POST['username'], 'email' => $_POST['email']], 'OR', NULL);
-						
+
 						if($user_db) {
-							
+
 							foreach($user_db as $row) {
-								
+
 								if($row['user_id'] == $user['id']) continue; // Same guy?
-								
+
 								// Invalid user, check the time
 								if(!in_array($row['user_status'], ['valid', 'banned'])) { // Don't touch the valid and banned users
 									$must_delete_old_user = false;
 									$confirmation_db = CHV\Confirmation::get(['user_id' => $row['user_id']]);
 									if($confirmation_db) {
@@ -213,121 +213,121 @@
 									if($must_delete_old_user) {
 										CHV\DB::delete('users', ['id' => $row['user_id']]);
 										continue;
 									}
 								}
-								
+
 								// Username taken?
 								if(G\timing_safe_compare($row['user_username'], $_POST['username']) and $user['username'] !== $row['user_username']) {
 									$input_errors['username'] = 'Username already being used';
 								}
 								// Email taken?
 								if(!empty($_POST['email']) && G\timing_safe_compare($row['user_email'], $_POST['email']) &&
 								   $user['email'] !== $row['user_email']) {
 									$input_errors['email'] = _s('Email already being used');
 								}
 							}
-							
+
 							if(count($input_errors) > 0) {
 								$is_error = true;
 							}
 						}
 					}
 
 					// Email MUST be validated (two steps)
 					if(!$is_error && !empty($_POST['email']) && !G\timing_safe_compare($user['email'], $_POST['email'])) {
-						
+
 						// Delete any old confirmation
 						CHV\Confirmation::delete(['type' => 'account-change-email', 'user_id' => $user['id']]);
-						
+
 						// Generate the thing
 						$hashed_token = CHV\generate_hashed_token($user['id']);
 						$insert_email_confirm = CHV\Confirmation::insert([
 							'type'			=> 'account-change-email',
 							'user_id'		=> $user['id'],
 							'token_hash'	=> $hashed_token['hash'],
 							'status'		=> 'active',
 							'extra'			=> $_POST['email']
 						]);
 						$email_confirm_link = G\get_base_url('account/change-email-confirm/?token='.$hashed_token['public_token_format']);
-						$changed_email_message = _s('An email has been sent to %s with instructions to activate this email', $SAFE_POST['email']);	
-						
+						$changed_email_message = _s('An email has been sent to %s with instructions to activate this email', $SAFE_POST['email']);
+
 						// Build the mail global
 						global $theme_mail;
 						$theme_mail = [
 							'user' => $user,
 							'link' => $email_confirm_link
 						];
-						
+
 						ob_start();
 						require_once(G_APP_PATH_THEME . 'mails/account-change-email.php');
 						$mail_body = ob_get_contents();
 						ob_end_clean();
-						
+
 						$mail['subject'] = _s('Confirmation required at %s', CHV\getSettings()['website_name']);
 						$mail['message'] = $mail_body;
 
 						try {
 							if(CHV\send_mail($_POST['email'], $mail['subject'], $mail['message'])) {
 								//$is_changed = true;
 							}
 						} catch(Exception $e) {
 							echo($e->getMessage());
 						}
-						
+
 						unset($_POST['email']);
-						
+
 					}
-					
+
 				break;
-				
+
 				case 'profile':
 					if(!preg_match('/^.{1,60}$/', $_POST['name'])) {
 						$input_errors['name'] = _s('Invalid name');
 					}
 					if($_POST['website'] and !filter_var($_POST['website'], FILTER_VALIDATE_URL)) {
 						$input_errors['website'] = _s('Invalid website');
 					}
 				break;
-				
+
 				case 'password':
-					
+
 					if(!$is_dashboard_user) {
 						if($user['login']['password'] && !password_verify($_POST['current-password'], $user['login']['password']['secret'])) {
 							$input_errors['current-password'] = _s('Wrong password');
 						} else {
 							if($_POST['current-password'] == $_POST['new-password']) {
 								$input_errors['new-password'] = _s('Use a new password');
 								$handler::updateVar('safe_post', ['current-password' => NULL]);
 							}
 						}
 					}
-				
+
 					if(!preg_match('/'.CHV\getSetting('user_password_pattern').'/', $_POST['new-password'])) {
 						$input_errors['new-password'] = _s('Invalid password');
 					}
-					
+
 					if($_POST['new-password'] !== $_POST['new-password-confirm']) {
 						$input_errors['new-password-confirm'] = _s("Passwords don't match");
 					}
 
 				break;
-				
+
 				case 'homepage':
 					if(!array_key_exists($doing, $routes)) { // Nope
 						$handler->issue404();
 					}
 					$allowed_to_edit = ['homepage_title_html', 'homepage_paragraph_html', 'homepage_cta_html'];
-					
+
 					// Protect editing
 					$editing_array = G\array_filter_array($_POST, $allowed_to_edit, 'exclusion');
 					$update_settings = [];
 					foreach($allowed_to_edit as $k) {
 						if(!array_key_exists($k, CHV\Settings::get()) or CHV\Settings::get($k) == $editing_array[$k]) continue;
 						$update_settings[$k] = $editing_array[$k];
 					}
-					
+
 					// Update settings (if any)
 					if($update_settings) {
 						$db = CHV\DB::getInstance();
 						$db->beginTransaction();
 						$db->query('UPDATE ' . CHV\DB::getTable('settings') . ' SET setting_value = :value WHERE setting_name = :name;');
@@ -342,37 +342,37 @@
 								CHV\Settings::setValue($k, $v);
 							}
 						}
 					}
 				break;
-				
+
 				default:
 					$handler->issue404();
 				break;
 			}
-			
+
 			if(count($input_errors) > 0) {
 				$is_error = true;
 			}
-			
+
 			if(!$is_error) {
-			
+
 				// Account and profile changes
 				if(in_array($doing, [NULL, 'account', 'profile'])) {
-					
+
 					// Detect changes
 					foreach($_POST as $k => $v) {
 						if($user[$k] !== $v) {
 							$is_changed = true;
 						}
 					}
 
 					if($is_changed) {
-						
+
 						// Protect editing
 						$editing_array = G\array_filter_array($_POST, $allowed_to_edit, 'exclusion');
-						
+
 						if(!$is_dashboard_user) {
 							unset($editing_array['status'], $editing_array['is_admin']);
 						} else {
 							if(!in_array($editing_array['status'], ['valid', 'banned', 'awaiting-confirmation', 'awaiting-email'])) {
 								unset($editing_array['status']);
@@ -390,84 +390,87 @@
 							unset($editing_array['email']);
 						}
 
 						if(CHV\User::update($user['id'], $editing_array)) {
 							$user = array_merge($user, $editing_array);
-							$handler::updateVar('safe_post', ['name' => CHV\User::sanitizeUserName($_POST['name'])]);
+							// 'name' gets sanitized on User::update, this update safe_post to reflect the actual value
+							$handler::updateVar('safe_post', [
+								'name' => G\safe_html($user['name']),
+							]);
 						}
-						
+
 						if(!$is_dashboard_user) {
 							$logged_user = CHV\Login::login($user['id'], $_SESSION['login']['type']);
 						} else {
 							$user = CHV\User::getSingle($user['id'], 'id');
 						}
 						$changed_message = _s('Changes have been saved.');
 					}
 				}
-				
+
 				// Update/create password
 				if($doing == 'password') {
-					
+
 					if($user['login']['password']) {
-					
+
 						// Delete any old cookie/session login for this user
 						CHV\Login::delete(['type' => 'cookie', 'user_id' => $user['id']]);
 						CHV\Login::delete(['type' => 'session', 'user_id' => $user['id']]);
-						
+
 						// Insert the new login DB if needed
 						if(!$is_dashboard_user and $_COOKIE['KEEP_LOGIN']) {
 							CHV\Login::insert(['type' => 'cookie', 'user_id' => $user['id']]);
 						}
-												
+
 						$is_changed = CHV\Login::changePassword($user['id'], $_POST['new-password']); // This inserts the session login
 						$changed_message = _s('Password has been changed');
-						
+
 					} else { // Insert
-						
+
 						$is_changed = CHV\Login::addPassword($user['id'], $_POST['new-password']);
 						$changed_message = _s('Password has been created.');
 						if(!$is_dashboard_user or $logged_user['id'] == $user['id']) {
 							$logged_user = CHV\Login::login($user['id'], 'password');
 						}
 					}
-					
+
 					$unsets = array('current-password', 'new-password', 'new-password-confirm');
 					foreach($unsets as $unset) {
 						$handler::updateVar('safe_post', [$unset => NULL]);
 					}
 				}
-				
+
 			} else {
 				if(in_array($doing, array('', 'account')) and !$is_dashboard_user) {
 					CHV\Requestlog::insert(array('type' => 'account-edit', 'result' => 'fail'));
 					$error_message = _s('Wrong Username/Email values');
 				}
 			}
 
 		}
-		
+
 		$handler::setCond('settings_linked_accounts', FALSE);
-		
+
 		$handler::setCond('owner', $is_owner);
 		$handler::setCond('error', $is_error);
 		$handler::setCond('changed', $is_changed);
 		$handler::setCond('captcha_needed', $captcha_needed);
 		$handler::setCond('dashboard_user', $is_dashboard_user);
 		$handler::setCond('email_required', $is_email_required);
-		
+
 		if($captcha_needed and !$handler::getVar('recaptcha_html')) {
 			$handler::setVar('recaptcha_html', CHV\Render\get_recaptcha_html());
 		}
-		
+
 		$handler::setVar('pre_doctitle', $is_dashboard_user ? _s('Settings for %s', $user['username']) : _s('Settings'));
-		
+
 		$handler::setVar('error',  $error_message);
 		$handler::setVar('input_errors', $input_errors);
 		$handler::setVar('changed_message', $changed_message);
 		$handler::setVar('changed_email_message', $changed_email_message);
 		$handler::setVar('user', $is_dashboard_user ? $user : $logged_user);
 		$handler::setVar('safe_html_user', G\safe_html($handler::getVar('user')));
-		
+
 	} catch(Exception $e) {
 		G\exception_to_error($e);
 	}
 };
\ No newline at end of file
diff --git a/app/themes/Peafowl/views/settings.php b/app/themes/Peafowl/views/settings.php
index 7e55b74..0b7e753 100644
--- a/app/themes/Peafowl/views/settings.php
+++ b/app/themes/Peafowl/views/settings.php
@@ -1,12 +1,12 @@
 <?php if(!defined('access') or !access) die('This file cannot be directly accessed.'); ?>
 <?php G\Render\include_theme_header(); ?>
 
 <div class="content-width">
-    
+
 	<div class="c24 center-box">
-		
+
 		<div class="header header-tabs default-margin-bottom">
 			<h1><?php echo get_pre_doctitle(); ?></h1>
 			<div class="hidden phone-show phablet-show">
 				<?php
 					foreach(get_settings_menu() as $tab) {
@@ -38,27 +38,27 @@
 			</div>
 			<?php
 				}
 			?>
 		</div>
-		
+
 		<div class="form-content">
-			
+
 			<ul class="content-tabs c5 content-tabs-vertical phone-hide phablet-hide">
 				<?php
 					foreach(get_settings_menu() as $item) {
 				?>
 				<li<?php if($item["current"]) echo ' class="current"'; ?>><a href="<?php echo $item["url"]; ?>"><?php echo $item["label"]; ?></a></li>
 				<?php
 					}
 				?>
 			</ul>
-		
+
 			<form data-content="main-form" class="tabbed-input-column" method="post" data-type="<?php echo get_setting(); ?>" data-action="validate">
-				
+
 				<?php echo G\Render\get_input_auth_token(); ?>
-				
+
 				<?php
 					if(is_settings_account()) {
 
 						if(is_dashboard_user() or is_admin()) {
 				?>
@@ -97,11 +97,11 @@
 					<li><span class="c4 display-table-cell padding-right-10"><?php echo $v['label']; ?></span> <span class="display-table-cell"><?php echo $v['content']; ?></span></li>
 					<?php
 						}
 					?>
 				</ul>
-				
+
 				<div class="c5 phablet-c1">
 					<div class="input-label">
 						<label for="status"><?php _se('Status'); ?></label>
 						<select name="status" id="status" class="text-input">
 							<?php
@@ -130,13 +130,13 @@
 								}
 							?>
 						</select>
 					</div>
 				</div>
-				
+
 				<hr class="line-separator"></hr>
-				
+
 				<?php
 						}
 				?>
 				<div class="c9 phablet-c1">
 					<div class="input-label">
@@ -156,13 +156,13 @@
 						<input type="email" name="email" id="email" class="text-input" value="<?php echo get_safe_post() ? get_safe_post()["email"] : get_user()["email"]; ?>" placeholder="<?php _se('Your email address'); ?>"<?php if(is_email_required()) { ?> required<?php } ?>>
 						<span class="input-warning red-warning"><?php echo get_input_errors()["email"]; ?></span>
 						<?php if(get_changed_email_message()) { ?><div class="input-below highlight padding-5"><?php echo get_changed_email_message(); ?></div><?php } ?>
 					</div>
 				</div>
-				
+
 				<hr class="line-separator"></hr>
-				
+
 				<?php if(CHV\getSetting('enable_expirable_uploads')) { ?>
                 <div class="input-label">
                     <label for="image_expiration"><?php _se('Auto delete uploads'); ?></label>
                     <div class="c6 phablet-1">
                         <select type="text" name="image_expiration" id="image_expiration" class="text-input">
@@ -174,44 +174,44 @@
 					<div class="input-below input-warning red-warning"><?php echo get_input_errors()["image_expiration"]; ?></div>
                     <div class="input-below"><?php _se('This setting will apply to all your image uploads by default. You can override this setting on each upload.'); ?></div>
                 </div>
 
                 <hr class="line-separator"></hr>
-				
+
 				<?php } ?>
-				
+
                 <?php if(CHV\getSetting('upload_image_exif_user_setting')) { ?>
                 <div class="input-label">
                     <label><?php _se('Image Exif data'); ?></label>
 					<?php echo CHV\Render\get_checkbox_html([
 						'name'		=> 'image_keep_exif',
 						'label'		=> _s('Keep image <a %s>Exif data</a> on upload', 'href="https://www.google.com/search?q=Exif" target="_blank"'),
 						'checked'	=> ((bool)(get_safe_post() ? get_safe_post()['image_keep_exif'] : get_user()['image_keep_exif']))
 					]); ?>
                 </div>
                 <?php } ?>
-        
+
 				<div class="input-label">
 					<label><?php _se('Newsletter'); ?></label>
 					<?php echo CHV\Render\get_checkbox_html([
 						'name'		=> 'newsletter_subscribe',
 						'label'		=> _s('Send me emails with news about %s', CHV\getSetting('website_name')),
 						'checked'	=> ((bool)(get_safe_post() ? get_safe_post()['newsletter_subscribe'] : get_user()['newsletter_subscribe']))
 					]); ?>
 				</div>
-				
+
 				<div class="input-label">
 					<label><?php _se('Content settings'); ?></label>
 					<?php echo CHV\Render\get_checkbox_html([
 						'name'		=> 'show_nsfw_listings',
 						'label'		=> _s('Show not safe content in listings (from others)'),
 						'checked'	=> ((bool)(get_safe_post() ? get_safe_post()['show_nsfw_listings'] : get_user()['show_nsfw_listings']))
 					]); ?>
 				</div>
-				
+
 				<hr class="line-separator"></hr>
-				
+
 				<?php if(CHV\getSetting('language_chooser_enable')) { ?>
 				<div class="c5 phablet-c1">
 					<div class="input-label">
 						<label for="language"><?php _se('Language'); ?></label>
 						<select name="language" id="language" class="text-input">
@@ -224,31 +224,31 @@
 							?>
 						</select>
 					</div>
 				</div>
 				<?php } ?>
-				
-				<?php 
+
+				<?php
 
 				$zones = timezone_identifiers_list();
-				
+
 				foreach ($zones as $zone) {
 					$zone = explode('/', $zone);
-					if(in_array($zone[0], array("Africa", "America", "Antarctica", "Arctic", "Asia", "Atlantic", "Australia", "Europe", "Indian", "Pacific"))) {      
+					if(in_array($zone[0], array("Africa", "America", "Antarctica", "Arctic", "Asia", "Atlantic", "Australia", "Europe", "Indian", "Pacific"))) {
 						if (isset($zone[1]) != '') {
 							$regions[$zone[0]][$zone[0]. '/' . $zone[1]] = str_replace('_', ' ', $zone[1]);
-						} 
+						}
 					}
 				}
-				
+
 				?>
-				
+
 				<div class="input-label">
 					<label for="timezone"><?php _se('Timezone'); ?></label>
-					
+
 					<div class="overflow-auto">
-					
+
 						<select id="timezone-region" class="c5 phablet-c1 grid-columns margin-right-10 phone-margin-bottom-10 phablet-margin-bottom-10 text-input" data-combo="timezone-combo">
 							<option><?php _se('Select region'); ?></option>
 							<?php
 								$user_region = preg_replace("/(.*)\/.*/", "$1", get_user()["timezone"]);
 								foreach($regions as $key => $region) {
@@ -274,19 +274,19 @@
 								}
 							?>
 						</div>
 
 					</div>
-					
+
 					<input type="hidden" id="timezone" name="timezone" data-content="timezone" data-highlight="#timezone-region" value="<?php echo get_user()["timezone"]; ?>" required>
-					
+
 				</div>
 
 				<?php } ?>
-				
+
 				<?php if(is_settings_password()) { ?>
-				
+
 				<?php
 					// User has password
 					if(get_user()["login"]["password"] !== NULL) {
 				?>
 				<div class="c9 phablet-c1">
@@ -333,11 +333,11 @@
 				</div>
 				<?php
 					}
 				?>
 				<?php } ?>
-				
+
 				<?php if(is_settings_profile()) { ?>
 				<div class="c19 phablet-c1">
 					<div class="input-upload user-settings-avatar">
 						<div class="user-settings-avatar-container grid-columns margin-right-10 phablet-float-left">
 							<?php if(get_user()["avatar"]["url"]) { ?>
@@ -357,21 +357,21 @@
 							</div>
 						</div>
 						<input id="user-avatar-upload" data-content="user-avatar-upload-input" class="hidden-visibility" type="file" accept="image/*">
 					</div>
 				</div>
-				
+
 				<div class="input-label">
                     <label><?php _se('Privacy'); ?></label>
 					<?php echo CHV\Render\get_checkbox_html([
 						'name'		=> 'is_private',
 						'label'		=> _s('Make my profile and identity totally private'),
 						'tooltip'	=> _s('Enable this if you want to act like an anonymous user'),
 						'checked'	=> ((bool)(get_safe_post() ? get_safe_post()['is_private'] : get_user()['is_private']))
-					]); ?>      
+					]); ?>
 				</div>
-				
+
 				<div class="c9 phablet-c1">
 					<div class="input-label">
 						<label for="name"><?php _se('Name'); ?></label>
 						<input type="text" name="name" id="name" class="text-input" maxlength="60" value="<?php echo get_safe_post() ? get_safe_post()["name"] : get_safe_html_user()["name"]; ?>" placeholder="Your real name" required>
 						<span class="input-warning red-warning"><?php echo get_input_errors()["name"]; ?></span>
@@ -382,16 +382,16 @@
 						<input type="url" name="website" id="website" class="text-input" value="<?php echo get_safe_post() ? get_safe_post()["website"] : get_user()["website_safe_html"]; ?>" data-validate rel="tooltip" title="<?php _se('http://yourwebsite.com'); ?>" data-tipTip="right" placeholder="<?php _se('http://yourwebsite.com'); ?>">
 						<span class="input-warning red-warning"><?php echo get_input_errors()["website"]; ?></span>
 					</div>
 					<div class="input-label">
 						<label for="bio"><?php _se('Bio'); ?></label>
-						<textarea name="bio" id="bio" class="resize-vertical" placeholder="<?php _se('Tell us a little bit about you'); ?>" maxlength="255"><?php echo get_safe_post() ? get_safe_post()["bio"] : get_user()["bio"]; ?></textarea>
+						<textarea name="bio" id="bio" class="resize-vertical" placeholder="<?php _se('Tell us a little bit about you'); ?>" maxlength="255"><?php echo get_safe_post() ? get_safe_post()["bio"] : get_safe_html_user()["bio"]; ?></textarea>
 						<span class="input-warning red-warning"><?php echo get_input_errors()["bio"]; ?></span>
 					</div>
 				</div>
 				<?php } ?>
-				
+
 				<?php
 					if(is_settings_linked_accounts()) {
 
 						if(is_dashboard_user()) {
 				?>
@@ -422,11 +422,11 @@
 					<div class="account-link-status"><?php echo $title; ?></div>
 				</div>
 				<?php
 						}
 				?>
-				
+
 				<?php
 						if(!is_dashboard_user()) {
 							foreach(get_available_connections() as $connection => $label) {
 				?>
 				<div class="account-link input-label<?php if(get_connections()[$connection]) echo ' soft-hidden'; ?>" data-connect="<?php echo $connection; ?>">
@@ -435,53 +435,53 @@
 				</div>
 				<?php
 							}
 						}
 				?>
-				
+
 				<?php } ?>
-				
+
 				<?php if(is_settings_homepage()) { ?>
 				<div class="input-label">
 					<label for="homepage_title_html"><?php _se('Title'); ?></label>
 					<div class="c12 phablet-c1"><textarea type="text" name="homepage_title_html" id="homepage_title_html" class="text-input r2 resize-vertical" placeholder="<?php echo get_user()['name']; ?>"><?php echo CHV\Settings::get('homepage_title_html'); ?></textarea></div>
 					<span class="input-warning red-warning"><?php echo get_input_errors()["homepage_title_html"]; ?></span>
 				</div>
-				
+
 				<div class="input-label">
 					<label for="homepage_paragraph_html"><?php _se('Paragraph'); ?></label>
 					<div class="c12 phablet-c1"><textarea type="text" name="homepage_paragraph_html" id="homepage_paragraph_html" class="text-input r2 resize-vertical" placeholder="<?php _se('Feel free to browse and discover all my shared images and albums.'); ?>"><?php echo CHV\Settings::get('homepage_paragraph_html'); ?></textarea></div>
 					<span class="input-warning red-warning"><?php echo get_input_errors()["homepage_paragraph_html"]; ?></span>
 				</div>
-				
+
 				<div class="input-label">
 					<label for="homepage_cta_html"><?php _se('Button'); ?></label>
 					<div class="c12 phablet-c1"><textarea type="text" name="homepage_cta_html" id="homepage_cta_html" class="text-input r2 resize-vertical" placeholder="<?php _se('View all my images'); ?>"><?php echo CHV\Settings::get('homepage_cta_html'); ?></textarea></div>
 					<span class="input-warning red-warning"><?php echo get_input_errors()["homepage_cta_html"]; ?></span>
 				</div>
 				<?php } ?>
-				
+
 				<hr class="line-separator"></hr>
-				
+
 				<?php if(is_captcha_needed()) { ?>
 				<div class="input-label">
 					<label for="recaptcha_response_field">reCAPTCHA</label>
 					<?php echo get_recaptcha_html(); ?>
 				</div>
 				<?php } ?>
-				
+
 				<?php if(!is_settings_linked_accounts()) { ?>
 				<div class="btn-container">
 					<button class="btn btn-input default" type="submit"><?php _se('Save changes'); ?></button> <span class="btn-alt"><?php _se('or'); ?> <a href="<?php echo get_user()["url"]; ?>"><?php _se('cancel'); ?></a></span>
 				</div>
 				<?php } ?>
-			
+
 			</form>
 		</div>
-	
+
 	</div>
-    
+
 </div>
 
 <?php if(get_post() and (is_changed() or is_error())) { ?>
 <script>
 $(function() {

Vulnerable code: define('G_APP_VERSION', '1.0.12');
  
		
		
		
		
		
		
		
		
        
		
		
		
		
		
		
		
		
		
		
		$SAFE_POST = $handler::getVar('safe_post');	
		
		
		
			
			
			
				
					
					
                    
					
					
					
                    
                    
					
						
						
							
								
								
								
							
						
						
						$changed_email_message = _s('An email has been sent to %s with instructions to activate this email', $SAFE_POST['email']);	
						
						
						
						
						
					
				
				
					
				
					
				
					
					
				
			
			
			
					
						
						
							$handler::updateVar('safe_post', ['name' => CHV\User::sanitizeUserName($_POST['name'])]);
						
				
					
					
						
												
						
						
					
				
		
		
		
		
		
		
    
		
		
			
		
				
				
				
				
				
				
				
				
				
        
				
				
				
				
				<?php 
				
					if(in_array($zone[0], array("Africa", "America", "Antarctica", "Arctic", "Asia", "Atlantic", "Australia", "Europe", "Indian", "Pacific"))) {      
						} 
				
				
					
					
					
					
				
				
				
				
					]); ?>      
				
						<textarea name="bio" id="bio" class="resize-vertical" placeholder="<?php _se('Tell us a little bit about you'); ?>" maxlength="255"><?php echo get_safe_post() ? get_safe_post()["bio"] : get_user()["bio"]; ?></textarea>
				
				
				
				
				
				
				
				
				
			
	
    
Fixed code: define('G_APP_VERSION', '1.0.13');
		'1.0.13' => NULL,




















		$SAFE_POST = $handler::getVar('safe_post');

























						$changed_email_message = _s('An email has been sent to %s with instructions to activate this email', $SAFE_POST['email']);





















							// 'name' gets sanitized on User::update, this update safe_post to reflect the actual value
							$handler::updateVar('safe_post', [
								'name' => G\safe_html($user['name']),
							]);



































				<?php

					if(in_array($zone[0], array("Africa", "America", "Antarctica", "Arctic", "Asia", "Atlantic", "Australia", "Europe", "Indian", "Pacific"))) {
						}










					]); ?>

						<textarea name="bio" id="bio" class="resize-vertical" placeholder="<?php _se('Tell us a little bit about you'); ?>" maxlength="255"><?php echo get_safe_post() ? get_safe_post()["bio"] : get_safe_html_user()["bio"]; ?></textarea>