: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
__('This %1$s contains a URL that is currently listed on Wordfence\'s domain blocklist. The URL is: %2$s', 'wordfence'),
$ignoreC = $idString . '-' . $contentMD5;
$added = $this->addIssue('commentBadURL', wfIssues::SEVERITY_LOW, $ignoreP, $ignoreC, $shortMsg, $longMsg, array(
'commentID' => $commentID,
'badURL' => $result['URL'],
'editCommentLink' => get_edit_comment_link($commentID),
'isMultisite' => $blog['isMultisite'],
'domain' => $blog['domain'],
if ($added == wfIssues::ISSUE_ADDED || $added == wfIssues::ISSUE_UPDATED) {
$haveIssues = wfIssues::STATUS_PROBLEM;
} else if ($haveIssues != wfIssues::STATUS_PROBLEM && ($added == wfIssues::ISSUE_IGNOREP || $added == wfIssues::ISSUE_IGNOREC)) {
$haveIssues = wfIssues::STATUS_IGNORED;
wfIssues::statusEnd($this->statusIDX['comments'], $haveIssues);
$this->scanController->completeStage(wfScanner::STAGE_CONTENT_SAFETY, $haveIssues);
public function isBadComment($author, $email, $url, $IP, $content) {
$content = $author . ' ' . $email . ' ' . $url . ' ' . $IP . ' ' . $content;
$cDesc = sprintf(/* translators: WordPress username. */ __("Author: %s", 'wordfence'), $author) . ' ';
$cDesc .= sprintf(/* translators: Email address. */ __("Email: %s", 'wordfence'), $email) . ' ';
$cDesc .= sprintf(/* translators: IP address. */ __("Source IP: %s", 'wordfence'), $IP) . ' ';
$this->status(2, 'info', sprintf(/* translators: Comment description. */ __("Scanning comment with %s", 'wordfence'), $cDesc));
$h = new wordfenceURLHoover($this->apiKey, $this->wp_version);
$h->hoover(1, $content, wordfenceURLHoover::standardExcludedHosts());
$hooverResults = $h->getBaddies();
if (sizeof($hooverResults) > 0 && isset($hooverResults[1])) {
$hresults = $hooverResults[1];
foreach ($hresults as $result) {
if ($result['badList'] == 'goog-malware-shavar') {
$this->status(2, 'info', sprintf(/* translators: Comment description. */ __("Marking comment as spam for containing a malware URL. Comment has %s", 'wordfence'), $cDesc));
} else if ($result['badList'] == 'googpub-phish-shavar') {
$this->status(2, 'info', sprintf(/* translators: Comment description. */ __("Marking comment as spam for containing a phishing URL. Comment has %s", 'wordfence'), $cDesc));
} else if ($result['badList'] == 'wordfence-dbl') {
$this->status(2, 'info', sprintf(/* translators: Comment description. */ __("Marking comment as spam for containing a malware URL. Comment has %s", 'wordfence'), $cDesc));
//A list type that may be new and the plugin has not been upgraded yet.
$this->status(2, 'info', sprintf(/* translators: Comment description. */ __("Scanned comment with %s", 'wordfence'), $cDesc));
public static function getBlogsToScan($table, $withID = null) {
$q1 = $wfdb->querySelect("select blog_id, domain, path from {$wpdb->blogs} where deleted=0 order by blog_id asc");
$q1 = $wfdb->querySelect("select blog_id, domain, path from {$wpdb->blogs} where deleted=0 and blog_id = %d", $withID);
$row['isMultisite'] = true;
$row['table'] = wfDB::blogTable($table, $row['blog_id']);
'table' => wfDB::networkTable($table),
private function highestCap($caps) {
foreach (array('administrator', 'editor', 'author', 'contributor', 'subscriber') as $cap) {
if (empty($caps[$cap]) === false && $caps[$cap]) {
private function isEditor($caps) {
foreach (array('contributor', 'author', 'editor', 'administrator') as $cap) {
if (empty($caps[$cap]) === false && $caps[$cap]) {
private function scan_passwds_init() {
$this->statusIDX['passwds'] = wfIssues::statusStart(__('Scanning for weak passwords', 'wordfence'));
$this->scanController->startStage(wfScanner::STAGE_PASSWORD_STRENGTH);
$query = "select ID from " . $wpdb->users;
$useMySQLi = wfUtils::useMySQLi();
if ($useMySQLi) { //If direct-access MySQLi is available, we use it to minimize the memory footprint instead of letting it fetch everything into an array first
$result = $dbh->query($query);
if (!is_object($result)) {
'errorMsg' => __("We were unable to generate the user list for your password check.", 'wordfence'),
while ($rec = $result->fetch_assoc()) {
$this->userPasswdQueue .= pack('N', $rec['ID']);
$res1 = $wpdb->get_results($query, ARRAY_A);
foreach ($res1 as $rec) {
$this->userPasswdQueue .= pack('N', $rec['ID']);
wordfence::status(2, 'info', sprintf(
/* translators: Number of users. */
_n("Starting password strength check on %d user.", "Starting password strength check on %d users.", $counter, 'wordfence'), $counter));
private function scan_passwds_main() {
while (strlen($this->userPasswdQueue) > 3) {
$usersLeft = strlen($this->userPasswdQueue) / 4; //4 byte ints
if ($usersLeft % 100 == 0) {
wordfence::status(2, 'info', sprintf(
/* translators: Number of users. */
"Total of %d users left to process in password strength check.",
"Total of %d users left to process in password strength check.",
$userID = unpack('N', substr($this->userPasswdQueue, 0, 4));
$this->userPasswdQueue = substr($this->userPasswdQueue, 4);
$state = $this->scanUserPassword($userID);
$this->scanController->incrementSummaryItem(wfScanner::SUMMARY_SCANNED_USERS);
if ($state == wfIssues::STATUS_PROBLEM) {
$this->passwdHasIssues = wfIssues::STATUS_PROBLEM;
} else if ($this->passwdHasIssues != wfIssues::STATUS_PROBLEM && $state == wfIssues::STATUS_IGNORED) {
$this->passwdHasIssues = wfIssues::STATUS_IGNORED;
private function scan_passwds_finish() {
wfIssues::statusEnd($this->statusIDX['passwds'], $this->passwdHasIssues);
$this->scanController->completeStage(wfScanner::STAGE_PASSWORD_STRENGTH, $this->passwdHasIssues);
public function scanUserPassword($userID) {
$suspended = wp_suspend_cache_addition();
wp_suspend_cache_addition(true);
require_once(ABSPATH . 'wp-includes/class-phpass.php');
$passwdHasher = new PasswordHash(8, TRUE);
$userDat = get_userdata($userID);
if ($userDat === false) {
wordfence::status(2, 'error', sprintf(/* translators: WordPress user ID. */ __("Could not get username for user with ID %d when checking password strength.", 'wordfence'), $userID));
$this->status(4, 'info', sprintf(
/* translators: 1. WordPress username. 2. WordPress user ID. */
__('Checking password strength of user \'%1$s\' with ID %2$d', 'wordfence'),
) . (function_exists('memory_get_usage') ? " (Mem:" . sprintf('%.1f', memory_get_usage(true) / (1024 * 1024)) . "M)" : ""));
$highCap = $this->highestCap($userDat->wp_capabilities);
if ($this->isEditor($userDat->wp_capabilities)) {
/* translators: 1. WordPress username. 2. WordPress capability. */
__('User "%1$s" with "%2$s" access has an easy password.', 'wordfence'),
esc_html($userDat->user_login),
/* translators: WordPress capability. */
__("A user with the a role of '%s' has a password that is easy to guess. Please change this password yourself or ask the user to change it.", 'wordfence'),
$level = wfIssues::SEVERITY_CRITICAL;
$words = $this->dictWords;
/* translators: WordPress username. */
__("User \"%s\" with 'subscriber' access has a very easy password.", 'wordfence'), esc_html($userDat->user_login));
$longMsg = __("A user with 'subscriber' access has a password that is very easy to guess. Please either change it or ask the user to change their password.", 'wordfence');
$level = wfIssues::SEVERITY_HIGH;
$words = array($userDat->user_login);
$haveIssues = wfIssues::STATUS_SECURE;
for ($i = 0; $i < sizeof($words); $i++) {
if ($passwdHasher->CheckPassword($words[$i], $userDat->user_pass)) {
$this->status(2, 'info', sprintf(/* translators: Scan result description. */ __('Adding issue %s', 'wordfence'), $shortMsg));
$added = $this->addIssue('easyPassword', $level, $userDat->ID, $userDat->ID . '-' . $userDat->user_pass, $shortMsg, $longMsg, array(
'user_login' => $userDat->user_login,
'user_email' => $userDat->user_email,
'first_name' => $userDat->first_name,
'last_name' => $userDat->last_name,
'editUserLink' => wfUtils::editUserLink($userDat->ID)
if ($added == wfIssues::ISSUE_ADDED || $added == wfIssues::ISSUE_UPDATED) {
$haveIssues = wfIssues::STATUS_PROBLEM;
} else if ($haveIssues != wfIssues::STATUS_SECURE && ($added == wfIssues::ISSUE_IGNOREP || $added == wfIssues::ISSUE_IGNOREC)) {
$haveIssues = wfIssues::STATUS_IGNORED;
$this->status(4, 'info', sprintf(/* translators: WordPress username. */ __("Completed checking password strength of user '%s'", 'wordfence'), $userDat->user_login));
wp_suspend_cache_addition($suspended);
private function scan_sitePages(){
if(is_multisite()){ return; } //Multisite not supported by this function yet
$this->statusIDX['sitePages'] = wordfence::statusStart("Scanning externally for malware");
$resp = wp_remote_get(site_url());
if(is_array($resp) && isset($resp['body']) && strlen($rep['body']) > 0){
$this->hoover = new wordfenceURLHoover($this->apiKey, $this->wp_version);
$this->hoover->hoover(1, $rep['body']);
$hooverResults = $this->hoover->getBaddies();
if($this->hoover->errorMsg){
wordfence::statusEndErr();
throw new Exception($this->hoover->errorMsg);
foreach($hooverResults as $idString => $hresults){
foreach($hresults as $result){
if(! in_array($result['URL'], $badURLs)){
$badURLs[] = $result['URL'];
if(sizeof($badURLs) > 0){
$this->addIssue('badSitePage', 1, 'badSitePage1', 'badSitePage1', "Your home page contains a malware URL");
private function scan_diskSpace() {
$this->statusIDX['diskSpace'] = wfIssues::statusStart(__('Scanning to check available disk space', 'wordfence'));
$this->scanController->startStage(wfScanner::STAGE_SERVER_STATE);
$total = function_exists('disk_total_space')?@disk_total_space('.'):false;
$free = function_exists('disk_free_space')?@disk_free_space('.'):false; //Normally false if unreadable but can return 0 on some hosts even when there's space available
$this->status(2, 'info', __('Unable to access available disk space information', 'wordfence'));
wfIssues::statusEnd($this->statusIDX['diskSpace'], wfIssues::STATUS_SECURE);
$this->scanController->completeStage(wfScanner::STAGE_SERVER_STATE, wfIssues::STATUS_SECURE);
$this->status(2, 'info', sprintf(
/* translators: 1. Number of bytes. 2. Number of bytes. */
__('Total disk space: %1$s -- Free disk space: %2$s', 'wordfence'),
wfUtils::formatBytes($total),
wfUtils::formatBytes($free)
$freeMegs = round($free / 1024 / 1024, 2);
$this->status(2, 'info', sprintf(/* translators: Number of bytes. */ __('The disk has %s MB available', 'wordfence'), $freeMegs));
$level = wfIssues::SEVERITY_CRITICAL;
} else if ($freeMegs < 20) {
$level = wfIssues::SEVERITY_HIGH;
wfIssues::statusEnd($this->statusIDX['diskSpace'], wfIssues::STATUS_SECURE);
$this->scanController->completeStage(wfScanner::STAGE_SERVER_STATE, wfIssues::STATUS_SECURE);
$haveIssues = wfIssues::STATUS_SECURE;
$added = $this->addIssue('diskSpace',
sprintf(/* translators: Number of bytes. */ __('You have %s disk space remaining', 'wordfence'), wfUtils::formatBytes($free)),
sprintf(/* translators: Number of bytes. */ __('You only have %s of your disk space remaining. Please free up disk space or your website may stop serving requests.', 'wordfence'), wfUtils::formatBytes($free)),
array('spaceLeft' => wfUtils::formatBytes($free))
if ($added == wfIssues::ISSUE_ADDED || $added == wfIssues::ISSUE_UPDATED) {
$haveIssues = wfIssues::STATUS_PROBLEM;
} else if ($haveIssues != wfIssues::STATUS_SECURE && ($added == wfIssues::ISSUE_IGNOREP || $added == wfIssues::ISSUE_IGNOREC)) {
$haveIssues = wfIssues::STATUS_IGNORED;
wfIssues::statusEnd($this->statusIDX['diskSpace'], $haveIssues);
$this->scanController->completeStage(wfScanner::STAGE_SERVER_STATE, $haveIssues);
private function scan_wafStatus() {
$this->statusIDX['wafStatus'] = wfIssues::statusStart(__('Checking Web Application Firewall status', 'wordfence'));
$this->scanController->startStage(wfScanner::STAGE_SERVER_STATE);
$haveIssues = wfIssues::STATUS_SECURE;
$firewall = new wfFirewall();
if (wfConfig::get('waf_status') !== $firewall->firewallMode() && $firewall->firewallMode() == wfFirewall::FIREWALL_MODE_DISABLED) {
$added = $this->addIssue('wafStatus',
wfIssues::SEVERITY_CRITICAL,
'wafStatus' . $firewall->firewallMode(),
__('Web Application Firewall is disabled', 'wordfence'),
sprintf(/* translators: Support URL. */ __('Wordfence\'s Web Application Firewall has been unexpectedly disabled. If you see a notice at the top of the Wordfence admin pages that says "The Wordfence Web Application Firewall cannot run," click the link in that message to rebuild the configuration. If this does not work, you may need to fix file permissions. <a href="%s" target="_blank" rel="noopener noreferrer">More Details<span class="screen-reader-text"> (' . esc_html__('opens in new tab', 'wordfence') . ')</span></a>', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_SCAN_RESULT_WAF_DISABLED)),
array('wafStatus' => $firewall->firewallMode(), 'wafStatusDisplay' => $firewall->displayText())
if ($added == wfIssues::ISSUE_ADDED || $added == wfIssues::ISSUE_UPDATED) {
$haveIssues = wfIssues::STATUS_PROBLEM;
} else if ($haveIssues != wfIssues::STATUS_SECURE && ($added == wfIssues::ISSUE_IGNOREP || $added == wfIssues::ISSUE_IGNOREC)) {
$haveIssues = wfIssues::STATUS_IGNORED;
wfIssues::statusEnd($this->statusIDX['wafStatus'], $haveIssues);
$this->scanController->completeStage(wfScanner::STAGE_SERVER_STATE, $haveIssues);
private function scan_oldVersions_init() {
$this->statusIDX['oldVersions'] = wfIssues::statusStart(__("Scanning for old themes, plugins and core files", 'wordfence'));
$this->scanController->startStage(wfScanner::STAGE_VULNERABILITY_SCAN);
$this->updateCheck = new wfUpdateCheck();
$this->updateCheck->checkCoreVulnerabilities();
$this->updateCheck->checkPluginVulnerabilities();
$this->updateCheck->checkThemeVulnerabilities();
$this->updateCheck->checkAllUpdates(!$this->isFullScan());
foreach ($this->updateCheck->getPluginSlugs() as $slug) {
$this->pluginRepoStatus[$slug] = false;
//Strip plugins that have a pending update
if (count($this->updateCheck->getPluginUpdates()) > 0) {
foreach ($this->updateCheck->getPluginUpdates() as $plugin) {
if (!empty($plugin['slug'])) {
unset($this->pluginRepoStatus[$plugin['slug']]);
private function scan_oldVersions_main() {
if (!$this->isFullScan()) {
if (!function_exists('plugins_api')) {
require_once(ABSPATH . 'wp-admin/includes/plugin-install.php');
foreach ($this->pluginRepoStatus as $slug => $status) {
$result = plugins_api('plugin_information', array(
'short_description' => false,
'active_installs' => false,
unset($result->versions);
unset($result->screenshots);
$this->pluginRepoStatus[$slug] = $result;
error_log(sprintf('Caught exception while attempting to refresh update status for slug %s: %s', $slug, $e->getMessage()));
$this->pluginRepoStatus[$slug] = false;
wfConfig::set(wfUpdateCheck::LAST_UPDATE_CHECK_ERROR_KEY, sprintf('%s [%s]', $e->getMessage(), $slug), false);
wfConfig::set(wfUpdateCheck::LAST_UPDATE_CHECK_ERROR_SLUG_KEY, $slug, false);
error_log(sprintf('Caught error while attempting to refresh update status for slug %s: %s', $slug, $t->getMessage()));
$this->pluginRepoStatus[$slug] = false;
wfConfig::set(wfUpdateCheck::LAST_UPDATE_CHECK_ERROR_KEY, sprintf('%s [%s]', $t->getMessage(), $slug), false);
wfConfig::set(wfUpdateCheck::LAST_UPDATE_CHECK_ERROR_SLUG_KEY, $slug, false);
private function scan_oldVersions_finish() {
$haveIssues = wfIssues::STATUS_SECURE;
if (!$this->isFullScan()) {
$this->deleteNewIssues(array('wfUpgradeError', 'wfUpgrade', 'wfPluginUpgrade', 'wfThemeUpgrade'));
if ($lastError = wfConfig::get(wfUpdateCheck::LAST_UPDATE_CHECK_ERROR_KEY)) {
$lastSlug = wfConfig::get(wfUpdateCheck::LAST_UPDATE_CHECK_ERROR_SLUG_KEY);
$longMsg = sprintf(/* translators: error message. */ __("The update check performed during the scan encountered an error: %s", 'wordfence'), esc_html($lastError));
if ($lastSlug === false) {
$longMsg .= ' ' . __('Wordfence cannot detect if the installed plugins and themes are up to date. This might be caused by a PHP compatibility issue in one or more plugins/themes.', 'wordfence');
$longMsg .= ' ' . __('Wordfence cannot detect if this plugin/theme is up to date. This might be caused by a PHP compatibility issue in the plugin.', 'wordfence');
$longMsg .= ' ' . sprintf(
/* translators: Support URL. */
__('<a href="%s" target="_blank" rel="noopener noreferrer">Get more information.<span class="screen-reader-text"> (' . esc_html__('opens in new tab', 'wordfence') . ')</span></a>', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_SCAN_RESULT_UPDATE_CHECK_FAILED));
$ignoreKey = ($lastSlug === false ? 'wfUpgradeErrorGeneral' : sprintf('wfUpgradeError-%s', $lastSlug));
$added = $this->addIssue(
wfIssues::SEVERITY_MEDIUM,
($lastSlug === false ? __("Update Check Encountered Error", 'wordfence') : sprintf(/* translators: plugin/theme slug. */ __("Update Check Encountered Error on '%s'", 'wordfence'), esc_html($lastSlug))),
if ($added == wfIssues::ISSUE_ADDED || $added == wfIssues::ISSUE_UPDATED) {
$haveIssues = wfIssues::STATUS_PROBLEM;
else if ($haveIssues != wfIssues::STATUS_PROBLEM && ($added == wfIssues::ISSUE_IGNOREP || $added == wfIssues::ISSUE_IGNOREC)) {
$haveIssues = wfIssues::STATUS_IGNORED;
// WordPress core updates needed
if ($this->updateCheck->needsCoreUpdate()) {
$updateVersion = $this->updateCheck->getCoreUpdateVersion();
$severity = wfIssues::SEVERITY_HIGH;
$shortMsg = __("Your WordPress version is out of date", 'wordfence');
$longMsg = sprintf(/* translators: Software version. */ __("WordPress version %s is now available. Please upgrade immediately to get the latest security updates from WordPress.", 'wordfence'), esc_html($updateVersion));
$currentVulnerable = $this->updateCheck->isCoreVulnerable('current');
$edgeVulnerable = $this->updateCheck->isCoreVulnerable('edge');
if ($this->updateCheck->coreUpdatePatchAvailable()) { //Non-edge branch with available backported update
$updateVersion = $this->updateCheck->getCoreUpdatePatchVersion();
$patchVulnerable = $this->updateCheck->isCoreVulnerable('patch');
if (!$currentVulnerable && !$patchVulnerable) { //Non-edge branch, neither the current version or patch version have a known vulnerability
$severity = wfIssues::SEVERITY_MEDIUM;
$longMsg = sprintf(/* translators: Software version. */ __("WordPress version %s is now available for your site's current branch. Please upgrade immediately to get the latest fixes and compatibility updates from WordPress.", 'wordfence'), esc_html($updateVersion));