How to Detect and Remove Malware From a Website

How to tell a site is infected, find the malicious files, clean or restore it, close the hole it came through, and clear Google's warning.

Published
Reading time
4 min

A hacked website rarely announces itself. More often it redirects some visitors to a pharmacy, sends spam quietly, or serves a phishing page at a URL nobody normally visits. Here is how to confirm an infection, remove it thoroughly, and keep it from coming back — in that order, because cleaning without closing the hole is a weekend wasted.

Signs of an infection

  • Google Search Console reports "Social engineering" or "Hacked content", or Chrome shows a red warning.
  • Visitors from Google are redirected, while typing the URL directly works (malware often targets search referrals only).
  • Unknown admin users, plugins or scheduled tasks.
  • Outbound mail queue full of messages you did not send.
  • Files with recent modification dates you did not touch, or PHP files inside wp-content/uploads.
  • The host's scanner (Imunify360 on VPSPioneer plans) reports findings.

1. Take a copy and lock the doors

Before changing anything, take a full backup of the infected state — you may need it for forensics — and note the time. Then reduce the damage while you work:

  • Put the site in maintenance mode or, if it is serving phishing pages, take it offline.
  • Change every password: hosting panel, SFTP, database, WordPress admin, and the email accounts on the domain.
  • Revoke API keys and application passwords.

2. Find the malicious files

Run a scanner first. On Plesk, Imunify360's Malware Scanner scans the whole account and lists findings with paths. WordPress Toolkit's Security → Check and the Wordfence plugin also scan core and plugin files against known-good checksums.

Then look by hand, because scanners miss new variants. Recently changed PHP files:

bash
cd /var/www/vhosts/example.com/httpdocs
find . -name "*.php" -mtime -14 -not -path "./wp-content/cache/*" | head -50

PHP where it does not belong:

bash
find ./wp-content/uploads -name "*.php"

The functions almost every web shell uses:

bash
grep -rlE "eval\(|base64_decode\(|gzinflate\(|str_rot13\(|preg_replace\(.*/e" --include="*.php" . | head

Expect some false positives in legitimate plugins; open the file and look. Malware is usually a long single line of encoded text, often at the top of an otherwise normal file, or in a file with a name mimicking WordPress core (wp-conf.php, class-wp-cache.php).

Check the things that survive file cleanup: .htaccess for redirect rules, wp_options in the database for injected scripts (siteurl, home, and anything in active_plugins you do not recognise), and wp_users for extra admins.

bash
grep -n "RewriteRule\|Redirect" .htaccess

3. Clean — or, better, replace

For WordPress, the reliable method is not to edit infected files but to replace them:

  1. Download a fresh copy of the same WordPress version and overwrite wp-admin, wp-includes and the root PHP files.
  2. Delete each plugin and theme directory and reinstall it from the official source. Delete anything you are not using.
  3. Keep wp-content/uploads and wp-config.php, after checking both by hand (uploads for PHP files, config for injected code at the top or bottom).
  4. Check the database as above.

WordPress Toolkit does step 1 in a click (Reinstall core). If you have a clean backup from before the infection and know when it happened, restoring that backup is faster than all of the above — but only if you also do step 4 next, or it will reinfect within days.

4. Close the hole

The infection came through something. The likely candidates, in order:

  1. An outdated plugin or theme with a known vulnerability. Update everything; remove what you do not use.
  2. A weak or reused password, or no two-factor auth on the admin.
  3. A neighbouring site on the same account — infections spread within an account. Check every site under the same login.
  4. A compromised computer with saved SFTP passwords.
  5. File permissions allowing writes where they should not be — see file permissions explained.

Read the access log for the days before the infection: requests with POST to odd URLs, or to a plugin's file directly, show the entry point.

bash
grep -h "POST" logs/access_ssl_log* | grep -v "wp-admin/admin-ajax\|wp-login\|wp-cron" | tail -50

5. Rescan and request review

Run the scanner again; it should be clean. Then in Google Search Console, Security & Manual Actions → Request review, describing what you found and fixed. Reviews typically clear within a day or two. If the domain was blacklisted for spam, check mxtoolbox and request delisting from each list.

Keeping it clean

Automatic core and plugin updates, two-factor auth, a scanner that runs daily, off-server backups, and no unused plugins. Our WordPress hardening checklist is the full list.

Every VPSPioneer shared plan runs Imunify360 with automatic cleanup, and on any plan you can ask us to do the removal above for you — it is the most common job our security team does.

#security#malware#wordpress#cleanup#imunify360

Keep reading

More from Security

All guides

Security

SSL/TLS Explained: Certificates, Authorities and HTTPS

What a TLS certificate proves, how the handshake works, DV vs OV vs EV, why Let's Encrypt is enough for almost everyone, and what the padlock does not mean.

4 min read →

Security

How to Install Fail2ban and Stop Brute-Force Attacks

Install Fail2ban, understand jails and bantime, protect SSH, Plesk, Nginx and WordPress logins, whitelist your own IP and read what it has banned.

3 min read →

Security

How to Harden a New Linux VPS in 10 Steps

The first hour on a fresh VPS: updates, a sudo user, SSH keys, firewall, Fail2ban, automatic patches and backups, with commands for Ubuntu and AlmaLinux.

3 min read →