fail( Aardwolf_Check_Result::SEVERITY_HIGH, __( 'The site address is configured over plain HTTP. All traffic — including login credentials, session cookies and form submissions — travels unencrypted and can be read or modified on the network path.', 'aardwolf-security-scanner' ), __( 'Obtain a TLS certificate (Let\'s Encrypt is free and most hosts automate it), then update the WordPress Address and Site Address to https:// under Settings → General. Add a permanent redirect from HTTP to HTTPS and set FORCE_SSL_ADMIN. Update any hard-coded http:// links in content afterwards.', 'aardwolf-security-scanner' ), 'https://wordpress.org/documentation/article/https-for-wordpress/' ); } return $this->pass( __( 'The site is configured to use HTTPS.', 'aardwolf-security-scanner' ) ); } } /** * PHP version is end-of-life / unsupported. */ class Aardwolf_Check_Php_Version extends Aardwolf_Check { public function id() { return 'php_version'; } public function label() { return __( 'PHP version is supported', 'aardwolf-security-scanner' ); } public function category() { return __( 'Transport & Environment', 'aardwolf-security-scanner' ); } public function run() { $current = PHP_VERSION; // Anything below 7.4 is well past end-of-life and receives no security // fixes. 7.4/8.0 are also EOL but many hosts still run them, so warn. if ( version_compare( $current, '7.4', '<' ) ) { return $this->fail( Aardwolf_Check_Result::SEVERITY_HIGH, sprintf( /* translators: %s: PHP version. */ __( 'The server runs PHP %s, which is end-of-life and no longer receives security patches. Known interpreter vulnerabilities will never be fixed on this version.', 'aardwolf-security-scanner' ), esc_html( $current ) ), __( 'Ask your host to move the site to a currently supported PHP release (8.1 or newer). Test on staging first, as very old plugins may need updating for compatibility.', 'aardwolf-security-scanner' ), 'https://www.php.net/supported-versions.php' ); } if ( version_compare( $current, '8.1', '<' ) ) { return $this->warn( Aardwolf_Check_Result::SEVERITY_MEDIUM, sprintf( /* translators: %s: PHP version. */ __( 'The server runs PHP %s, which has reached (or is close to) end of active security support.', 'aardwolf-security-scanner' ), esc_html( $current ) ), __( 'Plan an upgrade to a supported PHP version (8.1+). Newer PHP is also meaningfully faster.', 'aardwolf-security-scanner' ), 'https://www.php.net/supported-versions.php' ); } return $this->pass( sprintf( /* translators: %s: PHP version. */ __( 'PHP %s is a currently supported release.', 'aardwolf-security-scanner' ), esc_html( $current ) ) ); } } /** * SSL certificate reachability / mixed configuration sanity check. */ class Aardwolf_Check_Login_Protection extends Aardwolf_Check { public function id() { return 'login_protection'; } public function label() { return __( 'Login brute-force protection is present', 'aardwolf-security-scanner' ); } public function category() { return __( 'Accounts & Authentication', 'aardwolf-security-scanner' ); } public function run() { // WordPress core has no built-in login rate limiting, so we look for a // known protective plugin. This is a heuristic, not a guarantee. We read // the stored option directly, so no wp-admin include is needed. $active = (array) get_option( 'active_plugins', array() ); if ( is_multisite() ) { $active = array_merge( $active, array_keys( (array) get_site_option( 'active_sitewide_plugins', array() ) ) ); } $active_str = strtolower( implode( ' ', $active ) ); $signals = array( 'limit-login', 'wordfence', 'ithemes-security', 'better-wp-security', 'all-in-one-wp-security', 'sucuri', 'jetpack', 'loginizer', 'wps-hide-login', 'wp-cerber', 'solid-security' ); $has_protection = false; foreach ( $signals as $signal ) { if ( false !== strpos( $active_str, $signal ) ) { $has_protection = true; break; } } if ( ! $has_protection ) { return $this->warn( Aardwolf_Check_Result::SEVERITY_MEDIUM, __( 'No login rate-limiting or brute-force protection plugin was detected. WordPress core does not lock out repeated failed logins, so wp-login.php and XML-RPC can be hammered with password guesses indefinitely.', 'aardwolf-security-scanner' ), __( 'Install a login-protection plugin (for example one that limits failed attempts), enforce strong passwords, and enable two-factor authentication for all administrator accounts. Consider adding a CAPTCHA to the login form and/or restricting wp-admin by IP.', 'aardwolf-security-scanner' ), 'https://wordpress.org/documentation/article/hardening-wordpress/#security-through-obscurity' ); } return $this->pass( __( 'A login-protection / security plugin appears to be active.', 'aardwolf-security-scanner' ) ); } }