WordPress

Hacked WordPress site: attack surface, incident response and what really changes

Hacked WordPress site: where automated attacks get in, how to handle the incident technically, and why fewer components matter more than a security plugin.

Fabio Folgori7 min read

Old rusty padlock on a wooden door
Photo by Arkadiusz Gąsiorowski on Unsplash

Most compromised WordPress sites I have seen were not chosen by someone. They were found by a scanner. Attacks on WordPress are almost always automated: bots mass-testing a vulnerability just disclosed in a popular plugin, or credentials stolen elsewhere. Understanding this changes how you respond and, above all, how you prevent it.

Where they get in

WordPress core is mature and patched quickly. The risk is almost always elsewhere.

  • Vulnerable plugins and themes: most vulnerabilities reported in the ecosystem concern third-party components. Unchecked file uploads, AJAX or REST endpoints without permission checks, SQL injection in search filters, privilege escalation from registered user to administrator.
  • Abandoned components: plugins removed from the official repository but still active on thousands of sites. Nobody will ever ship the fix.
  • "Nulled" themes and plugins: pirated copies of commercial products, often distributed with a backdoor already included.
  • Credentials: reused passwords, shared admin accounts, no second factor. wp-login.php and xmlrpc.php are hammered constantly.
  • Hosting: overly loose file permissions, unsupported PHP versions, several sites under the same system user, so compromising one infects the others.

The key point is the exposure window: between the disclosure of a vulnerability and the site actually being updated, hours, days or weeks pass. Automated scanners start exploiting it quickly. Priority depends on real exposure, the privileges the attack requires and the availability of a fix or mitigation.

Recognising the compromise

Visible signs (redirects to other sites, indexed spam pages, Google Safe Browsing warnings) come late. Technical ones come earlier:

  • unknown administrator users in wp_users, or capabilities altered in wp_usermeta;
  • PHP files in wp-content/uploads, which should contain none;
  • core files that do not match the official checksums (verified with WP-CLI);
  • must-use plugins or drop-ins nobody installed;
  • options in wp_options with obfuscated code, unknown cron jobs;
  • spikes of unusual POST requests in the server logs.

Spam injected only for Googlebot (cloaking) is a classic: the site looks normal to visitors, but Search Console shows pages in languages or topics that are not yours.

Incident response, in order

  1. Contain and start the privacy assessment: isolate the environment, preserve files and logs and inform the data controller at once. A maintenance page does not necessarily block endpoints, cron jobs or outgoing traffic. If personal data is involved, notification obligations are assessed immediately, without waiting for the clean-up to end.
  2. Snapshot: a full copy of files, database and logs as they are. It is how you understand what happened and since when.
  3. Rotate every credential: WordPress admins, database, FTP/SFTP, hosting panel, API keys stored in the site. Regenerate the salts and keys in wp-config.php to invalidate active sessions.
  4. Find the vector: match file modification dates with access logs, check which components had known vulnerabilities in that period. Without this step, the clean-up is temporary.
  5. Rebuild, don't scrub: core, themes and plugins are reinstalled from official sources, never "cleaned" by hand. The database is reviewed table by table. Uploads are filtered by file type.
  6. Close the hole: update or remove the vulnerable component. If it is abandoned, replace it.
  7. Bring it back online and request a review in Search Console if the site was flagged.
  8. Document the incident and complete the privacy obligations, started already during containment, if personal data is involved.

The backup is most useful at this stage: not to roll back blindly, but to compare a healthy state with the compromised one.

Prevention: fewer components, not more layers

The instinctive response to an attack is to add a security plugin. It helps on some fronts, but it is more code inside the same application you are trying to protect. The measures that really count are structural:

  • cut plugins down to the essential ones, chosen for active maintenance and vulnerability history;
  • timely, tested updates on a staging environment, with a procedure rather than "whenever";
  • two-factor authentication for every administrator, minimal roles for everyone else;
  • DISALLOW_FILE_EDIT to disable the built-in editors, together with file permissions and minimal roles. It does not by itself prevent the installation of plugins or other changes allowed to an administrator;
  • no executable PHP in uploads, enforced at server level;
  • a WAF in front of the site, blocking known exploits before they reach WordPress;
  • file integrity monitoring and alerts on new administrators.

How I set this work up over time is covered in WordPress maintenance: the real cost over time.

An open door nobody walks through

The WordPress admin is a door always open on the web: anyone can knock on wp-login.php, and bots do it all day. That is fine if someone really comes in every day. But in my experience almost every client asks for the admin "to be able to edit the site", and very few then use it: a text changed now and then, a news item every few months. For that handful of logins you keep a database needed for the application to run, PHP executed on every request and dozens of components to update. It is a door left open for a guest who never arrives.

A site generated in advance and served from a CDN, like the ones I build with Nuxt.js and Netlify, does not run server-side code on every visit, does not expose a database and has no public login panel. The most common class of attacks against WordPress simply has no target. The surface moves: the GitHub account, the hosting provider account and the domain registrar remain to be protected, three accounts with two-factor authentication instead of dozens of components. And every change goes through a tracked commit, which helps analysis and recovery. This requires protected repositories, permissions and pipelines: traceability alone does not prevent a compromise.

Credentials and rebuilding the environment

Exposed credentials must be revoked from a trusted device and channel, avoiding introducing new keys into the system that is still compromised. After the rebuild I check sessions, tokens, provider access and account privileges again, completing the necessary rotation in the new environment.

A maintenance mode in the application is not the same as isolating the server. Containment must consider endpoints still reachable, scheduled processes, other sites under the same user and outgoing connections. I log the actions and keep protected copies of the evidence, without including secrets in the reports.

The privacy assessment runs in parallel: the deadline for any notification starts from the moment the personal data breach is known, not from the end of the investigation. The controller also documents the reasoned decision not to notify, when the conditions apply.

Reference: GDPR, Articles 33 and 34.

My take

I have built with WordPress for many years and I still love it. But today, for a new project, the first question I ask is no longer "which theme?", it is "who will log into the admin, and how often?". If the answer is "an editor every day", WordPress remains a sensible choice, kept lean and followed with a procedure. If the answer is "maybe a few times a year", leaving the door open as a precaution is the risk I avoid: the site moves to Markdown or an external CMS, some attack vectors are reduced, while dependencies, accounts, pipelines and external services still have to be protected.

This is not a crusade against WordPress: I have cleaned enough sites to know the problem is rarely the fault of whoever runs them, it is an architecture where everything is tied to everything and one neglected plugin is enough to bring it down. For those who stay, maintenance matters more than any security plugin; for those who do not need the admin, moving to a static architecture is the most effective security measure I know.

Why work with me

Since 1999 I have delivered more than 300 projects and I work with more than 30 agencies, from Rome and remotely, and I have cleaned up enough hacked sites to know where they get in. I handle WordPress incidents methodically: containment, vector analysis, clean rebuild, then a plan so it does not happen again.

If your site has been compromised, or you fear it has, get in touch: first we find out how they got in, then we decide how to get it back on its feet. The service is in WordPress maintenance.

Frequently asked questions

Only if the backup predates the compromise and the entry point is closed. Many attacks lie dormant for weeks: restoring without knowing how they got in means reopening the same door.

It reduces some risks (brute force, known malware signatures), but it runs inside the same WordPress it is supposed to protect. If the vulnerable code is a plugin, the security plugin often notices afterwards.

If the site processes personal data and there has been a breach, the GDPR may require notifying the supervisory authority within 72 hours and, in some cases, the people affected. It should be assessed straight away with whoever handles privacy.

It can be, but the surface is much smaller: no PHP running on every request, no database needed to serve static pages, no public panel. What remains to protect are the GitHub, provider and domain accounts, with two-factor authentication.

  • #hacked website
  • #wordpress security
  • #malware
  • #incident response
  • #maintenance

More articles

// Contact

A project, a problem or just a question?

Agency, business or professional: choose how you'd rather talk to me. I reply as soon as I can, no strings attached.