WordPress Is Patched. That Doesn’t Mean It’s Recovered.
- account_circle SaidWP - Post
- calendar_month Wednesday, 2 Sep 2026
- visibility 58
- comment 0 comment
- print Cetak

info Adjust the font size of this article to get the best reading experience.
When a WordPress vulnerability is discovered, updating the site should happen quickly. But an update only closes the vulnerability we know about. It doesn’t remove an administrator account an attacker already created, a file they already uploaded, an active session, or changes already written to the database.
In one client project I worked on, the first signs looked like a WordPress-level problem: content had been changed, an unfamiliar account had appeared, and there were several suspicious uploads.
Around the same time, the logs also showed activity on the REST batch endpoint. The problem was that the logs only captured the request to the endpoint. They didn’t include the request body or the subrequests inside it. The activity was suspicious, but it wasn’t enough to tell us how the attacker got in.
Names, addresses, logs, paths, and other details in this article have been generalized. This isn’t a client incident report or an exploitation guide. The focus here is what happens after the vulnerability is found and WordPress has already been patched.
There’s Still Work to Do After the Patch
wp2shell drew attention because it involved WordPress’s REST API batch handling and an issue in the query layer. WordPress has released security fixes for the affected issue, including releases across multiple supported branches.
To check which versions have received the fix, use the WordPress security releases page directly. A version number copied from an older article may already be outdated.
The patch closes the vulnerability. The attacker may still have had time to do other things before that patch was installed.
If they were able to execute code inside WordPress, they could have created a new administrator, changed options, written files, created sessions, or read credentials stored by the application. Clicking Update doesn’t undo any of that.
Don’t Rush to Delete the Evidence
When you find an unfamiliar account or a page that has been changed, the first instinct is usually to clean it up immediately.
But those accounts, files, and changes may help explain what happened and when.
Before making broad changes to the site, preserve what you can:
- Record the symptoms, affected URLs, and when they were first observed.
- Save relevant web, application, authentication, and container logs.
- Take a database dump and copies of persistent files or volumes.
- Inventory users, plugins, themes, uploads, scheduled tasks, containers, and external integrations.
- Hash important artifacts and store copies somewhere with restricted access.
If the site is actively putting visitors at risk, you don’t have to leave it online just to preserve evidence. Disable the affected access or functionality first, and record what was changed.
The response also doesn’t need to be broader than the problem. Disabling the entire REST API, for example, can break editors or plugins that aren’t involved in the incident.
A REST Batch Request Doesn’t Prove the Entry Point
Several signals appeared close together in this case:
| What we saw | What it tells us | What it doesn’t tell us |
|---|---|---|
| Requests to the REST batch endpoint | There was activity on that endpoint | Whether the request was actually an exploit |
| An unfamiliar administrator account | Someone gained access they shouldn’t have had inside WordPress | How the account was created |
| New plugins, themes, or uploads | They may be related to the attack and need inspection | Whether those files were ever executed |
| PHP or polyglot files in uploads | Those files deserve immediate attention | Whether the attacker gained control of the entire VPS |
| Nothing suspicious found on the host | No further host-level signs were found during that check | That the host is definitely clean |
The REST batch activity still had to be matched against other evidence.
The logs showed the request and its status, but not the body or the result of each subrequest. Without those details, there wasn’t enough evidence to say that wp2shell was the confirmed entry point.
The WordPress documentation for batch requests also makes clear that this endpoint is a normal part of the REST API. A request to it, by itself, isn’t evidence of exploitation.
Restricting the REST API Without Breaking It
The endpoint that appeared during the investigation was:
POST /wp-json/batch/v1
The REST API is also used by normal editors and plugins. If the concern is a specific endpoint or request pattern, the protection should be aimed there rather than at all of /wp-json/.
That might include:
- rate limiting the relevant path and method at the edge;
- adding an origin-side guard for requests that can reach the server directly;
- making sure real-IP configuration only trusts proxies you actually manage;
- using Fail2ban for direct-to-origin traffic where it makes sense, rather than treating it as a replacement for a WAF or CDN rate limiting.
The rate-limit values shouldn’t simply be copied from another site.
First look at normal traffic from editors, administrators, and plugins that write content. Once the rule is in place, test both normal requests and requests that cross the limit. If the rule needs to be rolled back, the rollback path should already be clear.
A WordPress Breach Doesn’t Automatically Mean the VPS Is Owned
A serious WordPress issue doesn’t automatically mean the entire VPS has been taken over.
The reverse is also true: failing to find a suspicious file on the host isn’t enough to declare the server clean.
It helps to look at each layer separately:
- WordPress: users, core files, plugins, themes, uploads, options, scheduled tasks, and sessions.
- Containers and volumes: images, writable mounts, processes, networking, and persistent data.
- Host: users, services, timers, processes, SSH, the Docker socket, and sensitive mounts.
- Connected services: backups, DNS, registries, credentials, and other applications.
If everything found so far is inside WordPress and the host checks don’t reveal anything else, rebuilding the entire VPS may not be necessary.
But that still isn’t enough to write, "the host is clean." The accurate statement is narrower: based on what was checked, there were no signs that the attacker reached the host level.
You Have a Backup. Can You Actually Restore It?
A code repository doesn’t contain media, the database, users, options, or the full runtime configuration. A database dump alone may not be enough to bring the site back to its previous state either.
Before relying on a backup, check:
- whether it contains the database, uploads, application files, and configuration you need;
- whether it was created before the incident;
- how much legitimate data would be lost by rolling back to it;
- whether it can actually be restored in an isolated environment.
If the archive is encrypted, decrypt it. If hashes are available, verify them. Restore the database and volumes, then start the application.
A backup completed status doesn’t mean much if nobody has ever tested the restore.
A Fresh Installation Is Usually the Safer Starting Point
Once the evidence you need has been preserved and you have a reasonable idea of what was affected, deleting a few suspicious files until the old installation looks normal again may not be enough.
Where possible, build a fresh WordPress installation from core files, plugins, themes, images, and configuration whose origin you know. Then bring back the data you’ve already reviewed.
That can look something like this:
- Patch WordPress and any exposed components.
- Get WordPress core, plugins, themes, images, and configuration from trusted sources.
- Use a new database and volumes where practical.
- Review users, options, uploads, posts, scheduled tasks, and sessions before bringing them back.
- Rotate credentials that may have been exposed and invalidate relevant sessions.
- Test login, public pages, the REST API, cron, integrations, logs, and writable directories.
The old installation can stay offline for a while if it’s still useful for investigation or rollback.
What it shouldn’t become is the shortcut back to production just because the homepage looks normal again.
Don’t Claim More Than the Evidence Shows
In this case, there were changes and artifacts inside WordPress that shouldn’t have been there. There was also activity on the REST batch endpoint during the same period.
What wasn’t available was evidence that:
wp2shell was definitely used as the entry point.
The request body, the results of the subrequests, and a timeline strong enough to connect everything weren’t available.
A possible WordPress RCE is also a good reason to inspect the host. It doesn’t automatically prove that the attacker took over the entire VPS.
If the evidence only supports saying that WordPress was affected and no further host-level signs were found, stop there.
WordPress Recovery Checklist
- ☐ The immediate impact has been contained without destroying evidence that may still be useful.
- ☐ Relevant logs, database data, files, volumes, and runtime metadata have been preserved.
- ☐ WordPress core, plugins, and themes have been updated from trusted sources.
- ☐ Users, sessions, uploads, scheduled tasks, and database options have been checked.
- ☐ At-risk credentials have been rotated and old sessions invalidated.
- ☐ The backup has been test-restored in an isolated environment.
- ☐ WordPress, containers, the host, and connected services have been checked as needed.
- ☐ The final notes distinguish what was found, what is still a hypothesis, and what still needs monitoring.
A site isn’t recovered just because the homepage looks normal again.
Before bringing it back online, you should at least know which files you trust, which accounts belong there, and which backup can actually be restored.
If those answers aren’t clear yet, the patch may be done. The recovery isn’t.
Sources and Editorial Notes
- Author: SaidWP - Post
At the moment there is no comment