General security

In-Depth WordPress Security

June 8, 2012 by Scott Miller

Note: the following suggestions are at your own risk! This article assumes some level of understanding of what changes are being suggested.

WordPress is the most popular CMS used for many commercial websites as well as hobbyist sites. The popularity of WordPress also brings the software to the front as a target by attackers. Lax security and an over-trust of many free plugins and themes leads to many sites being easily compromised. Several steps can be taken to increase the security of hosting and running WordPress.

Changes in wp-config.php

One easy change is to require HTTPS for the WordPress login and Dashboard area.

To enable and require HTTPS for the WordPress login and WordPress Dashboard area, put the following in wp-config.php:

define(‘FORCE_SSL_ADMIN’, true);

With this enabled, visiting the login URL of WordPress (Ex: ) will automatically redirect to HTTPS and retain the HTTPS session while logged in to the Dashboard.

Curiously, many large corporate WordPress sites have their login page and Dashboard in clear text over HTTP and are not using this above option. Ex: ; ; ; ; and others (eek!). In this case all it takes is an employee logging in over coffee shop wifi for the credentials to be stolen or other Dashboard activity be intercepted.

Consider further protecting the login page for your blog by requiring a second factor authentication such as Yubikey ( ), Google Authenticator ( ), and/or Apache server auth for another layer of security.

Another suggested change in wp-config.php is to add some salt. Visit the url and copy/paste the provided salts to your wp-config.php. This will help add some security to the authenticated cookies when logged in to manage the site or blog.


define(‘AUTH_KEY’,     ‘{[z`YW,!7tE&f]V.R<h>*_u#`SHm^!4S-0d7)GZ|M)=DK|]@^cuoLeh*+XA9;h%|’);
define(‘SECURE_AUTH_KEY’, ‘r(1n%/%NA?uZEzS# PD 8R^3JJyj])kG2#uHzTGs#C1OBGzAu$ctp`vrk-!Ly<eq’);
define(‘LOGGED_IN_KEY’,    ‘(aG5!neqXT?XT|tz(p{$<[m=xMF`1P&[!`K)0[brRC7JsJ6G&;%Ne:w *#/a^|<,’);
define(‘NONCE_KEY’,     ‘XuNO_]r_<&TwO!RoSp|vEXi?$vF#gD8>WS-`F`BZ!-iN=@(V*Nr$LVa3W0^,*A/`’);
define(‘AUTH_SALT’,     ‘cCKSOF2JkI!%5qJ`8Ad6P`+ n6-#nd4jJlVplj]x,~:+Z3O09;X#B|K{@&x$f/M|’);
define(‘SECURE_AUTH_SALT’, ‘Xrj~J&+s)G*TAx7;Um|e+JTVB7Y4N|I>u4RF})TB 8#>UE{OdJZhU0-|G5k LI0i’);
define(‘LOGGED_IN_SALT’, ‘A7 K==/I0qe0(,Hj7x4zzbF1<~{;:EMY1fk`/1{d.7&Xa22Q)oDN8-p-~Jz22,;(‘);
define(‘NONCE_SALT’,     ‘aSVb>|#+xqxm%=0~H|{+8|71*Gks|7}~f}]1LjW@Z7P*|hxhfm,Bxh28^fG5Kh/.’);

Information Leakage

By default, WordPress will disclose its version and other tidbits in the header of the HTML. To remove this information leakage, add the following to the bottom of the theme’s functions.php:

remove_action(‘wp_head’, ‘rsd_link’);
remove_action(‘wp_head’, ‘wlwmanifest_link’);
remove_action(‘wp_head’, ‘wp_generator’);
remove_action(‘wp_head’, ‘start_post_rel_link’);
remove_action(‘wp_head’, ‘index_rel_link’);
remove_action(‘wp_head’, ‘adjacent_posts_rel_link’);

Restrict Bad Bots

Restrict various bad ‘bots’ or crawling software often used to poke at sites with mod_rewrite. These bots are easily blocked by restricting the user-agent in the file .htaccess in the root directory of the WordPress installation. An example rewrite rule that can be used in .htaccess is:

RewriteCond %{HTTP_USER_AGENT} ADSARobot|ah-ha|almaden|aktuelles|Anarchie|amzn_assoc|ASPSeek|ASSORT|ATHENS|Atomz|attach|attache|autoemailspider
|BackWeb|Bandit|BatchFTP|bdfetch||BlackWidow|bmclient|Boston Project|BravoBrian SpiderEngine MarcoPolo|Bot|Buddy|Bullseye|bumblebee|capture|CherryPicker|ChinaClaw|CICC|clipping|Collector
|Copier|Crescent|Crescent Internet ToolPak|Custo|cyberalert|DA$|Deweb|diagem|Digger|Digimarc|DIIbot|DISCo|DISCo Pump|DISCoFinder|Download Demon|Download Wonder|Downloader|Drip|DSurf15a|DTS.Agent|EasyDL|eCatch|ecollector||Email Extractor|EirGrabber|email|EmailCollector|EmailSiphon|EmailWolf|Express WebPictures|ExtractorPro|EyeNetIE|FavOrg|fastlwspider|Favorites Sweeper|Fetch|FEZhead|FileHound|FlashGet WebWasher|FlickBot|fluffy|FrontPage|GalaxyBot|Generic|Getleft|GetRight|GetSmart|GetWeb!|GetWebPage|gigabaz
|Girafabot|Go!Zilla|Go!Zilla|Go-Ahead-Got-It|GornKer|gotit|Grabber|GrabNet|Grafula|Green Research|grub-client|Harvest|hhjhj@yahoo|Havij|hloader|HMView|HomePageSearch|http generic|HTTrack|httpdown|httrack|ia_archiver|IBM_Planetwide|Image Stripper|Image Sucker|imagefetch|IncyWincy|Indy*Library|Indy Library|informant|Ingelin|InterGET|Internet Ninja|InternetLinkagent|Internet Ninja||Iria|Irvine|JBH*agent|JetCar|JOC|JOC Web Spider|JustView|KWebGet|Lachesis|larbin|LeechFTP|LexiBot|lftp|libwww|likse|Link|Link*Sleuth|LINKS ARoMATIZED|LinkWalker|LWP|lwp-trivial|Mag-Net|Magnet|Mac Finder|Mag-Net|Mass Downloader|MCspider|Memo|Microsoft.URL|MIDown tool|Mirror|Missigua Locator|Mister PiX|MMMtoCrawl/UrlDispatcherLLL|^Mozilla$|Mozilla.*Indy|Mozilla.*NEWT|Mozilla*MSIECrawler|MS FrontPage*|MSFrontPage|MSIECrawler|MSProxy|multithreaddb|nationaldirectory|Navroad|NearSite|NetAnts
|NetCarta|NetMechanic|netprospector|NetResearchServer|NetSpider|Net Vampire|NetZIP|NetZip Downloader|NetZippy|NEWT|NICErsPRO|Nikto|Ninja|NPBot|Octopus|Offline Explorer|Offline Navigator|OpaL|Openfind|OpenTextSiteCrawler|OrangeBot|PageGrabber|Papa Foto|PackRat|pavuk|pcBrowser|PersonaPilot|Ping|PingALink|Pockey|Proxy|psbot|PSurf|puf|Pump|PushSite
|QRVA|RealDownload|Reaper|Recorder|ReGet|replacer|RepoMonkey|Robozilla|Rover|RPT-HTTPClient|Rsync|Scooter|SearchExpress|searchhippo||Second Street Research|Seeker|Shai|Siphon|sitecheck||SiteSnagger|SlySearch|SmartDownload
|SurfWalker|Szukacz|tAkeOut|tarspider|Teleport Pro|Templeton|TrueRobot|TV33_Mercator|UIowaCrawler|UtilMind|URLSpiderPro|URL_Spider_Pro|Vacuum
|vagabondo|vayala|visibilitygap|VoidEYE|vspider|Web Downloader|w3mir|Web Data Extractor|Web Image Collector|Web Sucker|Wweb|WebAuto|WebBandit||Webclipping|webcollage|webcollector|WebCopier
|webcraft@bea|webdevil|webdownloader|Webdup|WebEMailExtrac|WebFetch|WebGo IS|WebHook|Webinator|WebLeacher|WEBMASTERS|WebMiner|WebMirror|webmole|WebReaper|WebSauger
|Website|Website eXtractor|Website Quester|WebSnake|Webster|WebStripper|websucker|webvac|webwalk|webweasel|WebWhacker|WebZIP|Wget
|Whacker|whizbang|WhosTalking|Widow|WISEbot|WWWOFFLE|x-Tractor|^Xaldon WebSpider|WUMPUS|Xenu|XGET|Zeus.*Webster|Zeus [NC]

RewriteRule ^.* – [F]

WordPress Permissions

Web server files or directories should never be 777 as this will let anyone tamper with files or directories on your server. 777 permissions are not required for WordPress to operate nor for any upload directories to function.

For example, a simple HTTP POST command using curl can upload a malicious plugin to take control of the blog. A recent example of this is the ToolsPack plugin found on compromised blogs due to 777 permissions (

In general, directories should be 750 or 755. Files should be 644 or 640. For example, this command will make all files recursively in /var/www/ to be 755 permissions:

$ sudo chmod -R 755 /var/www/

To locate any directories that are 777, the find command can be used. This command searches for directories that are 777 in /var/www/:

$ sudo find /var/www/ -type d -perm -002

Likewise for files, this command searches for files that are 777 in /var/www/:

$ sudo find /var/www/ -type f -perm -002

The other aspect of permissions concerns the owner and group of the files in /var/www or whatever is the location of the WordPress installation. Files and directories should be owned by a regular user and in the group of the apache user. This is so that if a compromise was to occur or if a rogue script was run launched by WordPress or related software it would not be able to maliciously alter or install malware in the WordPress installation or other web directories.

This example command changes the owner to jsmith (example username) and group of the Apache user on Debian and Ubuntu for all files in the WordPress installation:

$ sudo chown -R jsmith:www-data /var/www/wordpress

This does cause a slight problem for WordPress Dashboard updates of plugins or themes. To temporarily switch permissions to allow Dashboard updates, change the owner to the apache user:

$ sudo chown -R www-data:www-data /var/www/wordpress

Next perform updates in the WordPress Dashboard, then set permissions back:

$ sudo chown -R jsmith:www-data /var/www/wordpress

While not convenient, temporarily changing ownership for updates and back will help to keep the WordPress installation more secure.

Plugins and Themes from Trusted Sources

Only install plugins and themes from trusted sources. It is good to exercise a healthy bit of skepticism even when browsing available themes or plugins from Inspect the author of the plugin or theme to check their credibility, the amount of time the plugin or theme has been in use, and any general common sense gauge before implementing the code on your WordPress installation.

Various free themes and plugins floating around the internet have malicious links or code embedded. This malicious code is often masked as base64 so looking at the php files malicious links or javascript may not be immediately visible.

One example at time of writing is an ‘Advanced Search’ plugin which is available from a random link: . According to, this plugin sneaks in many malicious URLs into your blog (

Limit number of plugins used

If possible, limit the total number of plugins used. For plugins that are not used and disabled, delete them completely. The same goes for unused themes. Remove unused themes from your server. The only themes installed should be the WordPress default and the current activated theme for the website. For example, many themes made use of the timthumb.php file which caused many blogs to be compromised over the past few months. This vulnerable file could be part of a random theme that is unused, yet remains sitting on the web server.

The number of users allowed to have accounts should be kept to an absolute minimum as well.

Recommended Security Plugins

Many security related plugins exist for WordPress. In particular the following are very useful.

Bad Behavior ( restricts HTTP connections that appear malicious, somewhat acting as an IDS/IPS all from a plugin. Even better, Bad Behavior can integrate with so that the current blacklist from project honeypot is also applied to protect against malicious connections to WordPress.

To prevent spam links, it is possible to disable comment Author Links via a simple plugin called Disable comment Author Links ( ).

It is helpful to use a good anti-spam comment plug, such as WP Captcha-Free (

The plugin wp-updates-notifier ( provides instant email notifications for plugin, theme, or core WordPress updates.

Regarding comments, be very skeptical of very generic comments on the blog such as ‘Very informative post’, ‘Great site, I love the information here’, or ‘Good post on the topic’. Many of these are from spam-bots often either testing the comment system, testing anti-spam measures, or testing for XSS.

Third party content

When choosing an advertising provider, chose a trusted provider such as Google Adsense. By using third party services the site is allowing a trust of the provider to place content, links, and code onto the site. There have been rare occurrences of third party advertising installing malware on sites as with, though this can be considered somewhat rare.

System Administration

p>If the blog or site is hosted on an unmanaged service such as a VPS, WordPress security extends to full server OS security. For example, if the server running WordPress is running out-of-date PHP, this leaves the entire server vulnerable.

In this case it is critical to stay on top of all operating system updates. For the case of Debian or Ubuntu Linux, make use of the program apticron, which sends email notifications when operating system updates are available (

As with general server security, minimize running services on the box. For required services that are running (HTTP, SMTP, etc) minimize information leakage from the running services.

Many providers that use cpanel and other administration interfaces make use of FTP as a predominant way to transfer files to the hosting site. FTP is insecure and should be avoided. Using SFTP over port 22 is the preferred way for connecting for file transfer and all modern FTP clients support SFTP. If the hosting company does not support SFTP, change to a different provider.


Daily reviewing of Apache logs can be automated in Linux with logwatch. Logwatch emails a daily snip-it of log activity and can highlight specific information that looks suspicious or would need closer manual inspection.

Example logwatch email:

Subject: Logwatch for (Linux)
Date: Sun, 13 May 2012 06:25:10 -0700 (PDT)
################### Logwatch 7.3.6 (05/19/07) ####################
    Processing Initiated: Sun May 13 06:25:10 2012
    Date Range Processed: yesterday
    ( 2012-May-12 )
    Period is day.
    Detail Level of Output: 0
    Type of Output/Format: mail / text
    Logfiles for Host:
——————— httpd Begin ————————
A total of 79 sites probed the server
Requests with error response codes
    400 Bad Request
    /: 1 Time(s)
    401 Unauthorized
    /wp-login.php?redirect_to=https%3A%2F%2Fsc … min%2F&reauth=1: 1 Time(s)
    404 Not Found
    /admin/spaw2/spacer.gif: 1 Time(s)
    /data/ap1.php?f=25: 2 Time(s)
    /manager/html: 1 Time(s)
    408 Request Timeout
    null: 262 Time(s)
———————- httpd End ————————-

The Linux program fail2ban is often thought of as an ssh anti-brute-forcing tool, but it has a use for web servers as well. fail2ban can be utilized to prevent repeated attempts from bots or other various malicious attempts to the server. The fail2ban configuration apache-badbots.conf from Yaroslav Halchenko is extremely useful in this regard. When enabled, repeated attempts using these user agents result in the ip being blocked by the firewall.

# Fail2Ban configuration file
# List of bad bots fetched from
# Generated on Sun Feb 11 01:09:15 EST 2007 by ./
# Author: Yaroslav Halchenko
# $Revision: 668 $
badbotscustom = EmailCollector|WebEMailExtrac|TrackBack/1.02|sogou music spider
badbots = atSpider/1.0|autoemailspider|China Local Browse 2.6|ContentSmartz|DataCha0s/2.0|DBrowse 1.4b|DBrowse 1.4d|Demo Bot DOT 16b|Demo Bot Z 16b|DSurf15a 01|DSurf15a 71|DSurf15a 81|DSurf15a VA|EBrowse 1.4b|Educate Search VxB|EmailSiphon|EmailWolf 1.00|ESurf15a 15|ExtractorPro|Franklin Locator 1.8|FSurf15a 01|Full Web Bot 0416B|Full Web Bot 0516B|Full Web Bot 2816B|Industry Program 1.0.x|ISC Systems iRc Search 2.1|IUPUI Research Bot v 1.9a|LARBIN-EXPERIMENTAL (| +|Lincoln State Web Browser|LWP::Simple/5.803|Mac Finder 1.0.xx|MFC Foundation Class Library 4.0|Microsoft URL Control – 6.00.8xxx|Missauga Locate 1.0.0|Missigua Locator 1.9|Missouri College Browse|Mizzu Labs 2.2|Mo College 1.9|Mozilla/2.0 (compatible; NEWT ActiveX; Win32)|Mozilla/3.0 (compatible; Indy Library)|Mozilla/4.0 (compatible; Advanced Email Extractor v2.xx)|Mozilla/4.0 (compatible; Iplexx Spider/1.0|Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; DTS Agent|Mozilla/4.0|Mozilla/5.0 (Version: xxxx Type:xx)|MVAClient|NASA Search 1.0|Nsauditor/1.x|PBrowse 1.4b|PEval 1.4b|Poirot|Port Huron Labs|Production Bot 0116B|Production Bot 2016B|Production Bot DOT 3016B|Program Shareware 1.0.2|PSurf15a 11|PSurf15a 51|PSurf15a VA|psycheclone|RSurf15a 41|RSurf15a 51|RSurf15a 81|searchbot|sogou spider|sohu agent|SSurf15a 11 |TSurf15a 11|Under the Rainbow 2.2|User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)| libwww-perl/5.803|Wells Search II|WEP Search 00
# Option: failregex
# Notes.: Regexp to catch known spambots and software alike. Please verify
#     that it is your intent to block IPs which were driven by
#     abovementioned bots.
# Values: TEXT
failregex = ^<HOST> -.*”(GET|POST).*HTTP.*”(?:%(badbots)s|%(badbotscustom)s)”$
# Option: ignoreregex
# Notes.: regex to ignore. If this regex matches, the line is ignored.
# Values: TEXT
ignoreregex =


It goes without saying but upgrading all plugins, themes, and of course WordPress to their latest versions is critical.

After upgrading WordPress, remove readme.html and license.txt from the WordPress directory. For the even more paranoid, remove any readme.txt files or license files from all plugins and themes which would reveal the version of the software installed.

Daily mysql backups as well as daily theme/plugin backups should be in place. Recovering a snapshot of the site or database from backup should be rehearsed and procedures documented.

Scanning and Auditing

Regular auditing of the site for security against XSS and SQLi should be performed with various web application scanners either commercial or open source. Multiple web scanners should be used for various viewpoints on the current level of security of the site. For high traffic sites weekly web application scanning should be performed or automated. For lower traffic site quarterly scans can perhaps suffice.


WordPress is a very extensible CMS but is often also seen as an easy target for exploitation. Taking an active approach to securing WordPress should be done as would be done with securing any operating system. It is not WordPress itself which is altogether too problematic from security concern but often a poor implementation, out-of-date software and plugins, or use of untrusted plugins which result in a compromised target. It is critical to stay on top of security to keep the WordPress installation as protected as possible from would-be attackers.

Posted: June 8, 2012
Scott Miller
View Profile

Scott Miller is a security researcher for the InfoSec Institute with experience in web application hacking, Linux security, and also network security. As a Linux administrator and open source advocate, Maher has worked in both higher education and the private sector with enterprise networks facing a variety of security challenges.