Wordfence Security – Firewall & Malware Scan - Version 3.3.4

Version Description

  • Fixed bug that caused malformed URLs to be sent to scanning server which caused errors on some installations.
  • Fixed issue that caused scans to "hang" or stall on larger sites during "Analyzing" phase when we hash files. Sites of arbitrary size can now be scanned.
  • Fixed issue that caused "plugin generated X characters of unexpected output" error during install or upgrade.
Download this release

Release Info

Developer mmaunder
Plugin Icon 128x128 Wordfence Security – Firewall & Malware Scan
Version 3.3.4
Comparing to
See all releases

Code changes from version 3.3.3 to 3.3.4

lib/wfAPI.php CHANGED
@@ -17,7 +17,7 @@ class wfAPI {
17
return $this->getURL($this->getAPIURL() . $url);
18
}
19
public function call($action, $getParams = array(), $postParams = array()){
20
- $json = $this->getURL($this->getAPIURL() . '/v' . WORDFENCE_API_VERSION . '/?' . $this->makeAPIQueryString() . '&' . http_build_query(
21
array_merge(
22
array('action' => $action),
23
$getParams
@@ -157,12 +157,19 @@ class wfAPI {
157
if(function_exists('get_bloginfo')){
158
$siteurl = get_bloginfo('siteurl');
159
}
160
- return http_build_query(array(
161
'v' => $this->wordpressVersion,
162
's' => $siteurl,
163
'k' => $this->APIKey
164
));
165
}
166
private function getAPIURL(){
167
$ssl_supported = false;
168
if(defined('CURL_VERSION_SSL') && function_exists('curl_version')){
17
return $this->getURL($this->getAPIURL() . $url);
18
}
19
public function call($action, $getParams = array(), $postParams = array()){
20
+ $json = $this->getURL($this->getAPIURL() . '/v' . WORDFENCE_API_VERSION . '/?' . $this->makeAPIQueryString() . '&' . self::buildQuery(
21
array_merge(
22
array('action' => $action),
23
$getParams
157
if(function_exists('get_bloginfo')){
158
$siteurl = get_bloginfo('siteurl');
159
}
160
+ return self::buildQuery(array(
161
'v' => $this->wordpressVersion,
162
's' => $siteurl,
163
'k' => $this->APIKey
164
));
165
}
166
+ private function buildQuery($data){
167
+ if(version_compare(phpversion(), '5.1.2', '>=')){
168
+ return http_build_query($data, '', '&'); //arg_separator parameter was only added in PHP 5.1.2. We do this because some PHP.ini's have arg_separator.output set to '&'
169
+ } else {
170
+ return http_build_query($data);
171
+ }
172
+ }
173
private function getAPIURL(){
174
$ssl_supported = false;
175
if(defined('CURL_VERSION_SSL') && function_exists('curl_version')){
lib/wfScanEngine.php CHANGED
@@ -21,7 +21,7 @@ class wfScanEngine {
21
private $apiKey = false;
22
private $startTime = 0;
23
private $scanStep = 0;
24
- private $maxExecTime = 10; //If more than $maxExecTime has elapsed since last check, fork a new scan process and continue
25
private $publicScanEnabled = false;
26
private $fileContentsResults = false;
27
private $scanner = false;
@@ -50,8 +50,10 @@ class wfScanEngine {
50
include('wfDict.php'); //$dictWords
51
$this->dictWords = $dictWords;
52
$this->jobList[] = 'publicSite';
53
- $this->jobList[] = 'knownFiles';
54
- foreach(array('fileContents', 'posts', 'comments', 'passwds', 'dns', 'diskSpace', 'oldVersions') as $scanType){
55
if(wfConfig::get('scansEnabled_' . $scanType)){
56
if(method_exists($this, 'scan_' . $scanType . '_init')){
57
foreach(array('init', 'main', 'finish') as $op){ $this->jobList[] = $scanType . '_' . $op; };
@@ -148,10 +150,9 @@ class wfScanEngine {
148
sleep(2); //enough time to read the message before it scrolls off.
149
}
150
}
151
- private function scan_knownFiles(){
152
$this->status(1, 'info', "Contacting Wordfence to initiate scan");
153
$this->api->call('log_scan', array(), array());
154
- $this->hasher = new wordfenceHash(strlen(ABSPATH));
155
$baseWPStuff = array( '.htaccess', 'index.php', 'license.txt', 'readme.html', 'wp-activate.php', 'wp-admin', 'wp-app.php', 'wp-blog-header.php', 'wp-comments-post.php', 'wp-config-sample.php', 'wp-content', 'wp-cron.php', 'wp-includes', 'wp-links-opml.php', 'wp-load.php', 'wp-login.php', 'wp-mail.php', 'wp-pass.php', 'wp-register.php', 'wp-settings.php', 'wp-signup.php', 'wp-trackback.php', 'xmlrpc.php');
156
$baseContents = scandir(ABSPATH);
157
if(! is_array($baseContents)){
@@ -161,12 +162,13 @@ class wfScanEngine {
161
if($scanOutside){
162
wordfence::status(2, 'info', "Including files that are outside the WordPress installation in the scan.");
163
}
164
foreach($baseContents as $file){ //Only include base files less than a meg that are files.
165
$fullFile = rtrim(ABSPATH, '/') . '/' . $file;
166
if($scanOutside){
167
- $includeInScan[] = $file;
168
} else if(in_array($file, $baseWPStuff) || (@is_file($fullFile) && @is_readable($fullFile) && (! wfUtils::fileTooBig($fullFile)) ) ){
169
- $includeInScan[] = $file;
170
}
171
}
172
@@ -175,12 +177,12 @@ class wfScanEngine {
175
}
176
$this->status(2, 'info', "Getting plugin list from WordPress");
177
$pluginData = get_plugins();
178
- $plugins = array();
179
foreach($pluginData as $key => $data){
180
if(preg_match('/^([^\/]+)\//', $key, $matches)){
181
$pluginDir = $matches[1];
182
$pluginFullDir = "wp-content/plugins/" . $pluginDir;
183
- $plugins[$key] = array(
184
'Name' => $data['Name'],
185
'Version' => $data['Version'],
186
'ShortDir' => $pluginDir,
@@ -189,20 +191,20 @@ class wfScanEngine {
189
}
190
}
191
192
- $this->status(2, 'info', "Found " . sizeof($plugins) . " plugins");
193
- $this->i->updateSummaryItem('totalPlugins', sizeof($plugins));
194
195
if(! function_exists( 'get_themes')){
196
require_once ABSPATH . '/wp-includes/theme.php';
197
}
198
$this->status(2, 'info', "Getting theme list from WordPress");
199
$themeData = get_themes();
200
- $themes = array();
201
foreach($themeData as $themeName => $themeData){
202
if(preg_match('/\/([^\/]+)#x2F;', $themeData['Stylesheet Dir'], $matches)){
203
$shortDir = $matches[1]; //e.g. evo4cms
204
$fullDir = substr($themeData['Stylesheet Dir'], strlen(ABSPATH)); //e.g. wp-content/themes/evo4cms
205
- $themes[$themeName] = array(
206
'Name' => $themeData['Name'],
207
'Version' => $themeData['Version'],
208
'ShortDir' => $shortDir,
@@ -210,15 +212,21 @@ class wfScanEngine {
210
);
211
}
212
}
213
- $this->status(2, 'info', "Found " . sizeof($themes) . " themes");
214
- $this->i->updateSummaryItem('totalThemes', sizeof($themes));
215
216
- $this->hasher->run(ABSPATH, $includeInScan, $themes, $plugins, $this); //Include this so we can call addIssue and ->api->
217
$this->i->updateSummaryItem('totalData', wfUtils::formatBytes($this->hasher->totalData));
218
$this->i->updateSummaryItem('totalFiles', $this->hasher->totalFiles);
219
$this->i->updateSummaryItem('totalDirs', $this->hasher->totalDirs);
220
$this->i->updateSummaryItem('linesOfPHP', $this->hasher->linesOfPHP);
221
$this->i->updateSummaryItem('linesOfJCH', $this->hasher->linesOfJCH);
222
}
223
private function scan_fileContents_init(){
224
$this->statusIDX['infect'] = wordfence::statusStart('Scanning file contents for infections and vulnerabilities');
21
private $apiKey = false;
22
private $startTime = 0;
23
private $scanStep = 0;
24
+ public $maxExecTime = 10; //If more than $maxExecTime has elapsed since last check, fork a new scan process and continue
25
private $publicScanEnabled = false;
26
private $fileContentsResults = false;
27
private $scanner = false;
50
include('wfDict.php'); //$dictWords
51
$this->dictWords = $dictWords;
52
$this->jobList[] = 'publicSite';
53
+ $this->jobList[] = 'knownFiles_init';
54
+ $this->jobList[] = 'knownFiles_main';
55
+ $this->jobList[] = 'knownFiles_finish';
56
+ foreach(array('knownFiles', 'fileContents', 'posts', 'comments', 'passwds', 'dns', 'diskSpace', 'oldVersions') as $scanType){
57
if(wfConfig::get('scansEnabled_' . $scanType)){
58
if(method_exists($this, 'scan_' . $scanType . '_init')){
59
foreach(array('init', 'main', 'finish') as $op){ $this->jobList[] = $scanType . '_' . $op; };
150
sleep(2); //enough time to read the message before it scrolls off.
151
}
152
}
153
+ private function scan_knownFiles_init(){
154
$this->status(1, 'info', "Contacting Wordfence to initiate scan");
155
$this->api->call('log_scan', array(), array());
156
$baseWPStuff = array( '.htaccess', 'index.php', 'license.txt', 'readme.html', 'wp-activate.php', 'wp-admin', 'wp-app.php', 'wp-blog-header.php', 'wp-comments-post.php', 'wp-config-sample.php', 'wp-content', 'wp-cron.php', 'wp-includes', 'wp-links-opml.php', 'wp-load.php', 'wp-login.php', 'wp-mail.php', 'wp-pass.php', 'wp-register.php', 'wp-settings.php', 'wp-signup.php', 'wp-trackback.php', 'xmlrpc.php');
157
$baseContents = scandir(ABSPATH);
158
if(! is_array($baseContents)){
162
if($scanOutside){
163
wordfence::status(2, 'info', "Including files that are outside the WordPress installation in the scan.");
164
}
165
+ $includeInKnownFilesScan = array();
166
foreach($baseContents as $file){ //Only include base files less than a meg that are files.
167
$fullFile = rtrim(ABSPATH, '/') . '/' . $file;
168
if($scanOutside){
169
+ $includeInKnownFilesScan[] = $file;
170
} else if(in_array($file, $baseWPStuff) || (@is_file($fullFile) && @is_readable($fullFile) && (! wfUtils::fileTooBig($fullFile)) ) ){
171
+ $includeInKnownFilesScan[] = $file;
172
}
173
}
174
177
}
178
$this->status(2, 'info', "Getting plugin list from WordPress");
179
$pluginData = get_plugins();
180
+ $knownFilesPlugins = array();
181
foreach($pluginData as $key => $data){
182
if(preg_match('/^([^\/]+)\//', $key, $matches)){
183
$pluginDir = $matches[1];
184
$pluginFullDir = "wp-content/plugins/" . $pluginDir;
185
+ $knownFilesPlugins[$key] = array(
186
'Name' => $data['Name'],
187
'Version' => $data['Version'],
188
'ShortDir' => $pluginDir,
191
}
192
}
193
194
+ $this->status(2, 'info', "Found " . sizeof($knownFilesPlugins) . " plugins");
195
+ $this->i->updateSummaryItem('totalPlugins', sizeof($knownFilesPlugins));
196
197
if(! function_exists( 'get_themes')){
198
require_once ABSPATH . '/wp-includes/theme.php';
199
}
200
$this->status(2, 'info', "Getting theme list from WordPress");
201
$themeData = get_themes();
202
+ $knownFilesThemes = array();
203
foreach($themeData as $themeName => $themeData){
204
if(preg_match('/\/([^\/]+)#x2F;', $themeData['Stylesheet Dir'], $matches)){
205
$shortDir = $matches[1]; //e.g. evo4cms
206
$fullDir = substr($themeData['Stylesheet Dir'], strlen(ABSPATH)); //e.g. wp-content/themes/evo4cms
207
+ $knownFilesThemes[$themeName] = array(
208
'Name' => $themeData['Name'],
209
'Version' => $themeData['Version'],
210
'ShortDir' => $shortDir,
212
);
213
}
214
}
215
+ $this->status(2, 'info', "Found " . sizeof($knownFilesThemes) . " themes");
216
+ $this->i->updateSummaryItem('totalThemes', sizeof($knownFilesThemes));
217
218
+ $this->hasher = new wordfenceHash(strlen(ABSPATH), ABSPATH, $includeInKnownFilesScan, $knownFilesThemes, $knownFilesPlugins, $this);
219
+ }
220
+ private function scan_knownFiles_main(){
221
+ $this->hasher->run($this); //Include this so we can call addIssue and ->api->
222
$this->i->updateSummaryItem('totalData', wfUtils::formatBytes($this->hasher->totalData));
223
$this->i->updateSummaryItem('totalFiles', $this->hasher->totalFiles);
224
$this->i->updateSummaryItem('totalDirs', $this->hasher->totalDirs);
225
$this->i->updateSummaryItem('linesOfPHP', $this->hasher->linesOfPHP);
226
$this->i->updateSummaryItem('linesOfJCH', $this->hasher->linesOfJCH);
227
+ $this->hasher = false;
228
+ }
229
+ private function scan_knownFiles_finish(){
230
}
231
private function scan_fileContents_init(){
232
$this->statusIDX['infect'] = wordfence::statusStart('Scanning file contents for infections and vulnerabilities');
lib/wordfenceClass.php CHANGED
@@ -639,8 +639,10 @@ class wordfence {
639
wp_clear_scheduled_hook('wordfence_start_scheduled_scan'); //Unschedule legacy scans without args
640
641
$schedArgs = wfConfig::get_ser('schedScanArgs', array());
642
- foreach($schedArgs as $futureTime){
643
- wp_clear_scheduled_hook('wordfence_start_scheduled_scan', array($futureTime));
644
}
645
wfConfig::set_ser('schedScanArgs', array());
646
}
639
wp_clear_scheduled_hook('wordfence_start_scheduled_scan'); //Unschedule legacy scans without args
640
641
$schedArgs = wfConfig::get_ser('schedScanArgs', array());
642
+ if(is_array($schedArgs)){
643
+ foreach($schedArgs as $futureTime){
644
+ wp_clear_scheduled_hook('wordfence_start_scheduled_scan', array($futureTime));
645
+ }
646
}
647
wfConfig::set_ser('schedScanArgs', array());
648
}
lib/wordfenceHash.php CHANGED
@@ -1,29 +1,39 @@
1
<?php
2
require_once('wordfenceClass.php');
3
class wordfenceHash {
4
- //Begin serialized vars
5
private $whitespace = array("\n","\r","\t"," ");
6
- public $totalData = 0; //To do a sanity check, don't use 'du' because it gets sparse files wrong and reports blocks used on disk. Use : find . -type f -ls | awk '{total += $7} END {print total}'
7
public $totalFiles = 0;
8
public $totalDirs = 0;
9
public $linesOfPHP = 0;
10
public $linesOfJCH = 0; //lines of HTML, CSS and javascript
11
- public $striplen = 0;
12
- private $engine = false;
13
- private $db = false;
14
private $coreEnabled = false;
15
- private $themesEnabled = false;
16
private $pluginsEnabled = false;
17
private $malwareEnabled = false;
18
private $malwareData = "";
19
- private $possibleMalware = array();
20
- private $status = array();
21
private $haveIssues = array();
22
- public function __construct($striplen){
23
$this->striplen = $striplen;
24
- }
25
- public function run($path, $only, $themes, $plugins, $engine){ //base path and 'only' is a list of files and dirs in the bast that are the only ones that should be processed. Everything else in base is ignored. If only is empty then everything is processed.
26
- $this->engine = $engine;
27
if(wfConfig::get('scansEnabled_core')){
28
$this->coreEnabled = true;
29
}
@@ -39,7 +49,7 @@ class wordfenceHash {
39
$this->db = new wfDB();
40
41
//Doing a delete for now. Later we can optimize this to only scan modified files.
42
- //$this->db->query("update " . $this->db->prefix() . "wfFileMods set oldMD5 = newMD5");
43
$this->db->query("delete from " . $this->db->prefix() . "wfFileMods");
44
$fetchCoreHashesStatus = wordfence::statusStart("Fetching core, theme and plugin file signatures from Wordfence");
45
$dataArr = $engine->api->binCall('get_known_files', json_encode(array(
@@ -75,14 +85,13 @@ class wordfenceHash {
75
wordfence::statusEnd($malwarePrefixStatus, false, true);
76
}
77
78
- if($path[strlen($path) - 1] != '/'){
79
- $path .= '/';
80
}
81
if(! is_readable($path)){
82
- throw new Exception("Could not read directory $path to do scan.");
83
exit();
84
}
85
- $files = scandir($path);
86
$this->haveIssues = array(
87
'core' => false,
88
'themes' => false,
@@ -93,11 +102,26 @@ class wordfenceHash {
93
if($this->themesEnabled){ $this->status['themes'] = wordfence::statusStart("Comparing open source themes against WordPress.org originals"); } else { wordfence::statusDisabled("Skipping theme scan"); }
94
if($this->pluginsEnabled){ $this->status['plugins'] = wordfence::statusStart("Comparing plugins against WordPress.org originals"); } else { wordfence::statusDisabled("Skipping plugin scan"); }
95
if($this->malwareEnabled){ $this->status['malware'] = wordfence::statusStart("Scanning for known malware files"); } else { wordfence::statusDisabled("Skipping malware scan"); }
96
foreach($files as $file){
97
- if(sizeof($only) > 0 && (! in_array($file, $only))){
98
continue;
99
}
100
- $file = $path . $file;
101
wordfence::status(4, 'info', "Hashing item in base dir: $file");
102
$this->_dirHash($file);
103
}
@@ -121,7 +145,7 @@ class wordfenceHash {
121
$this->engine->addIssue(
122
'file',
123
1,
124
- $path . $file,
125
$md5,
126
'This file is suspected malware: ' . $file,
127
"This file's signature matches a known malware file. The title of the malware is '" . $name . "'. Immediately inspect this file using the 'View' option below and consider deleting it from your server.",
@@ -166,6 +190,19 @@ class wordfenceHash {
166
}
167
private function processFile($realFile){
168
$file = substr($realFile, $this->striplen);
169
if(wfUtils::fileTooBig($realFile)){
170
wordfence::status(4, 'info', "Skipping file larger than max size: $realFile");
171
return;
1
<?php
2
require_once('wordfenceClass.php');
3
class wordfenceHash {
4
private $whitespace = array("\n","\r","\t"," ");
5
+ private $engine = false;
6
+ private $db = false;
7
+ private $startTime = false;
8
+
9
+ //Begin serialized vars
10
+ public $striplen = 0;
11
public $totalFiles = 0;
12
public $totalDirs = 0;
13
+ public $totalData = 0; //To do a sanity check, don't use 'du' because it gets sparse files wrong and reports blocks used on disk. Use : find . -type f -ls | awk '{total += $7} END {print total}'
14
public $linesOfPHP = 0;
15
public $linesOfJCH = 0; //lines of HTML, CSS and javascript
16
+ public $stoppedOnFile = false;
17
private $coreEnabled = false;
18
private $pluginsEnabled = false;
19
+ private $themesEnabled = false;
20
private $malwareEnabled = false;
21
+ private $knownFiles = false;
22
private $malwareData = "";
23
private $haveIssues = array();
24
+ private $status = array();
25
+ private $possibleMalware = array();
26
+ private $path = false;
27
+ private $only = false;
28
+ private $totalForks = 0;
29
+
30
+ public function __construct($striplen, $path, $only, $themes, $plugins, $engine){
31
$this->striplen = $striplen;
32
+ $this->path = $path;
33
+ $this->only = $only;
34
+
35
+ $this->startTime = microtime(true);
36
+
37
if(wfConfig::get('scansEnabled_core')){
38
$this->coreEnabled = true;
39
}
49
$this->db = new wfDB();
50
51
//Doing a delete for now. Later we can optimize this to only scan modified files.
52
+ //$this->db->query("update " . $this->db->prefix() . "wfFileMods set oldMD5 = newMD5");
53
$this->db->query("delete from " . $this->db->prefix() . "wfFileMods");
54
$fetchCoreHashesStatus = wordfence::statusStart("Fetching core, theme and plugin file signatures from Wordfence");
55
$dataArr = $engine->api->binCall('get_known_files', json_encode(array(
85
wordfence::statusEnd($malwarePrefixStatus, false, true);
86
}
87
88
+ if($this->path[strlen($this->path) - 1] != '/'){
89
+ $this->path .= '/';
90
}
91
if(! is_readable($path)){
92
+ throw new Exception("Could not read directory " . $this->path . " to do scan.");
93
exit();
94
}
95
$this->haveIssues = array(
96
'core' => false,
97
'themes' => false,
102
if($this->themesEnabled){ $this->status['themes'] = wordfence::statusStart("Comparing open source themes against WordPress.org originals"); } else { wordfence::statusDisabled("Skipping theme scan"); }
103
if($this->pluginsEnabled){ $this->status['plugins'] = wordfence::statusStart("Comparing plugins against WordPress.org originals"); } else { wordfence::statusDisabled("Skipping plugin scan"); }
104
if($this->malwareEnabled){ $this->status['malware'] = wordfence::statusStart("Scanning for known malware files"); } else { wordfence::statusDisabled("Skipping malware scan"); }
105
+ }
106
+ public function __sleep(){
107
+ return array('striplen', 'totalFiles', 'totalDirs', 'totalData', 'linesOfPHP', 'linesOfJCH', 'stoppedOnFile', 'coreEnabled', 'pluginsEnabled', 'themesEnabled', 'malwareEnabled', 'knownFiles', 'malwareData', 'haveIssues', 'status', 'possibleMalware', 'path', 'only', 'totalForks');
108
+ }
109
+ public function __wakeup(){
110
+ $this->db = new wfDB();
111
+ $this->startTime = microtime(true);
112
+ $this->totalForks++;
113
+ }
114
+ public function run($engine){ //base path and 'only' is a list of files and dirs in the bast that are the only ones that should be processed. Everything else in base is ignored. If only is empty then everything is processed.
115
+ if($this->totalForks > 1000){
116
+ throw new Exception("Wordfence file scanner detected a possible infinite loop. Exiting on file: " . $this->stoppedOnFile);
117
+ }
118
+ $this->engine = $engine;
119
+ $files = scandir($this->path);
120
foreach($files as $file){
121
+ if(sizeof($this->only) > 0 && (! in_array($file, $this->only))){
122
continue;
123
}
124
+ $file = $this->path . $file;
125
wordfence::status(4, 'info', "Hashing item in base dir: $file");
126
$this->_dirHash($file);
127
}
145
$this->engine->addIssue(
146
'file',
147
1,
148
+ $this->path . $file,
149
$md5,
150
'This file is suspected malware: ' . $file,
151
"This file's signature matches a known malware file. The title of the malware is '" . $name . "'. Immediately inspect this file using the 'View' option below and consider deleting it from your server.",
190
}
191
private function processFile($realFile){
192
$file = substr($realFile, $this->striplen);
193
+ if( (! $this->stoppedOnFile) && microtime(true) - $this->startTime > $this->engine->maxExecTime){ //max X seconds but don't allow fork if we're looking for the file we stopped on. Search mode is VERY fast.
194
+ $this->stoppedOnFile = $file;
195
+ $this->engine->fork();
196
+ //exits
197
+ }
198
+
199
+ //Put this after the fork, that way we will at least scan one more file after we fork if it takes us more than 10 seconds to search for the stoppedOnFile
200
+ if($this->stoppedOnFile && $file != $this->stoppedOnFile){
201
+ return;
202
+ } else if($this->stoppedOnFile && $file == $this->stoppedOnFile){
203
+ $this->stoppedOnFile = false; //Continue scanning
204
+ }
205
+
206
if(wfUtils::fileTooBig($realFile)){
207
wordfence::status(4, 'info', "Skipping file larger than max size: $realFile");
208
return;
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: mmaunder
3
Tags: wordpress, security, wordpress security, security plugin, secure, anti-virus, malware, firewall, antivirus, virus, google safe browsing, phishing, scrapers, hacking, wordfence, securty, secrity, secure
4
Requires at least: 3.3.1
5
Tested up to: 3.4.2
6
- Stable tag: 3.3.3
7
8
Wordfence Security is a free enterprise class security plugin that includes a firewall, virus scanning, real-time traffic with geolocation and more.
9
@@ -153,6 +153,11 @@ or a theme, because often these have been updated to fix a security hole.
153
5. If you're technically minded, this is the under-the-hood view of Wordfence options where you can fine-tune your security settings.
154
155
== Changelog ==
156
= 3.3.3 =
157
* Fixed errors caused by ini_set being disabled on certain servers.
158
* Removed error logging messages in certain cases because some badly configured hosts write these errors to the web browser.
3
Tags: wordpress, security, wordpress security, security plugin, secure, anti-virus, malware, firewall, antivirus, virus, google safe browsing, phishing, scrapers, hacking, wordfence, securty, secrity, secure
4
Requires at least: 3.3.1
5
Tested up to: 3.4.2
6
+ Stable tag: 3.3.4
7
8
Wordfence Security is a free enterprise class security plugin that includes a firewall, virus scanning, real-time traffic with geolocation and more.
9
153
5. If you're technically minded, this is the under-the-hood view of Wordfence options where you can fine-tune your security settings.
154
155
== Changelog ==
156
+ = 3.3.4 =
157
+ * Fixed bug that caused malformed URLs to be sent to scanning server which caused errors on some installations.
158
+ * Fixed issue that caused scans to "hang" or stall on larger sites during "Analyzing" phase when we hash files. Sites of arbitrary size can now be scanned.
159
+ * Fixed issue that caused "plugin generated X characters of unexpected output" error during install or upgrade.
160
+
161
= 3.3.3 =
162
* Fixed errors caused by ini_set being disabled on certain servers.
163
* Removed error logging messages in certain cases because some badly configured hosts write these errors to the web browser.
wordfence.php CHANGED
@@ -4,10 +4,10 @@ Plugin Name: Wordfence Security
4
Plugin URI: http://wordfence.com/
5
Description: Wordfence Security - Anti-virus and Firewall security plugin for WordPress
6
Author: Mark Maunder
7
- Version: 3.3.3
8
Author URI: http://wordfence.com/
9
*/
10
- define('WORDFENCE_VERSION', '3.3.3');
11
add_action('activated_plugin','wordfence_save_activation_error'); function wordfence_save_activation_error(){ update_option('wf_plugin_act_error', ob_get_contents()); }
12
if(! defined('WORDFENCE_VERSIONONLY_MODE')){
13
if((int) @ini_get('memory_limit') < 64){
4
Plugin URI: http://wordfence.com/
5
Description: Wordfence Security - Anti-virus and Firewall security plugin for WordPress
6
Author: Mark Maunder
7
+ Version: 3.3.4
8
Author URI: http://wordfence.com/
9
*/
10
+ define('WORDFENCE_VERSION', '3.3.4');
11
add_action('activated_plugin','wordfence_save_activation_error'); function wordfence_save_activation_error(){ update_option('wf_plugin_act_error', ob_get_contents()); }
12
if(! defined('WORDFENCE_VERSIONONLY_MODE')){
13
if((int) @ini_get('memory_limit') < 64){