CVE-2022-1509: Improper Neutralization of Special Elements used in a Command ('Command Injection') (CWE-77)
value: Sed Injection Vulnerability in GitHub repository hestiacp/hestiacp prior to 1.5.12. An authenticated remote attacker with low privileges can execute arbitrary code under root context.
CWE description: The product constructs all or part of a command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended command when it is sent to a downstream component.
CVSS v3 base score: 8.8
Published: 2022-04-28T10:15Z
Repository: https://github.com/hestiacp/hestiacp
Language: Other
Files changed: bin/v-add-access-key, bin/v-add-backup-host, bin/v-add-cron-job, bin/v-add-dns-domain, bin/v-add-dns-record, bin/v-add-fastcgi-cache, bin/v-add-firewall-chain, bin/v-add-mail-domain, bin/v-add-mail-domain-ssl, bin/v-add-mail-domain-webmail, bin/v-add-remote-dns-domain, bin/v-add-remote-dns-host, bin/v-change-user-ns, bin/v-change-user-theme, bin/v-change-web-domain-name, bin/v-check-access-key, bin/v-delete-database-temp-user, bin/v-delete-dns-on-web-alias, bin/v-delete-mail-account-forward, bin/v-delete-user-notification, bin/v-delete-user-ssh-key, bin/v-generate-ssl-cert, bin/v-get-user-salt, bin/v-log-action, bin/v-log-user-logout, bin/v-purge-nginx-cache, bin/v-schedule-letsencrypt-domain, bin/v-update-host-certificate, bin/v-update-user-backup-exclusions, func/main.sh, test/checks.bats, web/inc/main.php
Commit date: 2022-04-27 20:05:17 +0200
Commit message: [Security] Patches multiple security issue  (#2555)

* Add missing check in is_format_valid

* Add check on v-delete-dns-domain

* Validate theme via is_format_valid

* No need for extra code

* Prevent LF command passed trough + Add test to verify

* Add missing checks

* Don't allow exception for localhost

* Add some more missing checks

* Fix to strict error validation

* Add validation for user

* Fix bug in main.sh

* Use -d instead -f
Diff: diff --git a/bin/v-add-access-key b/bin/v-add-access-key
index a492a4fa45..6a54929612 100755
--- a/bin/v-add-access-key
+++ b/bin/v-add-access-key
@@ -59,16 +59,13 @@ date=$(echo "$time_n_date" |cut -f 2 -d \ )
 #----------------------------------------------------------#
 #                    Verifications                         #
 #----------------------------------------------------------#
 
 check_args '1' "$#" 'USER [PERMISSIONS] [COMMENT] [FORMAT]'
-is_format_valid 'user'
+is_format_valid 'user' 'comment' 'format'
 is_object_valid 'user' 'USER' "$user"
 is_key_permissions_format_valid "$permissions" "$user"
-if [ -n "$comment" ]; then
-    is_format_valid 'comment'
-fi
 
 #----------------------------------------------------------#
 #                       Action                             #
 #----------------------------------------------------------#
 
diff --git a/bin/v-add-backup-host b/bin/v-add-backup-host
index c3ca0dd0d1..665ae1b177 100755
--- a/bin/v-add-backup-host
+++ b/bin/v-add-backup-host
@@ -105,11 +105,12 @@ EOF
 #----------------------------------------------------------#
 
 if [ "$type" != 'local' ];then
     check_args '4' "$#" "TYPE HOST USERNAME PASSWORD [PATH] [PORT]"
     is_format_valid 'host' 'path' 'port'
-    is_username_format_valid "$username" "username"
+    is_type_valid "$type" 'sftp,ftp,b2'
+    is_username_format_valid "$user" "username"
     is_password_valid
     format_no_quotes "$password" "password"
     
     if [ "$type" = 'sftp' ]; then
         which expect >/dev/null 2>&1
diff --git a/bin/v-add-cron-job b/bin/v-add-cron-job
index 059bc05c20..fea441b30a 100755
--- a/bin/v-add-cron-job
+++ b/bin/v-add-cron-job
@@ -42,10 +42,11 @@ is_system_enabled "$CRON_SYSTEM" 'CRON_SYSTEM'
 is_object_valid 'user' 'USER' "$user"
 is_object_unsuspended 'user' 'USER' "$user"
 is_package_full 'CRON_JOBS'
 get_next_cronjob
 is_format_valid 'job'
+is_format_valid 'restart'
 is_object_new 'cron' 'JOB' "$job"
 
 # Perform verification if read-only mode is enabled
 check_hestia_demo_mode
 
diff --git a/bin/v-add-dns-domain b/bin/v-add-dns-domain
index 69a707cc39..68014da368 100755
--- a/bin/v-add-dns-domain
+++ b/bin/v-add-dns-domain
@@ -64,10 +64,14 @@ fi
 if [ -z "$(is_ip_format_valid $domain)" ]; then
     echo "Error: Invalid domain format. IP address detected as input." 
     exit 1
 fi
 
+if [ -n "$restart" ]; then 
+    is_format_valid 'restart'
+fi
+
 is_package_full 'DNS_DOMAINS'
 template=$(get_user_value '$DNS_TEMPLATE')
 is_dns_template_valid "$template"
 
 is_base_domain_owner "$domain"
diff --git a/bin/v-add-dns-record b/bin/v-add-dns-record
index f8b4cd93fd..9912bcb665 100755
--- a/bin/v-add-dns-record
+++ b/bin/v-add-dns-record
@@ -94,10 +94,13 @@ get_next_dnsrecord
 is_format_valid 'id'
 is_object_new "dns/$domain" 'ID' "$id"
 is_dns_fqnd "$rtype" "$dvalue"
 is_dns_nameserver_valid "$domain" "$rtype" "$dvalue"
 is_format_valid 'ttl'
+if [ -n "$restart" ]; then
+    is_format_valid 'restart'
+fi
 
 # Perform verification if read-only mode is enabled
 check_hestia_demo_mode
 
 #----------------------------------------------------------#
diff --git a/bin/v-add-fastcgi-cache b/bin/v-add-fastcgi-cache
index ee94e0829c..982bdbc1d1 100755
--- a/bin/v-add-fastcgi-cache
+++ b/bin/v-add-fastcgi-cache
@@ -29,11 +29,11 @@ source_conf "$HESTIA/conf/hestia.conf"
 #----------------------------------------------------------#
 #                    Verifications                         #
 #----------------------------------------------------------#
 
 check_args '2' "$#" 'USER DOMAIN [DURATION] [DEBUG] [RESTART]'
-is_format_valid 'user' 'domain'
+is_format_valid 'user' 'domain' 'restart'
 is_object_valid 'user' 'USER' "$user"
 is_object_unsuspended 'user' 'USER' "$user"
 is_object_valid 'web' 'DOMAIN' "$domain"
 is_object_unsuspended 'web' 'DOMAIN' "$domain"
 
diff --git a/bin/v-add-firewall-chain b/bin/v-add-firewall-chain
index da38decc45..cff298aa44 100755
--- a/bin/v-add-firewall-chain
+++ b/bin/v-add-firewall-chain
@@ -11,10 +11,11 @@
 #----------------------------------------------------------#
 
 # Argument definition
 chain=$(echo $1 | tr '[:lower:]' '[:upper:]')
 port=$2
+port_ext=$2
 protocol=${4-TCP}
 protocol=$(echo $protocol|tr '[:lower:]' '[:upper:]')
 
 # Defining absolute path to iptables
 iptables="/sbin/iptables"
@@ -38,11 +39,11 @@ source_conf "$HESTIA/conf/hestia.conf"
 #----------------------------------------------------------#
 #                    Verifications                         #
 #----------------------------------------------------------#
 
 check_args '1' "$#" 'CHAIN [PORT] [PROTOCOL]'
-is_format_valid 'chain'
+is_format_valid 'chain' 'port_ext' 'protocol'
 is_system_enabled "$FIREWALL_SYSTEM" 'FIREWALL_SYSTEM'
 
 # Perform verification if read-only mode is enabled
 check_hestia_demo_mode
 
diff --git a/bin/v-add-mail-domain b/bin/v-add-mail-domain
index ef0caa845a..bf282e0d59 100755
--- a/bin/v-add-mail-domain
+++ b/bin/v-add-mail-domain
@@ -48,11 +48,11 @@ domain_utf=$(idn -t --quiet -u "$domain_idn")
 #----------------------------------------------------------#
 #                    Verifications                         #
 #----------------------------------------------------------#
 
 check_args '2' "$#" 'USER DOMAIN [ANTISPAM] [ANTIVIRUS] [DKIM] [DKIM_SIZE]'
-is_format_valid 'user' 'domain' 'antispam' 'antivirus' 'dkim' 'dkim_size'
+is_format_valid 'user' 'domain' 'antispam' 'antivirus' 'dkim' 'dkim_size' 'restart'
 is_system_enabled "$MAIL_SYSTEM" 'MAIL_SYSTEM'
 is_object_valid 'user' 'USER' "$user"
 is_object_unsuspended 'user' 'USER' "$user"
 
 if [ "$($BIN/v-list-mail-domain $user $domain_utf plain |cut -f 1) " != "$domain" ]; then
diff --git a/bin/v-add-mail-domain-ssl b/bin/v-add-mail-domain-ssl
index 5307c76cf0..37bb48618a 100755
--- a/bin/v-add-mail-domain-ssl
+++ b/bin/v-add-mail-domain-ssl
@@ -61,10 +61,13 @@ is_object_value_empty 'mail' 'DOMAIN' "$domain" '$SSL'
 is_web_domain_cert_valid
 
 # Perform verification if read-only mode is enabled
 check_hestia_demo_mode
 
+if [ -n "$restart" ]; then 
+    is_format_valid "$restart"
+fi
 #----------------------------------------------------------#
 #                       Action                             #
 #----------------------------------------------------------#
 
 # Inherit web domain local ip address
diff --git a/bin/v-add-mail-domain-webmail b/bin/v-add-mail-domain-webmail
index a4542196a8..c4c00404bc 100755
--- a/bin/v-add-mail-domain-webmail
+++ b/bin/v-add-mail-domain-webmail
@@ -59,11 +59,11 @@ if [ -z "$webmail" ]; then
         webmail="$client"
     done
 fi
 
 check_args '2' "$#" 'USER DOMAIN [WEBMAIL] [RESTART]'
-is_format_valid 'user' 'domain'
+is_format_valid 'user' 'domain' 'restart'
 is_system_enabled "$WEB_SYSTEM" 'WEB_SYSTEM'
 is_system_enabled "$IMAP_SYSTEM" 'IMAP_SYSTEM'
 is_type_valid "$WEBMAIL_SYSTEM disabled" "$webmail"
 is_object_valid 'user' 'USER' "$user"
 is_object_unsuspended 'user' 'USER' "$user"
diff --git a/bin/v-add-remote-dns-domain b/bin/v-add-remote-dns-domain
index 45fbec62ee..aa64c1680d 100755
--- a/bin/v-add-remote-dns-domain
+++ b/bin/v-add-remote-dns-domain
@@ -30,10 +30,13 @@ source_conf "$HESTIA/conf/hestia.conf"
 #                    Verifications                         #
 #----------------------------------------------------------#
 
 check_args '2' "$#" 'USER DOMAIN [FLUSH]'
 is_format_valid 'user' 'domain'
+if [ -n "$flush" ]; then
+    is_type_valid "records yes no" "$flush" 
+fi
 is_system_enabled "$DNS_CLUSTER" 'DNS_CLUSTER'
 is_procces_running
 remote_dns_health_check
 
 # Perform verification if read-only mode is enabled
diff --git a/bin/v-add-remote-dns-host b/bin/v-add-remote-dns-host
index 0fd9d2a38b..ff74bd1680 100755
--- a/bin/v-add-remote-dns-host
+++ b/bin/v-add-remote-dns-host
@@ -44,11 +44,11 @@ source_conf "$HESTIA/conf/hestia.conf"
 #                    Verifications                         #
 #----------------------------------------------------------#
 
 args_usage='HOST PORT USER [PASSWORD] [TYPE] [DNS_USER]'
 check_args '3' "$#" "$args_usage"
-is_format_valid 'host' 'port' 'type' 'dns_user'
+is_format_valid 'host' 'port' 'dns_user'
 if [ -z "$password" ]; then
     is_format_valid 'hash'
 else
     is_format_valid 'user'
 fi
diff --git a/bin/v-change-user-ns b/bin/v-change-user-ns
index 4017c27358..f868f1207b 100755
--- a/bin/v-change-user-ns
+++ b/bin/v-change-user-ns
@@ -36,33 +36,35 @@ source_conf "$HESTIA/conf/hestia.conf"
 # Checking args
 check_args '3' "$#" 'USER NS1 NS2 [NS3] [NS4] [NS5] [NS6] [NS7] [NS8]'
 
 # Checking argument format
 is_format_valid 'user' 'ns1' 'ns2'
+
+ns="$ns1,$ns2"
 if [ -n "$ns3" ]; then
-    ns3=$(echo "$4" | sed -e 's/\.*$//g' -e 's/^\.*//g')
     is_format_valid 'ns3'
+    ns="$ns,$ns3"
 fi
 if [ -n "$ns4" ]; then
-    ns4=$(echo "$5" | sed -e 's/\.*$//g' -e 's/^\.*//g')
     is_format_valid 'ns4'
+    ns="$ns,$ns4"
 fi
 if [ -n "$ns5" ]; then
-    ns5=$(echo "$6" | sed -e 's/\.*$//g' -e 's/^\.*//g')
     is_format_valid 'ns5'
+    ns="$ns,$ns5"
 fi
 if [ -n "$ns6" ]; then
-    ns6=$(echo "$7" | sed -e 's/\.*$//g' -e 's/^\.*//g')
     is_format_valid 'ns6'
+    ns="$ns,$ns6"
 fi
 if [ -n "$ns7" ]; then
-    ns7=$(echo "$8" | sed -e 's/\.*$//g' -e 's/^\.*//g')
     is_format_valid 'ns7'
+    ns="$ns,$ns7"
 fi
 if [ -n "$ns8" ]; then
-    ns8=$(echo "$9" | sed -e 's/\.*$//g' -e 's/^\.*//g')
     is_format_valid 'ns8'
+    ns="$ns,$ns8"
 fi
 is_object_valid 'user' 'USER' "$user"
 is_object_unsuspended 'user' 'USER' "$user"
 
 # Perform verification if read-only mode is enabled
@@ -70,14 +72,10 @@ check_hestia_demo_mode
 
 #----------------------------------------------------------#
 #                       Action                             #
 #----------------------------------------------------------#
 
-# Merging values
-ns="$ns1,$ns2,$ns3,$ns4,$ns5,$ns6,$ns7,$ns8"
-ns=$(echo "$ns" | sed -e "s/,,//g" -e "s/,$//")
-
 # Changing ns values
 update_user_value "$user" '$NS' "$ns"
 
 #----------------------------------------------------------#
 #                       Hestia                             #
diff --git a/bin/v-change-user-theme b/bin/v-change-user-theme
index 85ad40407a..32165fb9ca 100755
--- a/bin/v-change-user-theme
+++ b/bin/v-change-user-theme
@@ -25,11 +25,11 @@ source_conf "$HESTIA/conf/hestia.conf"
 
 #----------------------------------------------------------#
 #                    Verifications                         #
 #----------------------------------------------------------#
 
-is_format_valid 'user'
+is_format_valid 'user' 'theme'
 is_common_format_valid "$theme" "theme"
 is_object_valid 'user' 'USER' "$user"
 
 is_object_unsuspended 'user' 'USER' "$user"
 
diff --git a/bin/v-change-web-domain-name b/bin/v-change-web-domain-name
index d6f01e2d56..c954d8cfa2 100755
--- a/bin/v-change-web-domain-name
+++ b/bin/v-change-web-domain-name
@@ -38,10 +38,11 @@ format_domain_idn
 #                    Verifications                         #
 #----------------------------------------------------------#
 
 check_args '3' "$#" 'USER DOMAIN NEW_DOMAIN [RESTART]'
 is_format_valid 'user' 'domain'
+is_domain_format_valid "$new_domain"
 is_system_enabled "$WEB_SYSTEM" 'WEB_SYSTEM'
 is_object_valid 'user' 'USER' "$user"
 is_object_unsuspended 'user' 'USER' "$user"
 is_object_valid 'web' 'DOMAIN' "$domain"
 is_object_unsuspended 'web' 'DOMAIN' "$domain"
diff --git a/bin/v-check-access-key b/bin/v-check-access-key
index e208f1cb01..9decfd39fd 100755
--- a/bin/v-check-access-key
+++ b/bin/v-check-access-key
@@ -76,11 +76,11 @@ abort_missmatch() {
 
 # Add a callback to intercept invalid "check_result" results
 CHECK_RESULT_CALLBACK="abort_missmatch"
 
 check_args '3' "$#" 'ACCESS_KEY_ID SECRET_ACCESS_KEY COMMAND [IP] [FORMAT]'
-is_format_valid 'access_key_id'
+is_format_valid 'access_key_id' 'ip' 'command'
 is_object_valid 'key' 'KEY' "$access_key_id"
 is_format_valid 'secret_access_key'
 check_access_key_secret "$access_key_id" "$secret_access_key" user
 check_access_key_cmd "$access_key_id" "$hst_command" user_arg_pos
 
diff --git a/bin/v-delete-database-temp-user b/bin/v-delete-database-temp-user
index b94a371ee2..df622efbc3 100755
--- a/bin/v-delete-database-temp-user
+++ b/bin/v-delete-database-temp-user
@@ -31,11 +31,11 @@ source_conf "$HESTIA/conf/hestia.conf"
 #----------------------------------------------------------#
 #                    Verifications                         #
 #----------------------------------------------------------#
 
 check_args '3' "$#" 'USER DATABASE DBUSER [TYPE] [HOST]'
-is_format_valid 'user' 'dbuser'
+is_format_valid 'user' 'database' 'dbuser'
 is_system_enabled "$DB_SYSTEM" 'DB_SYSTEM'
 is_object_valid 'user' 'USER' "$user"
 is_object_unsuspended 'user' 'USER' "$user"
 is_object_valid 'db' 'DB' "$database"
 is_object_unsuspended 'db' 'DB' "$database"
diff --git a/bin/v-delete-dns-on-web-alias b/bin/v-delete-dns-on-web-alias
index 5f8c95b774..ca5784a3fa 100755
--- a/bin/v-delete-dns-on-web-alias
+++ b/bin/v-delete-dns-on-web-alias
@@ -11,10 +11,11 @@
 #----------------------------------------------------------#
 
 # Argument definition
 user=$1
 domain=$2
+alias=$3
 domain_idn=$2
 dom_alias=$(idn -t --quiet -u "$3" )
 dom_alias=$(echo $dom_alias |sed -e 's/\.*$//g' -e 's/^\.*//g')
 dom_alias=$(echo $dom_alias |tr '[:upper:]' '[:lower:]')
 dom_alias_idn=$(idn -t --quiet -a "$dom_alias" )
@@ -41,11 +42,11 @@ check_hestia_demo_mode
 #----------------------------------------------------------#
 #                    Verifications                         #
 #----------------------------------------------------------#
 
 check_args '3' "$#" 'USER DOMAIN ALIAS [RESTART]'
-is_format_valid 'user' 'domain'
+is_format_valid 'user' 'domain' 'alias' 'restart'
 is_system_enabled "$WEB_SYSTEM" 'WEB_SYSTEM'
 is_system_enabled "$DNS_SYSTEM" 'DNS_SYSTEM'
 is_object_valid 'user' 'USER' "$user"
 is_object_valid 'web' 'DOMAIN' "$domain"
 
diff --git a/bin/v-delete-mail-account-forward b/bin/v-delete-mail-account-forward
index dede857232..939b2ee92c 100755
--- a/bin/v-delete-mail-account-forward
+++ b/bin/v-delete-mail-account-forward
@@ -34,10 +34,11 @@ format_domain_idn
 #----------------------------------------------------------#
 #                    Verifications                         #
 #----------------------------------------------------------#
 
 check_args '4' "$#" 'USER DOMAIN ACCOUNT FORWARD'
+is_format_valid 'user' 'domain' 'account'
 if [ "$forward"  != ':blackhole:' ]; then
     is_format_valid 'forward'
 fi
 is_system_enabled "$MAIL_SYSTEM" 'MAIL_SYSTEM'
 is_object_valid 'user' 'USER' "$user"
diff --git a/bin/v-delete-user-notification b/bin/v-delete-user-notification
index 4a1ef9fbb6..6b7e1b0a05 100755
--- a/bin/v-delete-user-notification
+++ b/bin/v-delete-user-notification
@@ -10,11 +10,11 @@
 #                Variables & Functions                     #
 #----------------------------------------------------------#
 
 # Argument definition
 user=$1
-nid=$2
+id=$2
 
 # Includes
 # shellcheck source=/etc/hestiacp/hestia.conf
 source /etc/hestiacp/hestia.conf
 # shellcheck source=/usr/local/hestia/func/main.sh
@@ -25,22 +25,22 @@ source_conf "$HESTIA/conf/hestia.conf"
 #----------------------------------------------------------#
 #                    Verifications                         #
 #----------------------------------------------------------#
 
 check_args '2' "$#" 'USER NOTIFICATION'
-is_format_valid 'user' 'nid'
+is_format_valid 'user' 'id'
 is_object_valid 'user' 'USER' "$user"
 
 # Perform verification if read-only mode is enabled
 check_hestia_demo_mode
 
 #----------------------------------------------------------#
 #                       Action                             #
 #----------------------------------------------------------#
 
 # Deleting notification
-sed -i "/NID='$nid' /d" $USER_DATA/notifications.conf 2>/dev/null
+sed -i "/NID='$id' /d" $USER_DATA/notifications.conf 2>/dev/null
 
 # Checking last notification
 if [ -e "$USER_DATA/notifications.conf" ]; then
     if [ -z "$(grep NID= $USER_DATA/notifications.conf)" ]; then
         notice='no'
diff --git a/bin/v-delete-user-ssh-key b/bin/v-delete-user-ssh-key
index 54d00d8857..ec172e1fb6 100755
--- a/bin/v-delete-user-ssh-key
+++ b/bin/v-delete-user-ssh-key
@@ -27,10 +27,11 @@ source_conf "$HESTIA/conf/hestia.conf"
 #                    Verifications                         #
 #----------------------------------------------------------#
 
 check_args '2' "$#" 'USER KEYID'
 is_format_valid 'user'
+is_no_new_line_format "$key_id"
 is_object_valid 'user' 'USER' "$user"
 
 source "$USER_DATA/user.conf"
 
 AUTHKEY_FILE="$HOMEDIR/$user/.ssh/authorized_keys"
diff --git a/bin/v-generate-ssl-cert b/bin/v-generate-ssl-cert
index 206ed1592f..2abb56338f 100755
--- a/bin/v-generate-ssl-cert
+++ b/bin/v-generate-ssl-cert
@@ -70,10 +70,15 @@ fi
 #----------------------------------------------------------#
 
 args_usage='DOMAIN EMAIL COUNTRY STATE CITY ORG UNIT [ALIASES] [FORMAT]'
 check_args '7' "$#" "$args_usage"
 is_format_valid 'domain' 'aliases' 'format' 'email'
+is_common_format_valid $country "country"
+is_common_format_valid $state "state"
+is_common_format_valid $org "org"
+is_common_format_valid $unit "unit"
+
 
 release="$(lsb_release -s -r)"
 
 if [ -z "$email" ] && [ "$release" = "18.04" ]; then 
     echo "Email address is required";
diff --git a/bin/v-get-user-salt b/bin/v-get-user-salt
index 8124ca6f80..b46373d943 100755
--- a/bin/v-get-user-salt
+++ b/bin/v-get-user-salt
@@ -62,11 +62,11 @@ csv_list() {
 #                    Verifications                         #
 #----------------------------------------------------------#
 
 
 check_args '1' "$#" 'USER [IP] [SALT]'
-is_format_valid 'user'
+is_format_valid 'user' 'ip'
 
 # Checking user
 if [ ! -d "$HESTIA/data/users/$user" ]; then
     echo "Error: password missmatch"
     echo "$date $time $user $ip failed to login" >> $HESTIA/log/auth.log
diff --git a/bin/v-log-action b/bin/v-log-action
index 82d3ae0f77..78b23b88d8 100755
--- a/bin/v-log-action
+++ b/bin/v-log-action
@@ -29,10 +29,12 @@ source_conf "$HESTIA/conf/hestia.conf"
 user=$1
 event_level=$2
 export event_category=$3
 event_details=$4
 
+is_common_format_valid "$event_level" "event level"
+
 # Validate event type input
 if [ "$event_level" != "Info" ] && [ "$event_level" != "Warning" ] && [ "$event_level" != "Error" ]; then 
     echo "Error: Invalid event type specified."
     exit 1
 fi
@@ -45,10 +47,11 @@ if [ "$user" = "system" ] || [ "$user" = "System" ]; then
     user="system"
 fi
 
 check_args '4' "$#" 'USER TYPE CATEGORY DETAILS'
 if [ "$user" != "system" ]; then
+    is_format_valid 'user'
     is_object_valid 'user' 'USER' "$user"
 fi
 
 log_history "$event_details" '' "$user"
 
diff --git a/bin/v-log-user-logout b/bin/v-log-user-logout
index 1cc9026d7e..2713748e6c 100755
--- a/bin/v-log-user-logout
+++ b/bin/v-log-user-logout
@@ -22,10 +22,11 @@ source_conf "$HESTIA/conf/hestia.conf"
 #                    Verifications                         #
 #----------------------------------------------------------#
 
 check_args '2' "$#" 'USER SESSION_ID'
 is_format_valid 'user'
+is_common_format_valid "$session_id" "Session ID"
 is_object_valid 'user' 'USER' "$user"
 
 if [ ! -f "$USER_DATA/auth.log" ]; then
     touch "$USER_DATA/auth.log"
 fi
diff --git a/bin/v-purge-nginx-cache b/bin/v-purge-nginx-cache
index a4294cc798..4196cb3045 100755
--- a/bin/v-purge-nginx-cache
+++ b/bin/v-purge-nginx-cache
@@ -11,10 +11,11 @@
 #----------------------------------------------------------#
 
 # Argument definition
 user=$1
 domain=$2
+rstart=$3
 
 # Includes
 # shellcheck source=/etc/hestiacp/hestia.conf
 source /etc/hestiacp/hestia.conf
 # shellcheck source=/usr/local/hestia/func/main.sh
@@ -26,12 +27,12 @@ source_conf "$HESTIA/conf/hestia.conf"
 
 #----------------------------------------------------------#
 #                    Verifications                         #
 #----------------------------------------------------------#
 
-check_args '2' "$#" 'USER DOMAIN'
-is_format_valid 'user' 'domain'
+check_args '2' "$#" 'USER DOMAIN [RESTART]'
+is_format_valid 'user' 'domain' 'restart'
 is_object_valid 'user' 'USER' "$user"
 is_object_unsuspended 'user' 'USER' "$user"
 is_object_valid 'web' 'DOMAIN' "$domain"
 is_object_unsuspended 'web' 'DOMAIN' "$domain"
 is_object_valid 'web' 'DOMAIN' "$domain" "$FASTCGI_CACHE"
diff --git a/bin/v-schedule-letsencrypt-domain b/bin/v-schedule-letsencrypt-domain
index 8420e5f0f4..05229e8c7c 100755
--- a/bin/v-schedule-letsencrypt-domain
+++ b/bin/v-schedule-letsencrypt-domain
@@ -28,11 +28,11 @@ source_conf "$HESTIA/conf/hestia.conf"
 #----------------------------------------------------------#
 #                    Verifications                         #
 #----------------------------------------------------------#
 
 check_args '2' "$#" 'USER DOMAIN [ALIASES]'
-is_format_valid 'user' 'domain'
+is_format_valid 'user' 'domain' 'aliases'
 is_system_enabled "$WEB_SYSTEM" 'WEB_SYSTEM'
 is_system_enabled "$WEB_SSL" 'SSL_SUPPORT'
 is_object_valid 'user' 'USER' "$user"
 is_object_unsuspended 'user' 'USER' "$user"
 is_object_valid 'web' 'DOMAIN' "$domain"
diff --git a/bin/v-update-host-certificate b/bin/v-update-host-certificate
index 581838ac15..d15f53cd76 100755
--- a/bin/v-update-host-certificate
+++ b/bin/v-update-host-certificate
@@ -34,10 +34,11 @@ source_conf "$HESTIA/conf/hestia.conf"
 #                    Verifications                         #
 #----------------------------------------------------------#
 
 check_args '1' "$#" '[USER] [HOSTNAME]'
 is_format_valid 'user'
+is_domain_format_valid "$hostname" "hostname"
 is_system_enabled "$WEB_SYSTEM" 'WEB_SYSTEM'
 is_system_enabled "$WEB_SSL" 'SSL_SUPPORT'
 is_object_valid 'user' 'USER' "$user"
 is_object_unsuspended 'user' 'USER' "$user"
 is_object_valid 'web' 'DOMAIN' "$hostname"
diff --git a/bin/v-update-user-backup-exclusions b/bin/v-update-user-backup-exclusions
index a6786e45cf..62c00d81ec 100755
--- a/bin/v-update-user-backup-exclusions
+++ b/bin/v-update-user-backup-exclusions
@@ -38,11 +38,11 @@ is_file_valid() {
 #----------------------------------------------------------#
 #                    Verifications                         #
 #----------------------------------------------------------#
 
 check_args '2' "$#" 'USER FILE'
-is_format_valid 'user' 'vfile'
+is_format_valid 'user'
 is_object_valid 'user' 'USER' "$user"
 is_file_available
 is_file_valid
 
 # Perform verification if read-only mode is enabled
diff --git a/func/main.sh b/func/main.sh
index 4a9c5ca001..52163c2d1f 100644
--- a/func/main.sh
+++ b/func/main.sh
@@ -684,17 +684,17 @@ is_user_format_valid() {
         fi
     fi
 }
 
 # Domain format validator
-# removed "" around  \.\. and $(printf '\t'): SC2076: Don't quote right-hand side of =~, it'll match literally rather than as a regex. And we need regex match!
 is_domain_format_valid() {
     object_name=${2-domain}
     exclude="[!|@|#|$|^|&|*|(|)|+|=|{|}|:|,|<|>|?|_|/|\|\"|'|;|%|\`| ]"
     if [[ $1 =~ $exclude ]] || [[ $1 =~ ^[0-9]+$ ]] || [[ $1 =~ \.\. ]] || [[ $1 =~ $(printf '\t') ]] ||  [[ "$1" = "www" ]]; then
         check_result "$E_INVALID" "invalid $object_name format :: $1"
     fi
+    is_no_new_line_format "$1";
 }
 
 # Alias forman validator
 is_alias_format_valid() {
     for object in ${1//,/ }; do
@@ -827,10 +827,11 @@ is_ip46_format_valid() {
 is_extention_format_valid() {
     exclude="[!|#|$|^|&|(|)|+|=|{|}|:|@|<|>|?|/|\|\"|'|;|%|\`| ]"
     if [[ "$1" =~ $exclude ]]; then
         check_result "$E_INVALID" "invalid proxy extention format :: $1"
     fi
+    is_no_new_line_format "$1";
 }
 
 # Number format validator
 is_number_format_valid() {
     object_name=${2-number}
@@ -883,25 +884,35 @@ is_common_format_valid() {
            check_result "$E_INVALID" "invalid $2 format :: $1"
     fi
     if [[ $(echo -n "$1" | grep -c '\_\_') -gt 0 ]]; then
            check_result "$E_INVALID" "invalid $2 format :: $1"
     fi
+    is_no_new_line_format "$1";
+}
+
+is_no_new_line_format() {
+    test=$(echo $1 | sed -e 's/\.*$//g' -e 's/^\.*//g');
+    if [[ "$test" != "$1" ]]; then
+      check_result "$E_INVALID" "invalid value :: $1"
+    fi
 }
 
 is_string_format_valid() {
   exclude="[!|#|$|^|&|(|)|+|=|{|}|:|<|>|?|/|\|\"|'|;|%|\`]"
   if [[ "$1" =~ $exclude ]]; then
       check_result "$E_INVALID" "invalid $2 format :: $1"
   fi
+  is_no_new_line_format "$1";
 }
 
 # Database format validator
 is_database_format_valid() {
     exclude="[!|@|#|$|^|&|*|(|)|+|=|{|}|:|,|<|>|?|/|\|\"|'|;|%|\`| ]"
     if [[ "$1" =~ $exclude ]] || [ 64 -le ${#1} ]; then
         check_result "$E_INVALID" "invalid $2 format :: $1"
     fi
+    is_no_new_line_format "$1";
 }
 
 # Date format validator
 is_date_format_valid() {
     if ! [[ "$1" =~ ^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$ ]]; then
@@ -916,10 +927,11 @@ is_dbuser_format_valid() {
         check_result "$E_INVALID" "mysql username can be up to 32 characters long"
     fi
     if [[ "$1" =~ $exclude ]]; then
         check_result "$E_INVALID" "invalid $2 format :: $1"
     fi
+    is_no_new_line_format "$1"
 }
 
 # DNS record type validator
 is_dns_type_format_valid() {
     known_dnstype='A,AAAA,NS,CNAME,MX,TXT,SRV,DNSKEY,KEY,IPSECKEY,PTR,SPF,TLSA,CAA'
@@ -938,11 +950,11 @@ is_dns_record_format_valid() {
     fi
     if [ "$rtype" = 'MX' ]; then
         is_domain_format_valid "${1::-1}" 'mx_record'
         is_int_format_valid "$priority" 'priority_record'
     fi
-
+    is_no_new_line_format "$1";
 }
 
 # Email format validator
 is_email_format_valid() {
     if [[ ! "$1" =~ ^[A-Za-z0-9._%+-]+@[[:alnum:].-]+\.[A-Za-z]{2,63}$ ]] ; then
@@ -1064,11 +1076,11 @@ is_object_format_valid() {
     fi
 }
 
 # Role validator
 is_role_valid (){
-    if ! [[ "$1" =~ ^admin|user$ ]]; then
+    if ! [[ "$1" =~ ^admin$|^user$ ]]; then
         check_result "$E_INVALID" "invalid $2 format :: $1"
     fi
 }
 
 # Password validator
@@ -1110,29 +1122,33 @@ is_format_valid() {
                 access_key_id)  is_access_key_id_format_valid "$arg" "$arg_name";;
                 account)        is_user_format_valid "$arg" "$arg_name";;
                 action)         is_fw_action_format_valid "$arg";;
                 active)         is_boolean_format_valid "$arg" 'active' ;;
                 aliases)        is_alias_format_valid "$arg" ;;
+                alias)          is_alias_format_valid "$arg" ;;        
                 antispam)       is_boolean_format_valid "$arg" 'antispam' ;;
                 antivirus)      is_boolean_format_valid "$arg" 'antivirus' ;;
                 autoreply)      is_autoreply_format_valid "$arg" ;;
                 backup)         is_object_format_valid "$arg" 'backup' ;;
                 charset)        is_object_format_valid "$arg" "$arg_name" ;;
                 charsets)       is_common_format_valid "$arg" 'charsets' ;;
+                chain)          is_object_format_valid "$arg" 'chain' ;;
                 comment)        is_object_format_valid "$arg" 'comment' ;;
                 database)       is_database_format_valid "$arg" 'database';;
                 day)            is_cron_format_valid "$arg" $arg_name ;;
                 dbpass)         is_password_format_valid "$arg" ;;
                 dbuser)         is_dbuser_format_valid "$arg" 'dbuser';;
                 dkim)           is_boolean_format_valid "$arg" 'dkim' ;;
                 dkim_size)      is_int_format_valid "$arg" ;;
                 domain)         is_domain_format_valid "$arg" ;;
+                dom_alias)      is_alias_format_valid "$arg" ;;
                 dvalue)         is_dns_record_format_valid "$arg";;
                 email)          is_email_format_valid "$arg" ;;
                 email_forward)  is_email_format_valid "$arg" ;;
                 exp)            is_date_format_valid "$arg" ;;
                 extentions)     is_common_format_valid "$arg" 'extentions' ;;
+                format)         is_type_valid 'plain json shell csv' "$arg" ;;
                 ftp_password)   is_password_format_valid "$arg" ;;
                 ftp_user)       is_user_format_valid "$arg" "$arg_name" ;;
                 hash)           is_hash_format_valid "$arg" "$arg_name" ;;
                 host)           is_object_format_valid "$arg" "$arg_name" ;;
                 hour)           is_cron_format_valid "$arg" $arg_name ;;
@@ -1179,22 +1195,38 @@ is_format_valid() {
                 service)        is_service_format_valid "$arg" "$arg_name" ;;
                 secret_access_key) is_secret_access_key_format_valid "$arg" "$arg_name" ;;
                 soa)            is_domain_format_valid "$arg" 'SOA' ;;
                 #missing command: is_format_valid_shell
                 shell)          is_format_valid_shell "$arg" ;;
+                ssl_dir)        is_folder_exists "$arg" "$arg_name" ;;
                 stats_pass)     is_password_format_valid "$arg" ;;
                 stats_user)     is_user_format_valid "$arg" "$arg_name" ;;
                 template)       is_object_format_valid "$arg" "$arg_name" ;;
+                theme)          is_common_format_valid "$arg" "$arg_name" ;;
                 ttl)            is_int_format_valid "$arg" 'ttl';;
                 user)           is_user_format_valid "$arg" $arg_name;;
                 wday)           is_cron_format_valid "$arg" $arg_name ;;
                 value)          is_common_format_valid "$arg" $arg_name;;
             esac
         fi
     done
 }
 
+is_folder_exists () {
+  if [ ! -d "$1" ]; then 
+    check_result "$E_NOTEXIST" "folder $1 does not exist"
+  fi
+}
+
+is_command_valid_format () {
+  if [[ ! "$1" =~ ^v-[[:alnum:]][-|\.|_[:alnum:]]{0,64}[[:alnum:]]$ ]]; then 
+    check_result "$E_INVALID" "Invalid command format"
+  fi
+  if [[ -n $( echo "$1" | grep -e '\-\-' ) ]]; then 
+    check_result "$E_INVALID" "Invalid command format"
+  fi
+}
 # Check access_key_id name
 # Don't work with legacy key format
 is_access_key_id_format_valid() {
     local hash="$1"
 
@@ -1493,10 +1525,11 @@ source_conf(){
 format_no_quotes() {
     exclude="['|\"]"
     if [[ "$1" =~ $exclude ]]; then
        check_result "$E_INVALID" "Invalid $2 contains qoutes (\" or ') :: $1"
     fi
+    is_no_new_line_format "$1"
 }
 
 is_username_format_valid(){
     if [[ ! "$1" =~ ^[A-Za-z0-9._%+-]+@[[:alnum:].-]+\.[A-Za-z]{2,63}$ ]] ; then
       is_string_format_valid "$1" "$2"
diff --git a/test/checks.bats b/test/checks.bats
new file mode 100644
index 0000000000..e3789a6ce9
--- /dev/null
+++ b/test/checks.bats
@@ -0,0 +1,349 @@
+#!/usr/bin/env bats
+
+if [ "${PATH#*/usr/local/hestia/bin*}" = "$PATH" ]; then
+    . /etc/profile.d/hestia.sh
+fi
+
+load 'test_helper/bats-support/load'
+load 'test_helper/bats-assert/load'
+load 'test_helper/bats-file/load'
+
+function random() {
+head /dev/urandom | tr -dc 0-9 | head -c$1
+}
+
+function setup() {
+    # echo "# Setup_file" > &3
+    if [ $BATS_TEST_NUMBER = 1 ]; then
+        echo 'user=test-5285' > /tmp/hestia-test-env.sh
+        echo 'user2=test-5286' >> /tmp/hestia-test-env.sh
+        echo 'userbk=testbk-5285' >> /tmp/hestia-test-env.sh
+        echo 'userpass1=test-5285' >> /tmp/hestia-test-env.sh
+        echo 'userpass2=t3st-p4ssw0rd' >> /tmp/hestia-test-env.sh
+        echo 'HESTIA=/usr/local/hestia' >> /tmp/hestia-test-env.sh
+        echo 'domain=test-5285.hestiacp.com' >> /tmp/hestia-test-env.sh
+        echo 'domainuk=test-5285.hestiacp.com.uk' >> /tmp/hestia-test-env.sh
+        echo 'rootdomain=testhestiacp.com' >> /tmp/hestia-test-env.sh
+        echo 'subdomain=cdn.testhestiacp.com' >> /tmp/hestia-test-env.sh
+        echo 'database=test-5285_database' >> /tmp/hestia-test-env.sh
+        echo 'dbuser=test-5285_dbuser' >> /tmp/hestia-test-env.sh
+    fi
+    
+    source /tmp/hestia-test-env.sh
+    source $HESTIA/func/main.sh
+    source $HESTIA/conf/hestia.conf
+    source $HESTIA/func/ip.sh
+}
+
+@test "is_access_key_id_format_valid valid" {
+    run is_access_key_id_format_valid 'M0ocDoIKbsoXSqtk1mgc' "key"
+    assert_success
+}
+@test "is_access_key_id_format_valid short" {
+    run is_access_key_id_format_valid 'M0ocDoIKbsoXSqtk1mg' "key"
+    assert_failure $E_INVALID
+}
+@test "is_access_key_id_format_valid long" {
+    run is_access_key_id_format_valid 'M0ocDoIKbsoXSqtk1mgca' "key"
+    assert_failure $E_INVALID
+}
+@test "is_access_key_id_format_valid non alpha" {
+    run is_access_key_id_format_valid 'M0ocDoIKbsoX$qtk1mgc' "key"
+    assert_failure $E_INVALID
+}
+
+@test "is_access_key_id_format_valid LHF" {
+    run is_access_key_id_format_valid 'c
+1eshutdown
+r' "key"
+    assert_failure $E_INVALID
+}
+
+@test "is_user_format_valid valid" {
+    run is_user_format_valid 'hxh54SKbALne4s69VsqJRMbMd8Br' "key"
+    assert_success
+}
+@test "is_user_format_valid short" {
+    run is_user_format_valid 'hxh54SKbALne4s69VsqJR' "key"
+    assert_success
+}
+@test "is_user_format_valid long" {
+    run is_user_format_valid 'hxh54SKbALne4s69VsqJRMbMd8Braaa' "key"
+    assert_failure $E_INVALID
+}
+@test "is_user_format_valid dash" {
+    run is_user_format_valid 'hxh54SKbALne4-s6-VsqJRMbMd8Br' "key"
+    assert_success
+}
+
+@test "is_user_format_valid dash repeat" {
+    run is_user_format_valid 'hxh54SKbALne4s6--VsqJRMbMd8Br' "key"
+    assert_success
+}
+@test "is_user_format_valid dash start" {
+    run is_user_format_valid '-hxh54SKbALne4s6VsqJRMbMd8Br' "key"
+    assert_failure $E_INVALID
+}
+@test "is_user_format_valid dash end" {
+    run is_user_format_valid 'hxh54SKbALne4s6VsqJRMbMd8Br-' "key"
+    assert_failure $E_INVALID
+}
+@test "is_user_format_valid LHF" {
+    run is_user_format_valid 'M0ocDoIK
+    soXSqtk1mgc' "key"
+    assert_failure $E_INVALID
+}
+
+@test "is_fw_action_format_valid ACCEPT" {
+    run is_fw_action_format_valid 'ACCEPT' "key"
+    assert_success
+}
+@test "is_fw_action_format_valid DROP" {
+    run is_fw_action_format_valid 'DROP' "key"
+    assert_success
+}
+@test "is_fw_action_format_valid TEST" {
+    run is_fw_action_format_valid 'TEST' "key"
+    assert_failure $E_INVALID
+}
+@test "is_fw_action_format_valid LHF" {
+    run is_fw_protocol_format_valid 'M0ocDoIK
+    soXSqtk1mgc' "key"
+    assert_failure $E_INVALID
+}
+
+@test "is_fw_protocol_format_valid ICMP" {
+    run is_fw_protocol_format_valid 'ICMP' "key"
+    assert_success
+}
+
+@test "is_fw_protocol_format_valid UDP" {
+    run is_fw_protocol_format_valid 'UDP' "key"
+    assert_success
+}
+@test "is_fw_protocol_format_valid TCP" {
+    run is_fw_protocol_format_valid 'TCP' "key"
+    assert_success
+}
+@test "is_fw_protocol_format_valid TEST" {
+    run is_fw_protocol_format_valid 'TEST' "key"
+    assert_failure $E_INVALID
+}
+
+
+@test "is_domain_format_valid success" {
+     run is_domain_format_valid 'hestiacp.com' "key"
+    assert_success
+}
+
+@test "is_domain_format_valid www" {
+     run is_domain_format_valid 'www' "key"
+    assert_failure $E_INVALID
+}
+@test "is_domain_format_valid number" {
+     run is_domain_format_valid '12345' "key"
+    assert_failure $E_INVALID
+}
+
+@test "is_domain_format_valid .." {
+     run is_domain_format_valid '..' "key"
+    assert_failure $E_INVALID
+}
+@test "is_domain_format_valid LF." {
+     run is_domain_format_valid 'c
+1eshutdown
+r' "key"
+    assert_failure $E_INVALID
+}
+
+@test "is_alias_format_valid success" {
+     run is_domain_format_valid 'hestiacp.com' "key"
+    assert_success
+}
+
+@test "is_alias_format_valid www" {
+     run is_domain_format_valid 'www' "key"
+    assert_failure $E_INVALID
+}
+@test "is_alias_format_valid number" {
+     run is_domain_format_valid '12345' "key"
+    assert_failure $E_INVALID
+}
+
+@test "is_alias_format_valid .." {
+     run is_domain_format_valid '..' "key"
+    assert_failure $E_INVALID
+}
+@test "is_alias_format_valid LF." {
+     run is_domain_format_valid 'c
+1eshutdown
+r' "key"
+    assert_failure $E_INVALID
+}
+
+@test "is_extention_format_valid test" {
+     run is_extention_format_valid 'c
+1eshutdown
+r' "key"
+    assert_failure $E_INVALID
+}
+
+@test "is_string_format_valid test" {
+     run is_string_format_valid 'c
+1eshutdown
+r' "key"
+    assert_failure $E_INVALID
+}
+
+@test "is_database_format_valid test" {
+     run is_database_format_valid 'c
+1eshutdown
+r' "key"
+    assert_failure $E_INVALID
+}
+
+@test "is_date_format_valid test" {
+     run is_date_format_valid 'c
+1eshutdown
+r' "key"
+    assert_failure $E_INVALID
+}
+
+@test "is_dbuser_format_valid test" {
+     run is_dbuser_format_valid 'c
+1eshutdown
+r' "key"
+    assert_failure $E_INVALID
+}
+
+@test "is_dns_type_format_valid test" {
+     run is_dns_type_format_valid 'c
+1eshutdown
+r' "key"
+    assert_failure $E_INVALID
+}
+
+@test "is_dns_record_format_valid test" {
+     run is_dns_record_format_valid 'c
+1eshutdown
+r' "key"
+    assert_failure $E_INVALID
+}
+
+@test "is_email_format_valid test" {
+     run is_email_format_valid 'c
+1eshutdown
+r' "key"
+    assert_failure $E_INVALID
+}
+
+@test "is_fw_port_format_valid test" {
+     run is_fw_port_format_valid 'c
+1eshutdown
+r' "key"
+    assert_failure $E_INVALID
+}
+
+@test "is_int_format_valid test" {
+     run is_int_format_valid 'c
+1eshutdown
+r' "key"
+    assert_failure $E_INVALID
+}
+
+@test "is_interface_format_valid test" {
+     run is_interface_format_valid 'c
+1eshutdown
+r' "key"
+    assert_failure $E_INVALID
+}
+
+@test "is_ip_status_format_valid test" {
+     run is_ip_status_format_valid 'c
+1eshutdown
+r' "key"
+    assert_failure $E_INVALID
+}
+
+@test "is_cron_format_valid test" {
+     run is_cron_format_valid 'c
+1eshutdown
+r' "key"
+    assert_failure $E_INVALID
+}
+
+@test "is_name_format_valid test" {
+     run is_name_format_valid 'c
+1eshutdown
+r' "key"
+    assert_failure $E_INVALID
+}
+
+
+@test "is_role_valid test" {
+     run is_role_valid 'c
+1eshutdown
+r' "key"
+    assert_failure $E_INVALID
+}
+
+@test "is_object_format_valid test" {
+     run is_object_format_valid 'c
+1eshutdown
+r' "key"
+    assert_failure $E_INVALID
+}
+
+
+@test "is_common_format_valid test" {
+     run is_common_format_valid 'c
+1eshutdown
+r' "key"
+    assert_failure $E_INVALID
+}
+
+@test "format_no_quotes test" {
+     run format_no_quotes 'c
+1eshutdown
+r' "key"
+    assert_failure $E_INVALID
+}
+
+@test "is_type_valid" {
+    run is_type_valid 'c
+    1eshutdown
+    r' "test,key"
+    assert_failure $E_INVALID
+}
+
+@test "is_command_valid_format v-list-users" {
+    run is_command_valid_format 'v-list-users'
+    assert_success
+}
+
+@test "is_command_valid_format v-list--users (Fail)" {
+    run is_command_valid_format 'v-list--users'
+    assert_failure $E_INVALID
+}
+
+@test "is_command_valid_format h-list-users (Fail)" {
+    run is_command_valid_format 'h-list-users'
+    assert_failure $E_INVALID
+}
+
+@test "is_command_valid_format list-users (Fail)" {
+    run is_command_valid_format 'list-users'
+    assert_failure $E_INVALID
+}
+
+@test "is_command_valid_format vlist-users (Fail)" {
+    run is_command_valid_format 'vlist-users'
+    assert_failure $E_INVALID
+}
+
+@test "is_command_valid_format LF (Fail)" {
+     run is_command_valid_format 'v-
+1eshutdown
+r' "key"
+    assert_failure $E_INVALID
+}
\ No newline at end of file
diff --git a/web/inc/main.php b/web/inc/main.php
index 128d2a93f9..036fa77180 100644
--- a/web/inc/main.php
+++ b/web/inc/main.php
@@ -62,11 +62,11 @@ if (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) {
 if (!isset($_SESSION['user_combined_ip'])) {
     $_SESSION['user_combined_ip'] = $user_combined_ip;
 }
 
 // Checking user to use session from the same IP he has been logged in
-if ($_SESSION['user_combined_ip'] != $user_combined_ip && $_SERVER['REMOTE_ADDR'] != '127.0.0.1') {
+if ($_SESSION['user_combined_ip'] != $user_combined_ip) {
     $v_user = escapeshellarg($_SESSION['user']);
     $v_session_id = escapeshellarg($_SESSION['token']);
     exec(HESTIA_CMD . 'v-log-user-logout ' . $v_user . ' ' . $v_session_id, $output, $return_var);
     destroy_sessions();
     header('Location: /login/');

Vulnerable code: is_format_valid 'user'
if [ -n "$comment" ]; then
    is_format_valid 'comment'
fi
    is_username_format_valid "$username" "username"
is_format_valid 'user' 'domain'
is_format_valid 'chain'
is_format_valid 'user' 'domain' 'antispam' 'antivirus' 'dkim' 'dkim_size'
is_format_valid 'user' 'domain'
is_format_valid 'host' 'port' 'type' 'dns_user'
    ns3=$(echo "$4" | sed -e 's/\.*$//g' -e 's/^\.*//g')
    ns4=$(echo "$5" | sed -e 's/\.*$//g' -e 's/^\.*//g')
    ns5=$(echo "$6" | sed -e 's/\.*$//g' -e 's/^\.*//g')
    ns6=$(echo "$7" | sed -e 's/\.*$//g' -e 's/^\.*//g')
    ns7=$(echo "$8" | sed -e 's/\.*$//g' -e 's/^\.*//g')
    ns8=$(echo "$9" | sed -e 's/\.*$//g' -e 's/^\.*//g')
# Merging values
ns="$ns1,$ns2,$ns3,$ns4,$ns5,$ns6,$ns7,$ns8"
ns=$(echo "$ns" | sed -e "s/,,//g" -e "s/,$//")

is_format_valid 'user'
is_format_valid 'access_key_id'
is_format_valid 'user' 'dbuser'
is_format_valid 'user' 'domain'
nid=$2
is_format_valid 'user' 'nid'
sed -i "/NID='$nid' /d" $USER_DATA/notifications.conf 2>/dev/null
is_format_valid 'user'
check_args '2' "$#" 'USER DOMAIN'
is_format_valid 'user' 'domain'
is_format_valid 'user' 'domain'
is_format_valid 'user' 'vfile'
# removed "" around  \.\. and $(printf '\t'): SC2076: Don't quote right-hand side of =~, it'll match literally rather than as a regex. And we need regex match!

    if ! [[ "$1" =~ ^admin|user$ ]]; then
if ($_SESSION['user_combined_ip'] != $user_combined_ip && $_SERVER['REMOTE_ADDR'] != '127.0.0.1') {
Fixed code: is_format_valid 'user' 'comment' 'format'
    is_type_valid "$type" 'sftp,ftp,b2'
    is_username_format_valid "$user" "username"
is_format_valid 'restart'
if [ -n "$restart" ]; then 
    is_format_valid 'restart'
fi

if [ -n "$restart" ]; then
    is_format_valid 'restart'
fi
is_format_valid 'user' 'domain' 'restart'
port_ext=$2
is_format_valid 'chain' 'port_ext' 'protocol'
is_format_valid 'user' 'domain' 'antispam' 'antivirus' 'dkim' 'dkim_size' 'restart'
if [ -n "$restart" ]; then 
    is_format_valid "$restart"
fi
is_format_valid 'user' 'domain' 'restart'
if [ -n "$flush" ]; then
    is_type_valid "records yes no" "$flush" 
fi
is_format_valid 'host' 'port' 'dns_user'

ns="$ns1,$ns2"
    ns="$ns,$ns3"
    ns="$ns,$ns4"
    ns="$ns,$ns5"
    ns="$ns,$ns6"
    ns="$ns,$ns7"
    ns="$ns,$ns8"
is_format_valid 'user' 'theme'
is_domain_format_valid "$new_domain"
is_format_valid 'access_key_id' 'ip' 'command'
is_format_valid 'user' 'database' 'dbuser'
alias=$3
is_format_valid 'user' 'domain' 'alias' 'restart'
is_format_valid 'user' 'domain' 'account'
id=$2
is_format_valid 'user' 'id'
sed -i "/NID='$id' /d" $USER_DATA/notifications.conf 2>/dev/null
is_no_new_line_format "$key_id"
is_common_format_valid $country "country"
is_common_format_valid $state "state"
is_common_format_valid $org "org"
is_common_format_valid $unit "unit"

is_format_valid 'user' 'ip'
is_common_format_valid "$event_level" "event level"

    is_format_valid 'user'
is_common_format_valid "$session_id" "Session ID"
rstart=$3
check_args '2' "$#" 'USER DOMAIN [RESTART]'
is_format_valid 'user' 'domain' 'restart'
is_format_valid 'user' 'domain' 'aliases'
is_domain_format_valid "$hostname" "hostname"
is_format_valid 'user'
    is_no_new_line_format "$1";
    is_no_new_line_format "$1";
    is_no_new_line_format "$1";
}

is_no_new_line_format() {
    test=$(echo $1 | sed -e 's/\.*$//g' -e 's/^\.*//g');
    if [[ "$test" != "$1" ]]; then
      check_result "$E_INVALID" "invalid value :: $1"
    fi
  is_no_new_line_format "$1";
    is_no_new_line_format "$1";
    is_no_new_line_format "$1"
    is_no_new_line_format "$1";
    if ! [[ "$1" =~ ^admin$|^user$ ]]; then
                alias)          is_alias_format_valid "$arg" ;;        
                chain)          is_object_format_valid "$arg" 'chain' ;;
                dom_alias)      is_alias_format_valid "$arg" ;;
                format)         is_type_valid 'plain json shell csv' "$arg" ;;
                ssl_dir)        is_folder_exists "$arg" "$arg_name" ;;
                theme)          is_common_format_valid "$arg" "$arg_name" ;;
is_folder_exists () {
  if [ ! -d "$1" ]; then 
    check_result "$E_NOTEXIST" "folder $1 does not exist"
  fi
}

is_command_valid_format () {
  if [[ ! "$1" =~ ^v-[[:alnum:]][-|\.|_[:alnum:]]{0,64}[[:alnum:]]$ ]]; then 
    check_result "$E_INVALID" "Invalid command format"
  fi
  if [[ -n $( echo "$1" | grep -e '\-\-' ) ]]; then 
    check_result "$E_INVALID" "Invalid command format"
  fi
}
    is_no_new_line_format "$1"
#!/usr/bin/env bats

if [ "${PATH#*/usr/local/hestia/bin*}" = "$PATH" ]; then
    . /etc/profile.d/hestia.sh
fi

load 'test_helper/bats-support/load'
load 'test_helper/bats-assert/load'
load 'test_helper/bats-file/load'

function random() {
head /dev/urandom | tr -dc 0-9 | head -c$1
}

function setup() {
    # echo "# Setup_file" > &3
    if [ $BATS_TEST_NUMBER = 1 ]; then
        echo 'user=test-5285' > /tmp/hestia-test-env.sh
        echo 'user2=test-5286' >> /tmp/hestia-test-env.sh
        echo 'userbk=testbk-5285' >> /tmp/hestia-test-env.sh
        echo 'userpass1=test-5285' >> /tmp/hestia-test-env.sh
        echo 'userpass2=t3st-p4ssw0rd' >> /tmp/hestia-test-env.sh
        echo 'HESTIA=/usr/local/hestia' >> /tmp/hestia-test-env.sh
        echo 'domain=test-5285.hestiacp.com' >> /tmp/hestia-test-env.sh
        echo 'domainuk=test-5285.hestiacp.com.uk' >> /tmp/hestia-test-env.sh
        echo 'rootdomain=testhestiacp.com' >> /tmp/hestia-test-env.sh
        echo 'subdomain=cdn.testhestiacp.com' >> /tmp/hestia-test-env.sh
        echo 'database=test-5285_database' >> /tmp/hestia-test-env.sh
        echo 'dbuser=test-5285_dbuser' >> /tmp/hestia-test-env.sh
    fi
    
    source /tmp/hestia-test-env.sh
    source $HESTIA/func/main.sh
    source $HESTIA/conf/hestia.conf
    source $HESTIA/func/ip.sh
}

@test "is_access_key_id_format_valid valid" {
    run is_access_key_id_format_valid 'M0ocDoIKbsoXSqtk1mgc' "key"
    assert_success
}
@test "is_access_key_id_format_valid short" {
    run is_access_key_id_format_valid 'M0ocDoIKbsoXSqtk1mg' "key"
    assert_failure $E_INVALID
}
@test "is_access_key_id_format_valid long" {
    run is_access_key_id_format_valid 'M0ocDoIKbsoXSqtk1mgca' "key"
    assert_failure $E_INVALID
}
@test "is_access_key_id_format_valid non alpha" {
    run is_access_key_id_format_valid 'M0ocDoIKbsoX$qtk1mgc' "key"
    assert_failure $E_INVALID
}

@test "is_access_key_id_format_valid LHF" {
    run is_access_key_id_format_valid 'c
1eshutdown
r' "key"
    assert_failure $E_INVALID
}

@test "is_user_format_valid valid" {
    run is_user_format_valid 'hxh54SKbALne4s69VsqJRMbMd8Br' "key"
    assert_success
}
@test "is_user_format_valid short" {
    run is_user_format_valid 'hxh54SKbALne4s69VsqJR' "key"
    assert_success
}
@test "is_user_format_valid long" {
    run is_user_format_valid 'hxh54SKbALne4s69VsqJRMbMd8Braaa' "key"
    assert_failure $E_INVALID
}
@test "is_user_format_valid dash" {
    run is_user_format_valid 'hxh54SKbALne4-s6-VsqJRMbMd8Br' "key"
    assert_success
}

@test "is_user_format_valid dash repeat" {
    run is_user_format_valid 'hxh54SKbALne4s6--VsqJRMbMd8Br' "key"
    assert_success
}
@test "is_user_format_valid dash start" {
    run is_user_format_valid '-hxh54SKbALne4s6VsqJRMbMd8Br' "key"
    assert_failure $E_INVALID
}
@test "is_user_format_valid dash end" {
    run is_user_format_valid 'hxh54SKbALne4s6VsqJRMbMd8Br-' "key"
    assert_failure $E_INVALID
}
@test "is_user_format_valid LHF" {
    run is_user_format_valid 'M0ocDoIK
    soXSqtk1mgc' "key"
    assert_failure $E_INVALID
}

@test "is_fw_action_format_valid ACCEPT" {
    run is_fw_action_format_valid 'ACCEPT' "key"
    assert_success
}
@test "is_fw_action_format_valid DROP" {
    run is_fw_action_format_valid 'DROP' "key"
    assert_success
}
@test "is_fw_action_format_valid TEST" {
    run is_fw_action_format_valid 'TEST' "key"
    assert_failure $E_INVALID
}
@test "is_fw_action_format_valid LHF" {
    run is_fw_protocol_format_valid 'M0ocDoIK
    soXSqtk1mgc' "key"
    assert_failure $E_INVALID
}

@test "is_fw_protocol_format_valid ICMP" {
    run is_fw_protocol_format_valid 'ICMP' "key"
    assert_success
}

@test "is_fw_protocol_format_valid UDP" {
    run is_fw_protocol_format_valid 'UDP' "key"
    assert_success
}
@test "is_fw_protocol_format_valid TCP" {
    run is_fw_protocol_format_valid 'TCP' "key"
    assert_success
}
@test "is_fw_protocol_format_valid TEST" {
    run is_fw_protocol_format_valid 'TEST' "key"
    assert_failure $E_INVALID
}


@test "is_domain_format_valid success" {
     run is_domain_format_valid 'hestiacp.com' "key"
    assert_success
}

@test "is_domain_format_valid www" {
     run is_domain_format_valid 'www' "key"
    assert_failure $E_INVALID
}
@test "is_domain_format_valid number" {
     run is_domain_format_valid '12345' "key"
    assert_failure $E_INVALID
}

@test "is_domain_format_valid .." {
     run is_domain_format_valid '..' "key"
    assert_failure $E_INVALID
}
@test "is_domain_format_valid LF." {
     run is_domain_format_valid 'c
1eshutdown
r' "key"
    assert_failure $E_INVALID
}

@test "is_alias_format_valid success" {
     run is_domain_format_valid 'hestiacp.com' "key"
    assert_success
}

@test "is_alias_format_valid www" {
     run is_domain_format_valid 'www' "key"
    assert_failure $E_INVALID
}
@test "is_alias_format_valid number" {
     run is_domain_format_valid '12345' "key"
    assert_failure $E_INVALID
}

@test "is_alias_format_valid .." {
     run is_domain_format_valid '..' "key"
    assert_failure $E_INVALID
}
@test "is_alias_format_valid LF." {
     run is_domain_format_valid 'c
1eshutdown
r' "key"
    assert_failure $E_INVALID
}

@test "is_extention_format_valid test" {
     run is_extention_format_valid 'c
1eshutdown
r' "key"
    assert_failure $E_INVALID
}

@test "is_string_format_valid test" {
     run is_string_format_valid 'c
1eshutdown
r' "key"
    assert_failure $E_INVALID
}

@test "is_database_format_valid test" {
     run is_database_format_valid 'c
1eshutdown
r' "key"
    assert_failure $E_INVALID
}

@test "is_date_format_valid test" {
     run is_date_format_valid 'c
1eshutdown
r' "key"
    assert_failure $E_INVALID
}

@test "is_dbuser_format_valid test" {
     run is_dbuser_format_valid 'c
1eshutdown
r' "key"
    assert_failure $E_INVALID
}

@test "is_dns_type_format_valid test" {
     run is_dns_type_format_valid 'c
1eshutdown
r' "key"
    assert_failure $E_INVALID
}

@test "is_dns_record_format_valid test" {
     run is_dns_record_format_valid 'c
1eshutdown
r' "key"
    assert_failure $E_INVALID
}

@test "is_email_format_valid test" {
     run is_email_format_valid 'c
1eshutdown
r' "key"
    assert_failure $E_INVALID
}

@test "is_fw_port_format_valid test" {
     run is_fw_port_format_valid 'c
1eshutdown
r' "key"
    assert_failure $E_INVALID
}

@test "is_int_format_valid test" {
     run is_int_format_valid 'c
1eshutdown
r' "key"
    assert_failure $E_INVALID
}

@test "is_interface_format_valid test" {
     run is_interface_format_valid 'c
1eshutdown
r' "key"
    assert_failure $E_INVALID
}

@test "is_ip_status_format_valid test" {
     run is_ip_status_format_valid 'c
1eshutdown
r' "key"
    assert_failure $E_INVALID
}

@test "is_cron_format_valid test" {
     run is_cron_format_valid 'c
1eshutdown
r' "key"
    assert_failure $E_INVALID
}

@test "is_name_format_valid test" {
     run is_name_format_valid 'c
1eshutdown
r' "key"
    assert_failure $E_INVALID
}


@test "is_role_valid test" {
     run is_role_valid 'c
1eshutdown
r' "key"
    assert_failure $E_INVALID
}

@test "is_object_format_valid test" {
     run is_object_format_valid 'c
1eshutdown
r' "key"
    assert_failure $E_INVALID
}


@test "is_common_format_valid test" {
     run is_common_format_valid 'c
1eshutdown
r' "key"
    assert_failure $E_INVALID
}

@test "format_no_quotes test" {
     run format_no_quotes 'c
1eshutdown
r' "key"
    assert_failure $E_INVALID
}

@test "is_type_valid" {
    run is_type_valid 'c
    1eshutdown
    r' "test,key"
    assert_failure $E_INVALID
}

@test "is_command_valid_format v-list-users" {
    run is_command_valid_format 'v-list-users'
    assert_success
}

@test "is_command_valid_format v-list--users (Fail)" {
    run is_command_valid_format 'v-list--users'
    assert_failure $E_INVALID
}

@test "is_command_valid_format h-list-users (Fail)" {
    run is_command_valid_format 'h-list-users'
    assert_failure $E_INVALID
}

@test "is_command_valid_format list-users (Fail)" {
    run is_command_valid_format 'list-users'
    assert_failure $E_INVALID
}

@test "is_command_valid_format vlist-users (Fail)" {
    run is_command_valid_format 'vlist-users'
    assert_failure $E_INVALID
}

@test "is_command_valid_format LF (Fail)" {
     run is_command_valid_format 'v-
1eshutdown
r' "key"
    assert_failure $E_INVALID
}
if ($_SESSION['user_combined_ip'] != $user_combined_ip) {