Revolution Slider Security Hole (and Fix)

I read today* about a vulnerability in Revolution Slider. This is a very popular plugin, and is bundled with the 2nd most popular theme on Theme Forest, X | The Theme.

*It took 3 months for the severity of this attack to go from discovery to me via a colleague. Probably partially due to the fact that I’m not on Twitter all the time, but I’m quite disappointed that Envato did not alert anyone who bought the plugin or one of the 1,197 themes with Revolution Slider embedded, warning them of this vulnerability.

If you see in your server access logs:


Then your site has been attacked (not necessarily compromised). If successful, the attacker now has your MySQL database login and may be able to do just about anything they want with your site.

What you should do right now

Upgrade the Plugin

First, upgrade the plugin! If you’re running version 4.1.4 or older, you need to upgrade. If you are using a theme which has Revolution Slider included, and the theme hasn’t been updated, you need to get the plugin and upgrade it.

Add to .htaccess

Next, there are some lines you can add to your .htaccess file to make it more secure. Your existing file looks something like this:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

If you add the following lines, you’ll block any requests that contain “wp-config” in the query string (everything after the “?” in the URL)

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /

RewriteCond %{QUERY_STRING} wp-config.php
RewriteRule .* - [F]

RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

I’m a big fan of using htaccess to block certain parts of WordPress. Here’s some of what I use:

RewriteCond %{HTTP_REFERER} !^http://(.*)?ericnagel\.com [NC]
RewriteCond %{REQUEST_URI} ^/(.*)?wp-login\.php(.*)$ [OR]
RewriteCond %{REQUEST_URI} ^/(.*)?wp-admin$
RewriteRule ^(.*)$ - [R=403,L]

RewriteCond %{REQUEST_URI} ^/(.*)?xmlrpc\.php(.*)$
RewriteRule .* - [F]

RewriteCond %{QUERY_STRING} environ [NC]
RewriteRule .* - [F]

RewriteCond %{REQUEST_URI} ^/wp\-content\/uploads\/(.)*\.php
RewriteRule .* - [F]

RewriteCond %{QUERY_STRING} wp-config.php
RewriteRule .* - [F]

What this does is

  • only allow POSTs from my own site (you’ll change “” to your own domain)
  • block any requests to xmlrpc.php (if you don’t use it, block it)
  • block any request with environ in the query string (this is from an old attack – just block it)
  • block any requests to .php files that have been uploaded (if a hacker manages to upload a script to your wp-uploads folder, they won’t be able to execute it via the web)
  • block any requests that has wp-config.php in the query string

Lock Down MySQL

Finally, change your MySQL password and make sure that the database is only accessible to your web server. There’s no reason to allow anyone (%) with your MySQL username and password to connect. If your MySQL database is on the same server as your web server, use “localhost”; otherwise, use the web servers name.

Generate New Authentication Unique Keys

Go to and generate new Authentication Unique Keys, and paste these lines over the existing lines in your wp-config file. Since a successful attack has revealed these values, it’s best to reset them.

You can change these at any point in time to invalidate all existing cookies. This will force all users to have to log in again.

Looking Forward

Open Source software is awesome because anyone can see how it works, modify it, and expand on it. But it also allows for attackers to find vulnerabilities and exploit them.

How To & Tips



Handling Products Removed From Datafeeds

I received an email the other day from Garrett, and he asked:

I’m just curious how you might deal with pages/urls on your site that have been indexed (and may be getting good traffic/links), but all of a sudden they’ll disappear if the product happens to drop off the merchant’s feed.

After a couple emails back & forth, I think the best solution would be to find a similar product, and 301 redirect to that product. First, I’m going to change my .htaccess file to pass in the “name” of the item that was requested:


RewriteRule ^(.*)\-p([0-9]+).php$ item.php?ProductID=$2 [L]


RewriteRule ^(.*)\-p([0-9]+).php$ item.php?ProductID=$2&cName=$1 [L]

Then edit item.php, and after $rsData = mysql_fetch_array($oResult); (about line 6), add:

if (!$rsData) {
	// We don't have this item anymore!

	// Get the parts of the product name
	// See
	$aNameParts = explode('-', $_GET['cName']);

	// Look up similar products in the database
	$cQuery = "select * from products where";
	foreach ($aNameParts as $cNamePart) {
		$cQuery .= " Name like '%" . mysql_real_escape_string($cNamePart) . "%' or ";
	} // ends foreach ($aNameParts as $cNamePart)
	$cQuery = ereg_replace(" or $", "",$cQuery ); // remove the last "or"
	$oResult = mysql_query($cQuery);
	$rsData = mysql_fetch_array($oResult);
	if (!$rsData) {
		// No clue
		header("Location:  /");
	} // ends if (!$rsData)
	else {
		$p = 0;
		$nItemID = $cName = '';
		$cOrig = str_replace('-', ' ', $_GET['cName']);

		do {
			similar_text ($cOrig, $rsData['Name'], $fMatch);
			if ($fMatch > $p) {
				$nItemID = $rsData['ProductID'];
				$cName = $rsData['Name'];
				$p = $fMatch;
			} // ends if ($fMatch > $p)
		} while ($rsData = mysql_fetch_array($oResult));

		if ($p > 0) {
			// Best match
			header("Location:  /" . ereg_replace("[^A-Za-z0-9]", "-", $cName) . "-p" . (int)$nItemID . ".php", TRUE, 301);
		} // ends if ($p > 0)
		else {
			// No good match
			header("Location:  /");
		} // ends else from if ($p > 0)
	} // ends else from

} // ends if (!$rsData)

Now, if product 8675309 used to be at, the script will see it’s no longer in the database, then get all products with “New”, “Snow”, or “Sprout” in the title, compare them to “New Snow Sprout” and redirect the user to the best choice (in this case,

By default, the redirect is “HTTP/1.1 302 Found”, so we add “, TRUE, 301” to the header call to change it to a permanent redirect.

Of course, for all this to work, you have to be using .htaccess rewrites, otherwise there’s no way to get the name of the missing (and requested) product.

Thanks for the inspiration to this post, Garrett! Hope this answered your question for you!

How To & Tips



Display URL That Works

A common trick in PPC is to include keywords in your Display URL (the URL that is displayed with your PPC ad). The display URL doesn’t HAVE to work, but it should. I don’t have any stats on this, but if someone does a copy / paste of your display URL, and it goes to a 404 page, you just lost that potential customer.

Searching for Christmas lights shows the top 2 ads are using Display URLs with keywords in them.

Google AdWords Display URL

The first link,, goes to a very useful 404 page. In fact, I’m sure most users won’t even see the error message and quickly click on the Christmas lights image, yet that’s one click further away from the sale.

The second link,, works just fine, and takes the user right where they want to go.

Bronners, another PPC advertiser on the page, shows users – a very ugly 404 page.

Redirecting your Display URL to the proper Destination URL is easy to do with .htaccess. Here’s a quick example:

RewriteEngine On
Redirect 301 /save

So now your display URL can be and the user will be taken to

Every little bit helps!

How To & Tips