The Website Looked Fine, but Google Was Showing Spam: A WordPress Malware Cleanup

Recently, I worked on a WordPress website that looked completely normal when opened in the browser, but Google was showing spam content in the search results.

This is one of those issues that can easily confuse website owners. You open the homepage, everything looks fine. You check a few pages, still fine. No redirects, no popups, no strange content.

But Google was seeing something different.

In this case, Google was showing product spam for a website that had nothing to do with those products. The site itself was still loading correctly for normal visitors, but the search result made it look hacked.

The issue turned out to be cloaking. Normal visitors were getting the real website, while Googlebot was getting spam content.

First, I checked what Googlebot was seeing

When Google shows spam but the website looks fine, I don’t immediately assume the site is clean. Google may have cached an old hacked version, but the site may also still be serving spam only to search engines.

The quickest way to check that is to compare a normal request with a Googlebot request.

In my case, I searched for words that were already appearing in Google’s spam snippet. The exact words will be different for every website, so replace them with whatever Google is showing for your site.

curl -sL https://example.com/ | grep -iE "<title|description"

curl -sL -A "Googlebot/2.1 (+http://www.google.com/bot.html)" https://example.com/ \
  | grep -iE "<title|description|REPLACE_WITH_SPAM_WORD_1|REPLACE_WITH_SPAM_WORD_2|REPLACE_WITH_SPAM_WORD_3"

The normal request returned the correct website title and description.

The Googlebot request returned the spam text that was showing in Google.

That confirmed the problem was still active. It was not just an old Google cache issue.

Why the website looked clean to normal visitors

This kind of malware is designed to hide.

It checks who is visiting the website. If it looks like a normal person, it shows the real website. If it looks like Googlebot or another crawler, it shows spam content instead.

That is why the site owner can open the website and see nothing wrong, while Google indexes a completely different version.

This is usually called SEO spam or Googlebot cloaking.

The active infection was in index.php

After checking the database, SEO metadata, plugins, uploads folder, and mu-plugins, the active infection was found in the root index.php file.

A normal WordPress index.php file is small. It only loads WordPress and passes the request to the theme.

This file was larger than expected and had obfuscated PHP code inside it.

The suspicious code used functions like:

  • base64_decode
  • gzuncompress
  • tempnam
  • include
  • unlink

That combination is a common malware pattern. The code decodes a hidden payload, writes it to a temporary file, runs it, and then removes the temporary file.

I replaced the infected index.php with a clean WordPress version.

cat > index.php <<'PHP'
<?php
/**
 * Front to the WordPress application. This file doesn't do anything, but loads
 * wp-blog-header.php which does and tells WordPress to load the theme.
 *
 * @package WordPress
 */

define( 'WP_USE_THEMES', true );

/** Loads the WordPress Environment and Template */
require __DIR__ . '/wp-blog-header.php';
PHP

After that, I tested the website again as Googlebot. The spam was gone, and Googlebot was seeing the real website title and description.

The next question: what could bring it back?

Removing the infected file fixed the visible problem, but that is not enough.

If you only clean the file that shows the symptom, the site can get reinfected if the original source is still there.

So I kept checking the site for anything that could write files or execute hidden PHP code.

One inactive plugin stood out: hide-my-wp.

The plugin was not clean

Inside that plugin, I found PHP files with large encoded payloads that were decoded and executed using eval().

The code also used request headers as part of the decoding process, which is another bad sign. Clean plugins should not hide large blocks of code and execute them dynamically based on visitor headers.

A simplified version of what I found looked like this:

$data = base64_decode($encoded_payload);

// request header used as part of the decoding logic
$language = $_SERVER['HTTP_ACCEPT_LANGUAGE'];

// decoded PHP code gets executed
eval($decoded_code);

That is not normal WordPress plugin behavior.

Whether the plugin was installed from an untrusted source, modified later, or came from an old compromise, the installed copy was backdoored and could not be trusted.

Removing the backdoored plugin

Since the plugin was not clean, I removed it from the live website files.

If you need to keep a copy for investigation, download it first and store it outside the webroot. But for the live website, the plugin should not stay in wp-content/plugins.

rm -rf wp-content/plugins/hide-my-wp

Then I scanned the website again for the same malicious pattern.

grep -RIn --include='*.php' \
  -E "eval\(\$report_data\)|eval\(\$payment_amount\)|HTTP_ACCEPT_LANGUAGE.*base64_decode|base64_decode.*HTTP_ACCEPT_LANGUAGE" \
  /var/www/example.com/index.php /var/www/example.com/wp-config.php /var/www/example.com/wp-content 2>/dev/null \
  || echo "No matching malicious pattern found"

After removing the plugin, the scan came back clean.

Verifying WordPress core

Once the infected file and backdoored plugin were removed, I verified WordPress core files using WP-CLI.

wp core verify-checksums --allow-root

The first check failed because index.php had been changed and there were extra log files inside WordPress core directories.

I restored WordPress core from the official package and removed the extra files.

wp core download --force --skip-content --allow-root

rm -f wp-admin/includes/error_log \
      wp-admin/error_log \
      wp-includes/blocks/error_log \
      wp-includes/theme-compat/error_log \
      wp-includes/error_log

wp core verify-checksums --allow-root

After that, WordPress core verified successfully.

Locking down file changes

I also disabled file editing from the WordPress dashboard.

wp config set DISALLOW_FILE_EDIT true --raw --allow-root

During cleanup, I also disabled plugin and theme modifications from the dashboard.

wp config set DISALLOW_FILE_MODS true --raw --allow-root

Note: DISALLOW_FILE_MODS also blocks normal plugin and theme updates from the WordPress dashboard. I usually treat it as a temporary lockdown unless the site has a deployment process that handles updates outside the dashboard.

Clearing cache

After cleaning the files, cache still needs to be cleared.

This part depends on your setup. You may have WordPress cache, plugin cache, server cache, object cache, CDN cache, Cloudflare cache, or a mix of all of them.

The important point is not the exact command. The important point is to clear every cache layer that can serve the old response.

# WordPress object cache
wp cache flush --allow-root

# If your host/plugin provides a cache purge command, run it too.
# Examples: LiteSpeed, Redis object cache, hosting panel cache, etc.

If the site uses a CDN like Cloudflare, purge the CDN cache as well. Otherwise Google or visitors may still receive an old cached version even after the files are clean.

Final checks

Before calling the cleanup done, I checked a few things:

  • WordPress core checksums passed.
  • The backdoored plugin was no longer in wp-content/plugins.
  • The root index.php was clean.
  • Googlebot saw the real website metadata.
  • The spam words from Google’s search result no longer appeared in the live response.
wp core verify-checksums --allow-root

wp plugin list --fields=name,status,version --allow-root | grep -i hide || echo "Suspicious plugin not visible to WordPress"

grep -nE "base64_decode|gzuncompress|tempnam|sys_get_temp_dir|eval\(" index.php || echo "index.php clean"

curl -sL -A "Googlebot/2.1 (+http://www.google.com/bot.html)" https://example.com/ \
  | grep -iE "<title|description|REPLACE_WITH_SPAM_WORD_1|REPLACE_WITH_SPAM_WORD_2|REPLACE_WITH_SPAM_WORD_3" -n | head -n 20

At the end, Googlebot was seeing the real website again, WordPress core checksums passed, and the malicious plugin pattern was no longer present in the live website files.

The main lesson

If Google is showing spam for your website but the website looks normal when you visit it, test what Googlebot sees.

curl -sL -A "Googlebot/2.1 (+http://www.google.com/bot.html)" https://example.com/ | head

If the response is different, you may be dealing with cloaking.

In this case, cleaning index.php fixed the active spam output, but removing the backdoored plugin was the important part. Without that, the same issue could come back later.

For WordPress malware cleanup, don’t stop at the visible infected file. Find the code that can recreate it.