Who Changed It/Answers

WordPress site hacked? How to find out what changed.

Spam pages, a redirect to a site you've never heard of, an administrator you didn't create. Before you can clean up, you need to know what the attacker changed and how they got in. This page walks through where to look, in order.

Before you investigate: preserve, then contain

The instinct is to restore last week's backup and move on. Don't do that first. A restore wipes out the evidence of how the attacker got in, and if that way in is still open, whether it's a vulnerable plugin or a stolen password, they will be back within days.

  1. Take a full copy of the hacked site, files and database, and put it somewhere the site can't reach. That copy is your evidence.
  2. Change every password with access to the site: WordPress administrators, hosting panel, SFTP/SSH, the database user.
  3. Invalidate every logged-in session by replacing the authentication keys and salts in wp-config.php. A salts generator produces a fresh set. Everyone, including the attacker, is logged out.
  4. If the site is actively harming visitors, with redirects or malware downloads, put it in maintenance mode while you work.

Where to look, in order

Attackers change a small number of predictable things. Go through them in this order. The first two are quick, and they are where most break-ins show up.

1. Users and roles

Filter Users by Administrator and question every account. Attackers create admin accounts with plausible names ("wpadmin", "support", a copy of a real name) or quietly promote an existing low-level account. With WP-CLI: wp user list --role=administrator. Check the email addresses too. An attacker may change a real admin's email so that password resets go to them.

2. Plugins, themes and must-use plugins

Look for plugins you don't recognise, including ones that are deactivated, which can still hold a backdoor file anyone can reach by URL. Then check the Must-Use tab on the Plugins screen, or the wp-content/mu-plugins folder: code there runs on every request, can't be switched off from the dashboard, and is easy to miss.

3. Files

Compare your files with the official versions:

4. Settings

A handful of settings let an attacker take the site over without touching a file. Check Settings → General: the WordPress and site address (redirecting all your visitors), the admin email (receiving your password resets), "Anyone can register" and the default role (handing out accounts). On a shop, check the payment settings, because redirecting payouts is one of the most lucrative things an attacker can do to a WooCommerce site.

5. The database

Injected spam and redirect scripts often live in the database rather than in files. Search post content and the options table for <script, eval(, base64_decode and domains you don't recognise. Look for published posts and pages you didn't write, especially large batches of them.

6. Scheduled tasks

A well-hidden infection reinstalls itself. wp cron event list shows every scheduled job: look for hooks you can't match to a plugin you use. If you clean everything else but miss this, the site is reinfected on the next cron run.

7. Server logs: how they got in

Your host's access logs are the best evidence of the entry point, if they still exist. Many hosts keep them only for days. Look for bursts of POST requests to wp-login.php or xmlrpc.php (password guessing), requests to PHP files that shouldn't exist, and requests to a specific plugin's folder just before the first sign of trouble, which points at a vulnerability in that plugin.

Why "what changed" is so hard to answer

Everything above is reconstruction. WordPress doesn't record who created a user, changed a role, installed a plugin or edited a setting. It stores the current state and overwrites the past. And the attacker has every reason to tidy up after themselves: delete the account they used, remove the plugin they installed, clear whatever log they can find. If an activity log was running but stored its records in an ordinary database table, anyone with admin or database access could delete the rows that mention them, and nothing about the remaining table would look wrong.

A log an attacker can't quietly rewrite

Who Changed It is built for exactly this situation. It records the events a break-in consists of, and it's designed so that covering them up leaves a trace.

#60114 · 02:47 · no user · user_created · "wp-support" (administrator) — new administrator account — dangerous, alert sent

What it won't do

Being clear about the limits matters most on a page like this. Who Changed It records what passes through WordPress. It does not scan files for malware, and it can't see a file uploaded over FTP, a webshell written through a vulnerability that never goes through WordPress's own functions, or a row inserted straight into the database. An attacker with full control of the server can switch it off. That's why the alerts go out immediately and why a missing digest is meaningful. It doesn't replace backups, file integrity checks or a firewall. It's the record that tells you what happened in WordPress and lets you prove the record is intact.

If you'd rather hand the cleanup to someone else, finding the entry point, removing what was left behind and hardening the site is incident work. Malware removal and hardening is the service run by this site's own author.

Common questions

Should I restore a backup straight away after a hack?
Not before you have copied the hacked site. Restoring overwrites the evidence of how the attacker got in, and if the way in is still open (a vulnerable plugin, a stolen password) the restored site will be compromised again. Take a full copy of files and database first, find the entry point, then restore or clean.
How do I find files an attacker changed on WordPress?
Compare them with the official copies. With WP-CLI, wp core verify-checksums checks WordPress's own files and wp plugin verify-checksums --all checks plugins from WordPress.org. Then look for PHP files in wp-content/uploads, which should contain none, for recently modified PHP files, and for anything in wp-content/mu-plugins you didn't put there.
Can an attacker delete the activity log?
An attacker with administrator access can, but not quietly with Who Changed It. Purging the log from its settings is always logged as a dangerous event and triggers an alert. Deleting or editing rows directly in the database breaks the hash chain, and verification reports the missing or altered records. Alerts about the break-in, such as a new administrator account, will already have gone out by email, Slack, Discord or Telegram before the attacker gets to the log.
Does Who Changed It remove malware?
No. It is an activity log, not a scanner or a cleanup tool. It records what happens through WordPress, flags the events that look like an attack and alerts you, and keeps a record that can be verified later. It doesn't scan files, and changes made over FTP, SSH or directly in the database bypass it.