If you have just found out your WordPress site is hacked, the first hour matters more than the cleanup that follows. Do four things, in this order: capture the evidence, cut off access, find the entry point, and only then clean. Most recovery guides start at “scan and remove malware.” That order is why so many sites get reinfected inside a week — the malware goes, the hole stays open, and the attacker walks back in through the same door with the same credentials.
Here is the short version. Do not delete anything yet. Take a full snapshot of files and database exactly as they are. Pull the access logs and error logs off the server before your host rotates them. Then revoke sessions, rotate salts, and kill every credential — including the ones a password reset does not touch. Read the logs to find how they got in. Patch that specific hole. Clean or rebuild. Request a Google review last, once you are confident the site is actually clean, because a failed review is worse than a late one.
The rest of this article is that hour, minute by minute, plus the 48 hours after it.
Why the order matters more than the tools
The reason cleanup-first fails is arithmetic. Patchstack’s State of WordPress Security in 2026 report counted 11,334 new vulnerabilities disclosed across the WordPress ecosystem during 2025 — a 42% year-over-year increase — with 91% of them in plugins and 9% in themes. Six were in WordPress core. The median time to mass exploitation for heavily exploited vulnerabilities was five hours, and roughly half of high-impact vulnerabilities saw exploitation within 24 hours of disclosure. In the same report, 46% of vulnerabilities had no fix available from the developer at the time of public disclosure.
What that means practically: the thing that let someone in is almost certainly a plugin or theme, it was probably found by an automated scanner rather than by a person who chose you, and the window between “disclosed” and “exploited at scale” is measured in hours. Clean without identifying the entry point and you have removed the symptom of a door that is still open — the same scanner finds you again on its next pass. The same report found hosting-layer defences blocked only 12% of WordPress-specific vulnerability attacks in pentesting, so “my host has a firewall” is not an answer to “how did this happen.”
Minute 0–10: capture evidence before you change anything
The instinct is to delete the obvious bad file. Resist it. The moment you start editing you destroy timestamps, and file modification times are the most useful thing you have for reconstructing what happened.
Take these, in this order:
- A full file archive and database dump, as-is. Not a “clean backup” — a forensic copy of the compromised state. Store it off the server.
- Access logs and error logs. Most hosts rotate these on a short cycle, sometimes daily. Once they are gone, you will never know the entry point. Download the raw files rather than reading them in a control panel.
- A list of recently modified files. Run this before anything else touches the filesystem:
# Files changed in the last 14 days, newest last
find /path/to/site -type f -name "*.php" -mtime -14 -printf "%TY-%Tm-%Td %TH:%TM %p\n" | sort
# Core files that do not match WordPress.org's checksums
wp core verify-checksums
# Same check for every plugin installed from the .org repository
wp plugin verify-checksums --all --strictTwo caveats on those checksum commands. wp core verify-checksums compares core files against WordPress.org’s published checksums, so it catches modified and unexpected files in core directories — but it says nothing about wp-content, where most injected code lives. And wp plugin verify-checksums only covers plugins distributed through the WordPress.org repository; premium plugins bought from a developer’s own site have no published checksums, so they come back unverifiable rather than clean. Those are often exactly the components you most need to check.
Put the site into maintenance mode or return a 503 while you work. Do not take the domain fully offline — you want Google to see temporary unavailability, not a dead host.
Minute 10–25: cut off access, including the credentials nobody revokes
Changing the admin password is the step everyone takes and the step that accomplishes the least, because a password change does not end an existing logged-in session and does not touch several other credential types that grant full access.
Do all of this:
# Kill every logged-in session for every user
wp user list --field=ID | xargs -n 1 wp user session destroy --all
# Rotate the auth keys and salts in wp-config.php
wp config shuffle-salts
# See who actually has administrator rights right now
wp user list --role=administrator --fields=ID,user_login,user_email,user_registeredThat last command is the one that surprises people. A very common persistence trick is a second administrator account created days or weeks before the visible damage, often with a plausible name and an email on a domain you do not recognise. Check registration dates against your own records.
The credentials a password reset does not cover
Work through this list deliberately — each of these survives an account password change:
- Application passwords. These live under Users → Profile → Application Passwords and are separate credentials, individually revocable, designed specifically so an integration can be disabled without changing the user’s primary password. That independence cuts both ways: resetting the account password is not how you get rid of them. Revoke every one you do not recognise, on every account.
- SSH and SFTP keys. Check
~/.ssh/authorized_keyson the server. An added public key is a permanent back door that no WordPress-level cleanup will find. - Database users. More than one account may have rights on the site database.
- Scheduled tasks. Run
wp cron event listand look at the server’s own crontab. A scheduled job that re-downloads a payload every six hours will quietly undo your cleanup, and it is the most common reason a site “gets hacked again” two days later. - Third-party integrations. Payment gateway keys, SMTP credentials, and any API tokens stored in the database or in
wp-config.phpshould be treated as exposed.
If you are in the middle of this right now and the list above is longer than your evening, send us the site and the logs — emergency cleanup is work we do on a fixed scope, and the part that actually needs experience is reading the access logs to find the entry point, not running a scanner.
Minute 25–40: find the entry point
You are looking for the first request that wrote a file. Take the modification timestamp of the earliest suspicious file from your find output, then search the access log for requests within a few minutes either side of it.
# Requests around the time the first bad file appeared
grep "22/Sep/2026:14:1" access.log | grep -E "POST|admin-ajax|xmlrpc|wp-json"
# POST requests to files that should never receive them
awk '$6 ~ /POST/ {print $7}' access.log | sort | uniq -c | sort -rn | head -40Four patterns account for the overwhelming majority of WordPress compromises, and the log will usually tell you which one you are looking at:
| What you see in the log | Likely entry point | What to patch |
|---|---|---|
POSTs to /wp-json/ or admin-ajax.php from one IP, then a new file appears | Unauthenticated plugin vulnerability | Identify and update or remove that plugin |
Hundreds of POSTs to wp-login.php over hours, then one succeeds | Credential stuffing or brute force | Rate limiting, 2FA, unique passwords |
| A successful login from an unexpected country, no preceding failures | Reused or stolen password | Rotate everything, check the user’s other accounts |
| File changes with no matching HTTP request at all | Server-level or neighbouring-site compromise | Escalate to your host immediately |
That last row is worth flagging. On shared hosting a compromise can arrive sideways from another account on the same server, and nothing you do inside WordPress will fix it. If your file timestamps match no request in your own access log, open a ticket with your host before you spend three hours cleaning.
Minute 40–55: clean or rebuild?
Once you know the entry point, you have a real decision. Cleaning in place is faster; rebuilding is more certain. The honest trade-off:
| Clean in place | Rebuild from known-good sources | |
|---|---|---|
| Typical time | 2–6 hours | 6–16 hours |
| Confidence it is fully clean | Moderate — depends on how thoroughly you searched | High for code; the database still needs review |
| Risk of reinfection | Higher — one missed back door is enough | Lower |
| Best when | Single clear entry point, recent infection, small plugin footprint | Unknown entry point, infection older than your log retention, many nulled or abandoned plugins |
| Main risk | Missing a persistence mechanism | Losing undocumented customisations in the theme |
Rebuilding means fresh core from WordPress.org, fresh plugin and theme copies from their original vendors, wp-content/uploads carried across after scanning it for PHP files (there should be none), and the database migrated only after you have reviewed the users table, the options table for injected scripts, and any post content containing <script> or base64 blobs.
One warning about the step most guides put first: restoring from a backup is usually the wrong opening move. If the compromise predates your backup — and with a median of five hours from disclosure to mass exploitation, it often does — you restore the back door along with the site, and you overwrite the evidence you needed to find the entry point. Restore only once you know when the first malicious write happened, and only to a point before it.
Minute 55–60: handle Google, carefully
Check Search Console’s Security Issues report. If Google has flagged the site you will see it there, and visitors are seeing an interstitial warning in Chrome.
The temptation is to request a review immediately. Do not. Google states a review “can take from a few days to a few weeks to complete,” so you get one slow attempt at a time — and a review that fails because you missed a back door costs the whole cycle again.
There is a sharper reason to be patient. Under Google’s Safe Browsing policy, sites that repeatedly alternate between compliant and non-compliant states in a short window can be designated Repeat Offenders. That status persists for 30 days, and during it the owner cannot request another review at all. Flagged, cleaned superficially, reflagged, cleaned again is precisely the pattern that designation exists to catch.
Before requesting the review: confirm no modified files remain, the entry point is patched, no unknown admin users or scheduled tasks exist, and check the rendered HTML as Googlebot sees it — a lot of injected spam is cloaked and appears only for search engine user agents.
The 48 hours after: what people forget
Email reputation. If the compromise was used to send spam — and a large share are — your domain may be on a blocklist regardless of whether the site itself is now clean. Spamhaus’s domain blocklist is largely automated and most listings expire on their own once the associated activity stops, but you can request removal through their reputation checker, which is processed within minutes for most requesters and up to 24 hours for some. It is worth stating plainly: Spamhaus never charges a fee for removal, and anyone offering paid delisting is running a scam.
Update everything, then keep updating. Core releases are frequent and often security-driven: WordPress 7.1.1 shipped on 17 September 2026 with 11 security fixes, and 7.1.2 followed five days later on 22 September 2026 to address a critical-severity vulnerability. If your update cadence is “quarterly,” the five-hour exploitation window above is not a risk you are managing.
Re-baseline performance. Injected code costs real time — cryptominers, spam redirect logic, and unauthorised cron jobs all consume server resources. After cleanup, measure again rather than assuming you are back where you started; our WordPress speed optimization guide covers what to measure, and if the numbers are worse than you expected, the usual causes of a slow WordPress site are worth ruling out before you assume leftover malware.
Reduce the attack surface. The extensibility that makes WordPress worth using is the same thing that produced 91% of last year’s vulnerabilities. Deactivating is not enough — an inactive plugin’s files are still reachable over HTTP. Delete what you do not use.
What this costs if you get the order wrong
The expensive failure is not the hack. It is the second hack, two weeks later, from the same hole — because by then you have spent the cleanup effort twice, you may be inside a 30-day Repeat Offender window with no way to appeal, and your domain has been sending spam long enough for the blocklist entries to stick. The first hour is cheap. The second cleanup is not.
If you are looking at a compromised site and you are not confident you can find the entry point in the access logs, that is the specific thing worth handing off. Tell us what you are seeing — the file paths, the timestamps, and whether Search Console has flagged you — and we will tell you whether this is a clean-in-place job or a rebuild before anyone starts billing hours.
