iThemes Security (formerly Better WP Security) - Version 7.3.2

Version Description

  • Tweak: Allow the log description column to word break for URLs or other strings with no spaces.
  • Bug Fix: Hide Backend bypass on certain Apache configurations.
  • Bug Fix: Properly return error that occurs during a backup.
  • Bug Fix: Regex warning on PHP 7.3 in the File Change module.
  • Bug Fix: Resolve warning when a user is set to "No Role".
Download this release

Release Info

Developer TimothyBlynJacobs
Plugin Icon 128x128 iThemes Security (formerly Better WP Security)
Version 7.3.2
Comparing to
See all releases

Code changes from version 7.3.1 to 7.3.2

better-wp-security.php CHANGED
@@ -6,14 +6,14 @@
6
  * Description: Take the guesswork out of WordPress security. iThemes Security offers 30+ ways to lock down WordPress in an easy-to-use WordPress security plugin.
7
  * Author: iThemes
8
  * Author URI: https://ithemes.com
9
- * Version: 7.3.1
10
  * Text Domain: better-wp-security
11
  * Network: True
12
  * License: GPLv2
13
  */
14
 
15
  function itsec_load_textdomain() {
16
-
17
  if ( function_exists( 'determine_locale' ) ) {
18
  $locale = determine_locale();
19
  } elseif ( function_exists( 'get_user_locale' ) && is_admin() ) {
6
  * Description: Take the guesswork out of WordPress security. iThemes Security offers 30+ ways to lock down WordPress in an easy-to-use WordPress security plugin.
7
  * Author: iThemes
8
  * Author URI: https://ithemes.com
9
+ * Version: 7.3.2
10
  * Text Domain: better-wp-security
11
  * Network: True
12
  * License: GPLv2
13
  */
14
 
15
  function itsec_load_textdomain() {
16
+
17
  if ( function_exists( 'determine_locale' ) ) {
18
  $locale = determine_locale();
19
  } elseif ( function_exists( 'get_user_locale' ) && is_admin() ) {
core/admin-pages/css/style.css CHANGED
@@ -827,6 +827,7 @@ ul.itsec-settings-contacts li input[type="checkbox"] {
827
  }
828
  .itsec-log-entries .column-description {
829
  max-width: 30%;
 
830
  }
831
  .tablenav .actions {
832
  overflow: visible;
827
  }
828
  .itsec-log-entries .column-description {
829
  max-width: 30%;
830
+ word-break: break-all;
831
  }
832
  .tablenav .actions {
833
  overflow: visible;
core/history.txt CHANGED
@@ -790,3 +790,9 @@
790
  Bug Fix: Tabnapping: Apply noopener to links instead of using blankshield script when available to prevent new pop-up blocker behavior from killing the links.
791
  5.1.2 - 2019-02-20 - Chris Jean & Timothy Jacobs
792
  Enhancement: When ITSEC_DISABLE_MODULES is set, prevent hide backend from running.
 
 
 
 
 
 
790
  Bug Fix: Tabnapping: Apply noopener to links instead of using blankshield script when available to prevent new pop-up blocker behavior from killing the links.
791
  5.1.2 - 2019-02-20 - Chris Jean & Timothy Jacobs
792
  Enhancement: When ITSEC_DISABLE_MODULES is set, prevent hide backend from running.
793
+ 5.1.3 - 2019-03-12 - Chris Jean & Timothy Jacobs
794
+ Tweak: Allow the log description column to word break for URLs or other strings with no spaces.
795
+ Bug Fix: Hide Backend bypass on certain Apache configurations.
796
+ Bug Fix: Properly return error that occurs during a backup.
797
+ Bug Fix: Regex warning on PHP 7.3 in the File Change module.
798
+ Bug Fix: Resolve warning when a user is set to "No Role".
core/lib.php CHANGED
@@ -1685,4 +1685,20 @@ final class ITSEC_Lib {
1685
 
1686
  return $preload;
1687
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1688
  }
1685
 
1686
  return $preload;
1687
  }
1688
+
1689
+ /**
1690
+ * Check if the given string starts with the given needle.
1691
+ *
1692
+ * @param string $haystack
1693
+ * @param string $needle
1694
+ *
1695
+ * @return bool
1696
+ */
1697
+ public static function str_starts_with( $haystack, $needle ) {
1698
+ return 0 === strpos( $haystack, $needle );
1699
+ }
1700
+
1701
+ public static function str_ends_with( $haystack, $needle ) {
1702
+ return '' === $needle || substr_compare( $haystack, $needle, - strlen( $needle ) ) === 0;
1703
+ }
1704
  }
core/lib/class-itsec-lib-canonical-roles.php CHANGED
@@ -130,7 +130,12 @@ final class ITSEC_Lib_Canonical_Roles {
130
  * @return string
131
  */
132
  public static function get_canonical_role_from_role( $role ) {
133
- return self::get_role_from_caps( array_keys( array_filter( wp_roles()->get_role( $role )->capabilities ) ) );
 
 
 
 
 
134
  }
135
 
136
  /**
130
  * @return string
131
  */
132
  public static function get_canonical_role_from_role( $role ) {
133
+ // Handle invalid roles or roles that do not exist anymore.
134
+ if ( ! $role_object = wp_roles()->get_role( $role ) ) {
135
+ return '';
136
+ }
137
+
138
+ return self::get_role_from_caps( array_keys( array_filter( $role_object->capabilities ) ) );
139
  }
140
 
141
  /**
core/lockout.php CHANGED
@@ -769,66 +769,59 @@ final class ITSEC_Lockout {
769
  }
770
 
771
  /**
772
- * Store a record of the locked out user/host or permanently ban the host.
773
  *
774
- * Permanently banned hosts will be forwarded to the ban-users module via the itsec-new-blacklisted-ip hook and
775
- * not persisted to the database.
776
- *
777
- * If configured, notifies the configured email addresses of the lockout.
778
  *
779
- * @since 4.0
780
- *
781
- * @param string $module The module triggering the lockout.
782
- * @param string|bool $host Host to lock out or false if the host should not be locked out.
783
- * @param int|bool $user_id User ID to lockout or false if the host should not be locked out.
784
- * @param string|bool $username Username to lockout or false if the host should not be locked out.
785
- *
786
- * @return void
787
  */
788
- private function lockout( $module, $host, $user_id, $username ) {
789
  global $wpdb;
790
 
 
 
 
 
 
 
791
 
792
- $lock = "lockout_$host$user_id$username";
793
-
794
- // Acquire a lock to prevent a lockout being created more than once by a particularly fast attacker.
795
- if ( ! ITSEC_Lib::get_lock( $lock, 180 ) ) {
796
- return;
797
- }
798
-
799
 
800
- $module_details = $this->lockout_modules[$module];
801
 
802
  $whitelisted = ITSEC_Lib::is_ip_whitelisted( $host );
803
  $blacklisted = false;
804
 
805
  $log_data = array(
806
- 'module' => $module,
807
- 'host' => $host,
808
- 'user_id' => $user_id,
809
- 'username' => $username,
810
- 'module_details' => $module_details,
811
- 'whitelisted' => $whitelisted,
812
- 'blacklisted' => false,
813
  );
814
 
815
 
816
  // Do a permanent ban if enabled and settings criteria are met.
817
  if ( ITSEC_Modules::get_setting( 'global', 'blacklist' ) && false !== $host ) {
818
- $blacklist_count = ITSEC_Modules::get_setting( 'global', 'blacklist_count' );
819
- $blacklist_period = ITSEC_Modules::get_setting( 'global', 'blacklist_period', 7 );
820
  $blacklist_seconds = $blacklist_period * DAY_IN_SECONDS;
821
 
822
  $host_count = 1 + $wpdb->get_var(
823
- $wpdb->prepare(
824
- "SELECT COUNT(*) FROM `{$wpdb->base_prefix}itsec_lockouts` WHERE `lockout_expire_gmt` > %s AND `lockout_host`= %s",
825
- date( 'Y-m-d H:i:s', ITSEC_Core::get_current_time_gmt() - $blacklist_seconds ),
826
- $host
827
- )
828
- );
829
 
830
  if ( $host_count >= $blacklist_count ) {
831
- $blacklisted = true;
832
  $log_data['blacklisted'] = true;
833
 
834
  if ( $whitelisted ) {
@@ -843,11 +836,12 @@ final class ITSEC_Lockout {
843
 
844
  $host_expiration = false;
845
  $user_expiration = false;
 
846
 
847
  $lockouts_data = array(
848
- 'lockout_type' => $module_details['type'],
849
- 'lockout_start' => date( 'Y-m-d H:i:s', ITSEC_Core::get_current_time() ),
850
- 'lockout_start_gmt' => date( 'Y-m-d H:i:s', ITSEC_Core::get_current_time_gmt() ),
851
  );
852
 
853
  if ( $whitelisted ) {
@@ -862,36 +856,75 @@ final class ITSEC_Lockout {
862
 
863
  if ( false !== $host && ! $blacklisted ) {
864
  $host_expiration = $lockouts_data['lockout_expire'];
865
- $this->add_lockout_to_db( 'host', $host, $whitelisted, $lockouts_data, $log_data );
866
  }
867
 
868
  if ( false !== $user_id ) {
869
  $user_expiration = $lockouts_data['lockout_expire'];
870
- $this->add_lockout_to_db( 'user', $user_id, $whitelisted, $lockouts_data, $log_data );
871
  }
872
 
873
  if ( false !== $username ) {
874
  $user_expiration = $lockouts_data['lockout_expire'];
875
- $this->add_lockout_to_db( 'username', $username, $whitelisted, $lockouts_data, $log_data );
876
  }
877
 
 
 
878
 
879
- if ( $whitelisted ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
880
  // No need to send an email notice when the host is whitelisted.
881
  ITSEC_Lib::release_lock( $lock );
 
882
  return;
883
  }
884
 
885
-
886
- $this->send_lockout_email( $host, $user_id, $username, $host_expiration, $user_expiration, $module_details['reason'] );
 
 
 
 
 
 
887
 
888
  $lock_context = array(
889
- 'type' => $module_details['type'],
890
  );
891
 
892
  if ( false !== $user_id ) {
893
  $lock_context['user'] = get_userdata( $user_id );
894
- } else if ( false !== $username ) {
895
  $lock_context['username'] = $username;
896
  }
897
 
@@ -911,12 +944,16 @@ final class ITSEC_Lockout {
911
  * @param bool $whitelisted Whether or not the host triggering the event is whitelisted.
912
  * @param array $lockout_data Array of base data to be inserted.
913
  * @param array $log_data Array of data to be logged for the event.
 
 
914
  */
915
  private function add_lockout_to_db( $type, $id, $whitelisted, $lockout_data, $log_data ) {
916
  global $wpdb;
917
 
918
  $lockout_data["lockout_$type"] = $id;
919
- $wpdb->insert( "{$wpdb->base_prefix}itsec_lockouts", $lockout_data );
 
 
920
 
921
  if ( $whitelisted ) {
922
  ITSEC_Log::add_notice( 'lockout', "whitelisted-host-triggered-$type-lockout", array_merge( $log_data, $lockout_data ) );
@@ -931,6 +968,8 @@ final class ITSEC_Lockout {
931
 
932
  ITSEC_Log::add_action( 'lockout', $code, array_merge( $log_data, $lockout_data ) );
933
  }
 
 
934
  }
935
 
936
  /**
769
  }
770
 
771
  /**
772
+ * Create a lockout.
773
  *
774
+ * @param array $args
 
 
 
775
  *
776
+ * @return array
 
 
 
 
 
 
 
777
  */
778
+ public function create_lockout( $args = array() ) {
779
  global $wpdb;
780
 
781
+ $args = wp_parse_args( $args, array(
782
+ 'module' => '',
783
+ 'host' => false,
784
+ 'user_id' => false,
785
+ 'username' => false,
786
+ ) );
787
 
788
+ $module = $args['module'];
789
+ $host = $args['host'];
790
+ $user_id = $args['user_id'];
791
+ $username = $args['username'];
 
 
 
792
 
793
+ $module_details = $this->lockout_modules[ $module ];
794
 
795
  $whitelisted = ITSEC_Lib::is_ip_whitelisted( $host );
796
  $blacklisted = false;
797
 
798
  $log_data = array(
799
+ 'module' => $module,
800
+ 'host' => $host,
801
+ 'user_id' => $user_id,
802
+ 'username' => $username,
803
+ 'module_details' => $module_details,
804
+ 'whitelisted' => $whitelisted,
805
+ 'blacklisted' => false,
806
  );
807
 
808
 
809
  // Do a permanent ban if enabled and settings criteria are met.
810
  if ( ITSEC_Modules::get_setting( 'global', 'blacklist' ) && false !== $host ) {
811
+ $blacklist_count = ITSEC_Modules::get_setting( 'global', 'blacklist_count' );
812
+ $blacklist_period = ITSEC_Modules::get_setting( 'global', 'blacklist_period', 7 );
813
  $blacklist_seconds = $blacklist_period * DAY_IN_SECONDS;
814
 
815
  $host_count = 1 + $wpdb->get_var(
816
+ $wpdb->prepare(
817
+ "SELECT COUNT(*) FROM `{$wpdb->base_prefix}itsec_lockouts` WHERE `lockout_expire_gmt` > %s AND `lockout_host`= %s",
818
+ date( 'Y-m-d H:i:s', ITSEC_Core::get_current_time_gmt() - $blacklist_seconds ),
819
+ $host
820
+ )
821
+ );
822
 
823
  if ( $host_count >= $blacklist_count ) {
824
+ $blacklisted = true;
825
  $log_data['blacklisted'] = true;
826
 
827
  if ( $whitelisted ) {
836
 
837
  $host_expiration = false;
838
  $user_expiration = false;
839
+ $id = false;
840
 
841
  $lockouts_data = array(
842
+ 'lockout_type' => $module_details['type'],
843
+ 'lockout_start' => date( 'Y-m-d H:i:s', ITSEC_Core::get_current_time() ),
844
+ 'lockout_start_gmt' => date( 'Y-m-d H:i:s', ITSEC_Core::get_current_time_gmt() ),
845
  );
846
 
847
  if ( $whitelisted ) {
856
 
857
  if ( false !== $host && ! $blacklisted ) {
858
  $host_expiration = $lockouts_data['lockout_expire'];
859
+ $id = $this->add_lockout_to_db( 'host', $host, $whitelisted, $lockouts_data, $log_data );
860
  }
861
 
862
  if ( false !== $user_id ) {
863
  $user_expiration = $lockouts_data['lockout_expire'];
864
+ $id = $this->add_lockout_to_db( 'user', $user_id, $whitelisted, $lockouts_data, $log_data );
865
  }
866
 
867
  if ( false !== $username ) {
868
  $user_expiration = $lockouts_data['lockout_expire'];
869
+ $id = $this->add_lockout_to_db( 'username', $username, $whitelisted, $lockouts_data, $log_data );
870
  }
871
 
872
+ return compact( 'id', 'host_expiration', 'user_expiration', 'whitelisted', 'blacklisted', 'module_details' );
873
+ }
874
 
875
+ /**
876
+ * Store a record of the locked out user/host or permanently ban the host.
877
+ *
878
+ * Permanently banned hosts will be forwarded to the ban-users module via the itsec-new-blacklisted-ip hook and
879
+ * not persisted to the database.
880
+ *
881
+ * If configured, notifies the configured email addresses of the lockout.
882
+ *
883
+ * @since 4.0
884
+ *
885
+ * @param string $module The module triggering the lockout.
886
+ * @param string|bool $host Host to lock out or false if the host should not be locked out.
887
+ * @param int|bool $user_id User ID to lockout or false if the host should not be locked out.
888
+ * @param string|bool $username Username to lockout or false if the host should not be locked out.
889
+ *
890
+ * @return void
891
+ */
892
+ private function lockout( $module, $host, $user_id, $username ) {
893
+ global $wpdb;
894
+
895
+
896
+ $lock = "lockout_$host$user_id$username";
897
+
898
+ // Acquire a lock to prevent a lockout being created more than once by a particularly fast attacker.
899
+ if ( ! ITSEC_Lib::get_lock( $lock, 180 ) ) {
900
+ return;
901
+ }
902
+
903
+ $details = $this->create_lockout( compact( 'module', 'host', 'user_id', 'username' ) );
904
+
905
+ if ( $details['whitelisted'] ) {
906
  // No need to send an email notice when the host is whitelisted.
907
  ITSEC_Lib::release_lock( $lock );
908
+
909
  return;
910
  }
911
 
912
+ $this->send_lockout_email(
913
+ $host,
914
+ $user_id,
915
+ $username,
916
+ $details['host_expiration'],
917
+ $details['user_expiration'],
918
+ $details['module_details']['reason']
919
+ );
920
 
921
  $lock_context = array(
922
+ 'type' => $details['module_details']['type'],
923
  );
924
 
925
  if ( false !== $user_id ) {
926
  $lock_context['user'] = get_userdata( $user_id );
927
+ } elseif ( false !== $username ) {
928
  $lock_context['username'] = $username;
929
  }
930
 
944
  * @param bool $whitelisted Whether or not the host triggering the event is whitelisted.
945
  * @param array $lockout_data Array of base data to be inserted.
946
  * @param array $log_data Array of data to be logged for the event.
947
+ *
948
+ * @return int|false
949
  */
950
  private function add_lockout_to_db( $type, $id, $whitelisted, $lockout_data, $log_data ) {
951
  global $wpdb;
952
 
953
  $lockout_data["lockout_$type"] = $id;
954
+
955
+ $result = $wpdb->insert( "{$wpdb->base_prefix}itsec_lockouts", $lockout_data );
956
+ $insert_id = $result ? $wpdb->insert_id : false;
957
 
958
  if ( $whitelisted ) {
959
  ITSEC_Log::add_notice( 'lockout', "whitelisted-host-triggered-$type-lockout", array_merge( $log_data, $lockout_data ) );
968
 
969
  ITSEC_Log::add_action( 'lockout', $code, array_merge( $log_data, $lockout_data ) );
970
  }
971
+
972
+ return $insert_id;
973
  }
974
 
975
  /**
core/modules/backup/class-itsec-backup.php CHANGED
@@ -83,6 +83,10 @@ class ITSEC_Backup {
83
  $result = $this->execute_backup( $one_time );
84
  ITSEC_Lib::release_lock( 'backup' );
85
 
 
 
 
 
86
  switch ( $this->settings['method'] ) {
87
  case 0:
88
  $message = __( 'Backup complete. The backup was sent to the selected email recipients and was saved locally.', 'better-wp-security' );
83
  $result = $this->execute_backup( $one_time );
84
  ITSEC_Lib::release_lock( 'backup' );
85
 
86
+ if ( is_wp_error( $result ) ) {
87
+ return $result;
88
+ }
89
+
90
  switch ( $this->settings['method'] ) {
91
  case 0:
92
  $message = __( 'Backup complete. The backup was sent to the selected email recipients and was saved locally.', 'better-wp-security' );
core/modules/file-change/lib/package-factory.php CHANGED
@@ -29,7 +29,7 @@ class ITSEC_File_Change_Package_Factory {
29
  }
30
  }
31
 
32
- $core_files = '@' . preg_quote( ABSPATH, '@' ) . '[\w-_]+\.@';
33
  $sp[ $core_files ] = 'core';
34
 
35
  uksort( $sp, array( $this, '_sort' ) );
@@ -306,4 +306,4 @@ class ITSEC_File_Change_Package_Factory {
306
 
307
  return $parts[0];
308
  }
309
- }
29
  }
30
  }
31
 
32
+ $core_files = '@' . preg_quote( ABSPATH, '@' ) . '[\w\-_]+\.@';
33
  $sp[ $core_files ] = 'core';
34
 
35
  uksort( $sp, array( $this, '_sort' ) );
306
 
307
  return $parts[0];
308
  }
309
+ }
core/modules/hide-backend/class-itsec-hide-backend.php CHANGED
@@ -82,15 +82,19 @@ class ITSEC_Hide_Backend {
82
 
83
  $request_path = ITSEC_Lib::get_request_path();
84
 
 
 
 
 
85
  if ( $request_path === $this->settings['slug'] ) {
86
  $this->handle_login_alias();
87
- } else if ( in_array( $request_path, array( 'wp-login', 'wp-login.php' ) ) ) {
88
  $this->handle_canonical_login_page();
89
- } else if ( 'wp-admin' === $request_path || 'wp-admin/' === substr( $request_path, 0, 9 ) ) {
90
  $this->handle_wp_admin_page();
91
- } else if ( $request_path === $this->settings['register'] && $this->allow_access_to_wp_signup() ) {
92
  $this->handle_registration_alias();
93
- } else if ( 'wp-signup.php' === $request_path ) {
94
  $this->handle_canonical_signup_page();
95
  }
96
  }
82
 
83
  $request_path = ITSEC_Lib::get_request_path();
84
 
85
+ if ( strpos( $request_path, '/' ) !== false ) {
86
+ list( $request_path ) = explode( '/', $request_path );
87
+ }
88
+
89
  if ( $request_path === $this->settings['slug'] ) {
90
  $this->handle_login_alias();
91
+ } elseif ( in_array( $request_path, array( 'wp-login', 'wp-login.php' ) ) ) {
92
  $this->handle_canonical_login_page();
93
+ } elseif ( 'wp-admin' === $request_path || 'wp-admin/' === substr( $request_path, 0, 9 ) ) {
94
  $this->handle_wp_admin_page();
95
+ } elseif ( $request_path === $this->settings['register'] && $this->allow_access_to_wp_signup() ) {
96
  $this->handle_registration_alias();
97
+ } elseif ( 'wp-signup.php' === $request_path ) {
98
  $this->handle_canonical_signup_page();
99
  }
100
  }
history.txt CHANGED
@@ -828,3 +828,9 @@
828
  7.3.1 - 2019-02-21 - Chris Jean & Timothy Jacobs
829
  Enhancement: When ITSEC_DISABLE_MODULES is set, prevent hide backend from running.
830
  Bug Fix: Tabnapping: Apply noopener to links instead of using blankshield script when available to prevent new pop-up blocker behavior from killing the links.
 
 
 
 
 
 
828
  7.3.1 - 2019-02-21 - Chris Jean & Timothy Jacobs
829
  Enhancement: When ITSEC_DISABLE_MODULES is set, prevent hide backend from running.
830
  Bug Fix: Tabnapping: Apply noopener to links instead of using blankshield script when available to prevent new pop-up blocker behavior from killing the links.
831
+ 7.3.2 - 2019-03-19 - Chris Jean & Timothy Jacobs
832
+ Tweak: Allow the log description column to word break for URLs or other strings with no spaces.
833
+ Bug Fix: Hide Backend bypass on certain Apache configurations.
834
+ Bug Fix: Properly return error that occurs during a backup.
835
+ Bug Fix: Regex warning on PHP 7.3 in the File Change module.
836
+ Bug Fix: Resolve warning when a user is set to "No Role".
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: ithemes, chrisjean, gerroald, mattdanner, timothyblynjacobs
3
  Tags: security, security plugin, malware, hack, secure, block, SSL, admin, htaccess, lockdown, login, protect, protection, anti virus, attack, injection, login security, maintenance, permissions, prevention, authentication, administration, password, brute force, ban, permissions, bots, user agents, xml rpc, security log
4
  Requires at least: 4.7
5
  Tested up to: 5.1.0
6
- Stable tag: 7.3.1
7
  Requires PHP: 5.2
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
@@ -189,6 +189,13 @@ Free support may be available with the help of the community in the <a href="htt
189
 
190
  == Changelog ==
191
 
 
 
 
 
 
 
 
192
  = 7.3.1 =
193
  * Enhancement: When ITSEC_DISABLE_MODULES is set, prevent hide backend from running.
194
  * Bug Fix: Tabnapping: Apply noopener to links instead of using blankshield script when available to prevent new pop-up blocker behavior from killing the links.
@@ -524,5 +531,5 @@ Free support may be available with the help of the community in the <a href="htt
524
 
525
  == Upgrade Notice ==
526
 
527
- = 7.3.1 =
528
- Version 7.3.1 contains important bug fixes and improvements. It is recommended for all users.
3
  Tags: security, security plugin, malware, hack, secure, block, SSL, admin, htaccess, lockdown, login, protect, protection, anti virus, attack, injection, login security, maintenance, permissions, prevention, authentication, administration, password, brute force, ban, permissions, bots, user agents, xml rpc, security log
4
  Requires at least: 4.7
5
  Tested up to: 5.1.0
6
+ Stable tag: 7.3.2
7
  Requires PHP: 5.2
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
189
 
190
  == Changelog ==
191
 
192
+ = 7.3.2 =
193
+ * Tweak: Allow the log description column to word break for URLs or other strings with no spaces.
194
+ * Bug Fix: Hide Backend bypass on certain Apache configurations.
195
+ * Bug Fix: Properly return error that occurs during a backup.
196
+ * Bug Fix: Regex warning on PHP 7.3 in the File Change module.
197
+ * Bug Fix: Resolve warning when a user is set to "No Role".
198
+
199
  = 7.3.1 =
200
  * Enhancement: When ITSEC_DISABLE_MODULES is set, prevent hide backend from running.
201
  * Bug Fix: Tabnapping: Apply noopener to links instead of using blankshield script when available to prevent new pop-up blocker behavior from killing the links.
531
 
532
  == Upgrade Notice ==
533
 
534
+ = 7.3.2 =
535
+ Version 7.3.2 contains important bug fixes and security improvements. It is recommended for all users.