
When WordPress Patches Aren’t Enough: Incident Response for Live Exploitation of Recent Bugs
What active exploitation changes for WordPress operators
The shift is simple: a patched WordPress bug is maintenance, but a patched bug that is already being exploited is an incident-response problem.
If your site was exposed during the live exploitation window, patching is necessary but not enough. You need to know whether the attacker only had a chance to reach you or whether they already did. That answer determines what you preserve, what you rotate, and whether the system is still trustworthy.
| Site state | What you should do first | Why |
|---|---|---|
| Exposed, no evidence of compromise | Preserve logs, patch, then inspect | You may still need the evidence |
| Confirmed compromise | Contain, preserve, rebuild or restore | Assume persistence exists |
| Unclear because logs are missing | Treat as compromised until disproven | Absence of evidence is not evidence |
The TechCrunch report says attackers are already using recently patched WordPress bugs. That is the operational detail that matters. The window is live, not hypothetical. Once a bug is public and weaponized, this is no longer normal patch management.
Why a patch is not the finish line during live exploitation
A patch closes one path. It does not remove a dropped web shell, revoke a stolen admin cookie, undo a cron job, or clean an injected database redirect.
That is why I dislike the usual “update and move on” reflex. During active exploitation, the patch is only step one. Step two is deciding whether the site was merely exposed or actually touched. Step three is finding everything the attacker may have changed before the fix landed.
Exposed-but-uncompromised versus confirmed compromise
I keep the split strict:
- Exposed but unconfirmed: the vulnerable version was reachable, but I do not yet see new admins, file changes, suspicious outbound connections, or odd scheduled tasks.
- Confirmed compromise: I see one or more hard indicators, such as a new administrator account, PHP in uploads, a modified plugin file, a malicious
mu-plugin, an unexpected redirect in the database, or a cron entry that should not exist.
The key point is that “looks fine” does not mean “safe” unless you checked the places attackers actually use for persistence. WordPress incidents often hide in plain sight because the public site still loads normally.
The first 24 hours matter more than the CVE headline
The first day is when you still have evidence.
If you patch first and inspect later, you can overwrite the best clues: timestamps, log lines, attacker-created files, and volatile auth state. If you wait too long, your hosting platform may rotate logs or your backup system may overwrite the useful snapshot.
My usual order is:
- Preserve what exists.
- Limit further access.
- Patch from a trusted source.
- Verify the patch.
- Hunt for persistence.
It is not flashy, but it is how you avoid turning a recoverable intrusion into a guessing game.
Triage the vulnerable site before you touch anything else
Identify the affected core, plugin, or theme version
Start by recording exactly what is installed. Do not trust the admin dashboard if you suspect tampering.
Useful commands:
wp core version
wp plugin list --status=active
wp theme list
If the site is managed through Composer or a deployment pipeline, record those manifests too. I want the exact version string, the deploy commit, and the package source. If you cannot name the installed version, you do not really know what you are running.
For a quick local inventory, I also like:
wp core verify-checksums
wp plugin verify-checksums --all
If those checks fail, that is not proof of compromise by itself, but it is a strong reason to stop assuming the tree is clean.
Capture a baseline of files, accounts, and recent changes
Before changing anything, capture a baseline so you can compare later.
find wp-content -xdev -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort | tail -n 50
wp user list --fields=ID,user_login,user_email,roles,registered_date
wp cron event list
I am looking for:
- recent files in
wp-content - unexpected administrator accounts
- new scheduled events
- timestamps that line up with the suspected compromise window
If the site is small enough, keep a checksum manifest of wp-content, wp-config.php, and any custom plugin directories. On larger installs, at least hash the directories that should stay stable.
Separate frontend errors from backend evidence
A broken page is not the same thing as a hacked site.
JavaScript errors, 500 responses, and white screens can come from a bad deploy, a plugin conflict, or a PHP fatal error. They are useful clues, but they do not tell you whether an attacker got code execution.
What I check instead:
grep -R "POST " /var/log/nginx /var/log/apache2 2>/dev/null | tail -n 50
grep -R "wp-login.php" /var/log/nginx /var/log/apache2 2>/dev/null | tail -n 50
tail -n 200 /var/log/php*-fpm.log 2>/dev/null
If you have application-level logs, correlate them with file timestamps and user creation times. Frontend noise is common. Backend evidence is what matters.
Contain the blast radius without destroying evidence
Restrict admin access and pause risky automation
If you think the site is being actively exploited, reduce who can reach the admin surface right away.
Practical containment steps:
- restrict
/wp-adminto trusted IPs or VPN users - pause deploy jobs and plugin auto-updaters
- suspend external integrations that can create side effects
- disable unnecessary XML-RPC access if it is not needed
I would not delete suspicious files yet unless they are actively causing damage. Quarantine is better than cleanup at this stage.
Rotate passwords, API keys, and session tokens
After you have preserved evidence, rotate everything that could be abused again:
- WordPress administrator passwords
- database credentials
- SSH/SFTP credentials
- cloud console credentials
- SMTP, analytics, payment, and webhook secrets
- WordPress salts and session tokens
For WordPress salts, the CLI makes this easy:
wp config shuffle-salts
That is a blunt but effective step. It invalidates existing cookies, which is exactly what you want if you suspect token theft. Just make sure you are ready for every logged-in user to be signed out.
Preserve logs, backups, and a forensic snapshot
Before major cleanup, preserve the site state.
A safe pattern is:
rsync -aHAX --numeric-ids /var/www/example/ /evidence/example/
tar -czf /evidence/example-logs.tgz /var/log/nginx /var/log/apache2 /var/log/php* 2>/dev/null
If you can snapshot the whole VM, do that too. A filesystem copy is useful, but a VM snapshot often preserves more timing information and gives you a second chance if cleanup goes sideways.
Do not trust a single backup. I have seen backups that already contained the compromise.
Check the common WordPress persistence paths
New admin users, changed roles, and suspicious logins
Account abuse is one of the first things I check.
wp user list --role=administrator --fields=ID,user_login,user_email,registered_date
wp db query "SELECT user_login, user_registered FROM $(wp config get table_prefix)users ORDER BY user_registered DESC LIMIT 20;"
I am looking for:
- an admin user created during the incident window
- a legitimate user whose role changed
- logins from unusual IPs or geographies
- password resets that nobody requested
If you have auth logs from the host or SSO provider, correlate them with the user table. A new admin account is usually not subtle.
Web shell patterns in wp-content, uploads, and mu-plugins
Attackers like places that survive updates.
The usual hiding spots are:
wp-content/uploadswp-content/mu-plugins- custom theme directories
- plugin folders with recently modified PHP files
A few defensive searches help:
grep -R --line-number -E "base64_decode|gzinflate|eval\(|assert\(|shell_exec|system\(" wp-content 2>/dev/null
find wp-content/uploads -type f \( -name '*.php' -o -name '*.phtml' -o -name '*.php5' \)
Not every obfuscated string is malicious, but new executable PHP in uploads is a red flag. So is an mu-plugin you do not recognize.
Database changes, redirects, and injected scheduled tasks
WordPress attackers love the database because it is persistent and easy to overlook.
Check these areas first:
siteurlandhomeactive_pluginscron- widget settings
- theme options
- post content for injected redirects or spam
Examples:
wp option get home
wp option get siteurl
wp cron event list
If the homepage or login page suddenly redirects, the problem may live in a database option rather than a PHP file. That is why “delete the suspicious file” is such a weak response on its own.
Patch, then verify that the patch actually closed the hole
Update from trusted sources and confirm exact versions
Use the official WordPress update mechanism, a trusted package repository, or your deployment pipeline. Do not grab a random ZIP from an unknown mirror just to move faster.
After updating, record the exact installed versions again:
wp core version
wp plugin list --status=active
wp theme list
If the vendor advisory named a fixed version, compare against that number directly. “Updated” is not a version. It is a feeling.
Re-test the vulnerable path in a safe lab or staging copy
Do not re-test on production if you can avoid it. Clone the site into staging or a local container, then replay the exact request pattern you found in logs.
What you want to see after the fix is simple:
- the request is rejected
- the vulnerable action no longer succeeds
- the response changes from success to failure in a way that matches the patch
If you cannot safely reproduce the original request, at least verify the affected plugin or core component no longer exposes the route, parameter, or behavior that made exploitation possible.
Look for signs that a second payload arrived before the fix
This is the part many teams miss. The first payload is often a loader. The second payload is the actual persistence layer.
Watch for:
- new files created shortly before patching
- recently modified theme or plugin files
- unexpected outbound HTTP requests from the web server
- odd
cronentries that point to external URLs - PHP processes connecting to uncommon domains
If the patch went in after the attacker already landed a second-stage payload, the code fix is not the end of the story.
Recover cleanly instead of just deleting obvious malware
Replace known-bad files and compare against clean backups
If you can identify infected core files or plugin files, replace them from a trusted source. Do not edit malware out by hand unless you have no other choice.
My rule is:
- restore core from the official release
- restore plugins from vetted package sources
- compare custom code against version control
- keep content separate from executable code
If a backup is known clean, use it. If the backup might also be contaminated, treat it as untrusted until proven otherwise.
Rebuild from a trusted image when integrity is uncertain
If you cannot trust the host, rebuild it.
That sounds heavy, but it is often faster than trying to prove a whole server is clean. A fresh image with known-good code and a clean database import is usually safer than trying to disinfect a machine that has already been used as an attacker workspace.
I would strongly prefer a rebuild when:
- the root cause is still unclear
- you found multiple persistence mechanisms
- core system integrity is in doubt
- logs are incomplete or rotated away
Restore content carefully so you do not bring the attacker back
The dangerous mistake is restoring everything blindly.
Be selective:
- restore posts and media after inspection
- review user accounts before importing
- inspect serialized options and plugin settings
- verify that media directories do not contain executable PHP
- re-check the database for redirects or injected content after import
If you imported the old database and the backdoor came with it, you only recreated the incident.
What to monitor for the next week
File writes, admin creation, and outbound requests
The first week after remediation is where reinfection tends to show up.
I would alert on:
- new files in
wp-content - changes to
mu-plugins - new administrator accounts
- password resets
- outbound requests from the web server to unfamiliar domains
If you have file integrity monitoring, turn it back on. If you do not, at least schedule a daily diff against the clean baseline you captured earlier.
WAF, web server, and authentication logs
Correlate three log sources:
| Source | What to look for |
|---|---|
| WAF / reverse proxy | blocks against the vulnerable route, repeated probes |
| Web server | suspicious POSTs, file uploads, odd user agents |
| Auth logs | admin logins, failed logins, session reuse |
A spike in blocked requests after patching is useful. It tells you the site was visible to scanners and maybe to opportunistic attackers too.
Alerts for reinfection after password rotation
Password rotation is not magic if a backdoor still exists.
Watch for:
- a new login immediately after rotation
- admin creation without a corresponding deployment
- plugin installs or updates you did not authorize
- outbound callbacks from PHP processes
If any of those happen, assume the attacker still has a path in.
The practical position: patching is mandatory, but incident response is the real defense
My conclusion is blunt: in a live WordPress exploitation wave, patching is table stakes. The real defense is everything you do around the patch.
That means:
- preserve evidence before you overwrite it
- decide whether the site was touched, not just vulnerable
- check the boring persistence paths attackers actually use
- verify the fix instead of trusting the update banner
- rebuild if integrity is unclear
The headline bug is only the entry point. The incident is everything that happened after it.


