If your WordPress site was hacked once, the job is not finished just because the homepage loads again. That is the mistake site owners make over and over. Visible cleanup is not the same thing as removing persistence, closing the access path, rotating compromised credentials, checking the server layer, or cleaning up the SEO damage that can keep hurting you long after the obvious malware is gone. If you want to secure WordPress after infection, you are not doing a cosmetic cleanup. You are doing incident recovery.

The practical post-infection job is bigger than “scan, delete, move on.” You need to remove persistence, rotate every meaningful credential, verify file integrity, decide whether the hosting layer is still trustworthy, and clean up the Google fallout. If you skip those steps, a WordPress site can look clean while the attacker still has a usable path back in, spam pages remain indexed, unknown admin access still exists, or the same weak environment that allowed the breach is still sitting there waiting for the next exploit.

This article is intentionally not a generic malware cleanup guide. ServerSpan already has related material for cleanup itself, including How to Clean and Secure Your Hacked WordPress Website and the more specific Japanese keyword hack cleanup guide. This piece starts after the obvious cleanup. It is the hardening, persistence-hunting, reinfection-prevention, and SEO-recovery runbook that should happen next.

It is also a Type B article, so here is the blunt truth early: some compromises should no longer be handled as DIY projects, especially on weak shared hosting, opaque reseller environments, or messy unmanaged servers where you cannot verify logs, file ownership, web server rules, or what else is running in the same account. In those situations, the problem is not just WordPress. The problem is the environment.

Before You Harden Anything, Confirm It Was Actually Compromised

Do not confuse a broken plugin, a white screen, or a failed update with a confirmed compromise. A hacked WordPress site usually leaves different evidence. Sometimes that evidence is loud. Sometimes it is subtle. The important part is to establish whether this was really an infection, an access compromise, or an ordinary application failure.

  • Spam pages still appear in site:example.com search results.
  • Redirects happen only for visitors, crawlers, mobile traffic, or selected user agents.
  • You find an unknown admin user in WordPress.
  • wp-config.php, .htaccess, or plugin files were modified unexpectedly.
  • Your host sent abuse notices about phishing, spam, or malicious outbound traffic.
  • Google Search Console shows security warnings or strange indexed URLs.
  • A rogue sitemap exists, or Search Console lists sitemap paths you did not submit.
  • You restored from backup, but the site was reinfected again.

That last point matters. “WordPress reinfected after cleanup” is not just a frustrating user query. It usually means the first cleanup was incomplete, the access path was never closed, or another copy of the site in the same account remained infected. This is also why “WordPress hacked but looks clean” is such a dangerous state. A visually normal homepage proves almost nothing.

Use fast checks first:

site:example.com
site:example.com viagra
site:example.com casino
site:example.com japanese
site:example.com filetype:php
site:example.com inurl:sitemap

Those searches are not forensic proof, but they are fast indicators. If you see spam titles, spam directories, rogue query pages, or language patterns that do not belong on your site, treat that as compromise until proven otherwise.

Also check the actual WordPress admin user list from the command line if you can:

wp user list --role=administrator --fields=ID,user_login,user_email,user_registered

This proves more than the Users screen does in a rushed browser session. It gives you a clean list to compare against what should exist. If there is an unknown admin user, you are not “probably fine.” You were compromised or you still are.

Step 1: Freeze the Scene and Take a Real Backup

Do not start deleting files as your first move. Take a real backup first. Not because you want to restore the hacked state. Because you need evidence, rollback, comparison material, and something to inspect if your first cleanup attempt misses persistence.

Capture all of this before you mutate the environment further:

  • Full website files
  • Full database dump
  • Available web access and error logs
  • Current plugin inventory
  • Current theme inventory
  • Screenshots from Search Console Security Issues and indexing views
  • A list of suspicious URLs already indexed
  • Current cron jobs and scheduled tasks

If you have WP-CLI, capture the software inventory into files so you can compare later:

wp plugin list --format=csv > plugins-before-hardening.csv
wp theme list --format=csv > themes-before-hardening.csv
wp user list --format=csv > users-before-hardening.csv
wp option get home
wp option get siteurl

The inventory matters because post-hack WordPress recovery is often a comparison exercise. Which plugin was present? Which theme changed? Which user existed before the compromise? If you do not capture the current state, you are making later decisions from memory. That is weak incident handling.

On the server side, copy logs before rotation clears your best clues. Typical paths are:

  • /var/log/nginx/
  • /var/log/apache2/
  • /var/log/php*-fpm.log or pool-specific PHP-FPM logs
  • /var/log/auth.log

If you are on shared hosting and you cannot access logs beyond a superficial panel view, that is already one of the signals this may not be a rational DIY situation anymore.

Step 2: Reset Every Access Point, Not Just wp-admin

This step is where many site owners fool themselves. They change the WordPress admin password and think they have “secured the site.” That is not post-compromise security. That is one tiny part of it.

Rotate every meaningful access point:

  • WordPress admin passwords
  • Hosting panel password
  • SFTP and FTP credentials
  • Database password
  • Email accounts tied to password recovery
  • CDN or WAF credentials
  • API tokens
  • Search Console and analytics access if compromise touched ownership or scripts

Then rotate WordPress authentication salts in wp-config.php. That invalidates existing cookies and forces session loss for users still holding old auth state.

A standard security block in wp-config.php should now include, at minimum:

define( 'FORCE_SSL_ADMIN', true );
define( 'DISALLOW_FILE_EDIT', true );

FORCE_SSL_ADMIN makes logins and admin sessions use HTTPS. DISALLOW_FILE_EDIT disables the built-in plugin and theme file editors, which are one of the first places an attacker uses if they obtain admin access. This does not stop malware by itself. It removes one easy code-execution path after compromise.

You can also consider:

define( 'DISALLOW_FILE_MODS', true );

Use that carefully. It blocks plugin and theme installs and updates from the dashboard. On a tightly managed environment with a real deployment process, that can be good. On a small business site where updates are only applied through wp-admin, it can become self-inflicted operational pain. Post-compromise, the right question is not “can I lock everything down harder?” It is “what workflow am I replacing it with?”

Also review administrator accounts aggressively:

wp user list --role=administrator --fields=ID,user_login,user_email,roles,user_registered

And if you suspect hidden or unusual role assignments, query capabilities directly using the real table prefix:

PREFIX=$(wp db prefix)
wp db query "SELECT u.ID,u.user_login,u.user_email,m.meta_value \
FROM ${PREFIX}users u \
JOIN ${PREFIX}usermeta m ON u.ID=m.user_id \
WHERE m.meta_key='${PREFIX}capabilities';"

If a suspicious admin account exists, remove it only after you understand whether it created scheduled tasks, modified plugins, or planted persistence elsewhere. Deleting the user is necessary. It is not sufficient.

Step 3: Prove the Core Files Are Clean

If you cannot verify WordPress core integrity, you are guessing. And guessing is how “WordPress malware keeps coming back” turns into a recurring problem.

Start with official checksums:

wp core verify-checksums
wp plugin verify-checksums --all --strict

The first command compares your core files against official WordPress.org checksums without loading WordPress. The second checks plugins against repository checksums and, with --strict, even flags softer file changes like modified readmes. That does not prove the site is safe. It proves whether official components match their known-good sources.

There are limits, and you need to understand them:

  • Premium plugins often cannot be verified this way.
  • Custom plugins cannot be verified this way.
  • Custom themes cannot be trusted automatically.
  • Modified official plugins will fail checksums, but you still have to decide whether that was malicious or just someone editing in production.

That is why “the scanner found nothing” is weak evidence. If premium or custom code is involved, your trust model changes. The safer move is often not to edit suspicious files manually. It is to reinstall clean copies from the actual vendor source or your own version control.

If the checksums fail on core, do not debate it. Replace core files from a clean source.

Step 4: Hunt the Persistence Mechanisms That Usually Cause Reinfection

This is the section that separates real post-compromise work from shallow cleanup. Most reinfections happen because persistence survived the first cleanup. Not because WordPress is cursed. Not because the malware “came back by itself.” It came back because something still had a path to execute.

File system sweep

Look for recently modified files first. That gives you a fast picture of what changed around the compromise window.

find . -mtime -10 -ls
find . -type f -name "*.php" -mtime -10 -ls

That proves where recent file changes happened. It does not prove they are malicious, but it narrows the search dramatically.

Then inspect for common payload patterns:

grep --include=*.php -Rni . -e "base64_decode" -e "gzinflate" -e "str_rot13" -e "shell_exec" -e "passthru" -e "assert\s*(" -e "eval\s*("

find wp-content/uploads -type f \( -name "*.php" -o -name "*.phtml" -o -name "*.phar" -o -name "*.php7" -o -name "*.php8" \) -print

Expect false positives. Plenty of legitimate code uses compressed payloads or encoded strings. The point is not to delete every match. The point is to find what does not belong in that site.

Pay special attention to these locations:

  • wp-content/uploads/
  • wp-content/mu-plugins/
  • Unexpected plugin folders with harmless-looking names
  • wp-config.php
  • .htaccess
  • Custom drop-ins such as object cache or maintenance stubs

Uploads is a favorite persistence location because site owners often trust it as “just media.” It is not just media if PHP or other executable payloads were planted there. A post-cleanup WordPress site infected again after a few hours or a few days often has an executable file in uploads, a malicious MU plugin, or a redirect rule hidden in server config.

Database and user sweep

Not all persistence is file-based. Inspect the database for rogue options, suspicious scheduled tasks, spam content, and users you do not recognize.

wp user list --fields=ID,user_login,user_email,roles,user_registered
wp cron event list
wp option list --search="siteurl"
wp option list --search="home"

Then inspect suspicious content directly in the database if needed. This is especially relevant if the site was hacked but still spam pages remain in Google:

wp search-replace "spam-domain.example" "spam-domain.example" --dry-run --report-changed-only
wp db export before-db-deep-inspection.sql

The dry run is useful as a search mechanism because it shows where suspicious strings still exist without changing anything. If the compromise included injected SEO spam, this is often where the real size of the mess becomes obvious.

If the visible symptom was Japanese keyword hack or spam indexing, ServerSpan’s Japanese keyword hack guide is the right adjacent read for database-side spam removal. This article assumes you are already past the obvious cleanup and are now preventing the next round.

Environment sweep

Reinfection is often outside the visible WordPress folder. Check for abandoned subdomains, old development copies, and exposed backup files sitting under the same account.

find .. -maxdepth 4 \( -name wp-config.php -o -name wp-load.php \) -print
find . -maxdepth 3 \( -name "*.zip" -o -name "*.tar" -o -name "*.gz" -o -name "*.sql" \) -ls
crontab -l
ls -la /etc/cron* 2>/dev/null

Those commands help answer questions that matter after a hack:

  • Is there another forgotten WordPress copy in the same hosting account?
  • Is there an old backup archive exposed under the web root?
  • Is a scheduled task re-dropping malware on a timer?
  • Did a “staging” or “old” subdomain remain infected while you only cleaned the main site?

Also test redirects under different conditions. Some malicious redirect logic only triggers for certain user agents or clean sessions.

curl -I https://example.com/
curl -A "Mozilla/5.0" -I https://example.com/
curl -A "Googlebot/2.1 (+http://www.google.com/bot.html)" -I https://example.com/

Then repeat in clean browsers, incognito sessions, and different devices. If the site behaves differently for crawlers, logged-out users, or first-time visitors, assume redirect logic is still in play somewhere.

This entire section is why “remove WordPress persistence after malware” is not a niche concern. It is the real work. If you skip it, you are not doing recovery. You are doing cleanup theater.

Step 5: Reinstall What Can Be Reinstalled

After compromise, editing files in place is often the wrong instinct. Clean replacement is safer than manual surgery on untrusted code.

WordPress core should be replaced from a clean source. Official repository plugins should be reinstalled from a clean source. Themes should be reinstalled from a clean source. Premium plugins and premium themes should be reinstalled from the actual vendor package you trust, not from some old zip someone found in Downloads.

On a standard installation, replacing core files with WP-CLI is straightforward:

wp core download --skip-content --force

That replaces WordPress core files while leaving wp-content in place. It is not a full recovery by itself, but it is a cleaner way to restore core than hand-editing infected files.

For official repository plugins, the same logic applies. Reinstall clean. Do not patch suspicious files by hand because “it seems to work now.”

Nulled, abandoned, or unverifiable components should be removed. Not quarantined for later. Not left deactivated “just in case.” Not preserved because someone paid for them three years ago and lost the license. After compromise, keeping old plugin folders just in case is stupid. Untrusted code is not a backup strategy.

If a premium or custom component is business-critical but you do not have a clean known-good source, treat that as a real escalation point. Your site may be functionally dependent on code you can no longer trust.

Step 6: Lock Down the WordPress Layer to Secure WordPress After Infection

This is the point where you stop thinking about malware removal and start thinking about reducing future attack paths.

  • Enforce HTTPS for admin with FORCE_SSL_ADMIN.
  • Disable dashboard file editing with DISALLOW_FILE_EDIT.
  • Use 2FA for administrator accounts.
  • Reduce users to least-privilege roles.
  • Remove dormant users and old contractors.
  • Lock down XML-RPC if you do not need it.
  • Implement login abuse protection.
  • Move to a safe update workflow instead of live-edit chaos.
  • Audit plugin and theme hygiene continuously.

Do not make a security plugin the hero of this story. That is lazy thinking. Use layered controls. Admin 2FA matters. Clean user roles matter. Removing dormant accounts matters. Limiting who can install or modify code matters. If your environment is sensitive, especially for agencies or small businesses with multiple admins, dashboard-based plugin and theme installs may need to be restricted or moved to a controlled deployment process.

About XML-RPC: treat it as a feature, not a sacred object. If you do not need remote publishing, mobile app integration, or tooling that depends on it, reduce or disable its authenticated surface. WordPress still exposes XML-RPC by default, and the official filter only controls methods requiring authentication, not every possible XML-RPC-related behavior. So do not use vague “I turned off XML-RPC” language unless you know exactly what you disabled and why.

And if you have not read it recently, ServerSpan’s proactive WordPress maintenance checklist is the right next internal read once the incident response phase is over. Hardening after compromise should become maintenance discipline, not one more emergency sprint.

Step 7: Lock Down the Server and Hosting Layer

This is where the article stops being a pure WordPress checklist and becomes a hosting decision. If you cannot inspect server logs, ownership, cron, vhost rules, and execution restrictions, then you are limited to surface-level cleanup. That may be enough for a very small incident. It is not enough for a trustworthy recovery on a site that matters.

Start with basic server-layer controls:

  • Fix file permissions and ownership.
  • Block PHP execution in uploads.
  • Protect wp-config.php.
  • Protect wp-admin where that fits the use case.
  • Remove abandoned WordPress copies under the same account.
  • Review web server logs for repeat POST abuse and suspicious paths.
  • Review cron and scheduled tasks outside WordPress.
  • Separate deploy discipline from live production mess.

Typical file-permission targets in standard Linux web stacks are conservative, not permissive. If directories are writable where they do not need to be writable, or if PHP runs as an ownership model you do not understand, do not blindly chmod your way through the account. Verify who owns the files, which user PHP-FPM or Apache is running as, and what the write paths actually need to be.

At the web server layer, blocking PHP execution in uploads is one of the highest-value changes after compromise.

Apache example for uploads

<FilesMatch "\.(php|phtml|phar|php[0-9]?)$">
    Require all denied
</FilesMatch>

Place that in the relevant uploads path only, not blindly across the whole site.

Nginx example for uploads

location ~* ^/wp-content/uploads/.*\.(php|phtml|phar|php[0-9]?)$ {
    deny all;
}

That belongs in the correct server block under /etc/nginx/, and you should test it before reload.

Protect wp-config.php

<Files "wp-config.php">
    Require all denied
</Files>
location = /wp-config.php {
    deny all;
}

Then review logs in the places that actually matter:

  • /var/log/nginx/
  • /var/log/apache2/
  • PHP-FPM pool logs
  • auth logs for SFTP, SSH, and panel access

If you see repeated POST abuse against old plugin paths, wp-login.php, xmlrpc.php, or suspicious scripts that should not exist, the environment is telling you where to harden next.

This is also where weak shared hosting environments become a rational reason to stop DIY. If the same hosting account contains multiple WordPress installs, abandoned development copies, unknown subdomains, or stale backup archives, then cleaning one visible site may not remove the source of reinfection. ServerSpan’s persistent malware on shared hosting article exists for a reason. Reinfection often has more to do with account sprawl and poor isolation than with WordPress itself.

And this is where a better environment becomes a legitimate commercial decision, not an upsell cliché. Some sites should remain on strong, well-maintained shared hosting. Some should move to a cleaner managed setup. Some, especially agency or application-heavy sites with real server-side requirements, should move to a properly operated VPS. A VPS is not automatically “more secure.” It is only safer if someone is actually managing it. If nobody is managing it, you just moved the same mess to a bigger box.

Step 8: Clean Up the SEO Damage Properly

Security recovery is not finished when the files are clean. SEO recovery is part of security recovery. If spam URLs are still indexed, rogue sitemaps are still known to Google, or Search Console still sees a hacked-site problem, then the incident is still active from a business perspective.

Start with Search Console:

  • Review the Security Issues report.
  • Review the Manual Actions report.
  • Inspect indexed pages and sitemap submissions.
  • Capture the suspicious URLs you still see in search.

If Google still shows spam URLs, do not confuse temporary hiding with actual cleanup. The Removals tool is useful for quickly suppressing hacked URLs from search results, but it is temporary. It buys time. It does not replace actual removal, proper status codes, or real cleanup.

That means your SEO recovery process should include:

  • Removing rogue URLs from the site itself
  • Returning the right HTTP status for dead spam pages
  • Removing rogue sitemap files and references
  • Checking robots.txt and sitemap plugins
  • Submitting clean sitemaps only
  • Requesting review in Search Console if security issues were flagged

If the site was hit with injected SEO spam, also review search results with queries like:

site:example.com
site:example.com inurl:jp
site:example.com inurl:tag
site:example.com viagra
site:example.com casino
site:example.com cialis

And inspect sitemap endpoints directly:

curl -I https://example.com/robots.txt
curl -I https://example.com/wp-sitemap.xml
curl -I https://example.com/sitemap.xml

If spam URLs are still indexed after cleanup, do not panic and start deleting random database rows. Confirm the URLs are genuinely gone from the site, submit temporary removals where necessary, then request review if Search Console shows a security issue. The site “looking fine now” does not mean Google is done with the incident. Search fallout often outlives the visible compromise.

This is also why the Japanese keyword cleanup guide remains relevant even after malware removal. If the compromise created spam posts or spam URL paths in the database, those URLs can linger in search visibility long after the homepage is clean. That is not just an SEO annoyance. It is part of the compromise impact.

Step 9: Monitor for 7 to 14 Days Before Declaring Victory

Do not declare the site clean the same day you finish cleanup. Watch it.

  • Watch for newly modified files.
  • Watch for new admin users.
  • Watch for security alerts from the host or Search Console.
  • Recheck spam URLs in search results.
  • Test redirects in clean browsers and incognito sessions.
  • Watch login activity and suspicious POST bursts.
  • Watch scheduled tasks that could be re-dropping code.

If you have root or VPS-level access, file-change monitoring becomes very useful here. Even a simple daily diff on executable files is better than wishful thinking. The goal is not just to see whether the site works. The goal is to detect whether the infection is returning on a schedule, through a background task, or via the same weak path you missed the first time.

ServerSpan’s ClamAV on a VPS guide can help as a secondary monitoring layer on systems where you actually control the server, but do not make the same mistake again: a malware scan is support evidence, not proof of security.

When DIY Is No Longer Rational

This is the key decision point, so be direct with yourself.

Stop trying to handle it DIY and move to managed help when any of these are true:

  • Malware returns after one cleanup.
  • You cannot verify core, plugin, or server-side file integrity.
  • You have multiple WordPress installs on the same account.
  • The hosting layer is messy, opaque, or shared with too many unknowns.
  • The site handles customer data, leads, bookings, or payments.
  • Google warnings or spam indexing are hurting traffic or revenue.
  • You still do not know how the attacker got in.
  • You cannot safely rotate every credential and verify the server side.

This is where managed web hosting, Linux administration help, or a clean migration out of a weak environment stop being “extra services” and become rational risk control. If the site matters, repeated DIY cleanup is not thrift. It is expensive denial.

If the problem is mostly site-level and you need a cleaner hosting path with better operational discipline, ServerSpan’s web hosting is the right starting point. If the problem includes server-side hardening, log review, cron review, Nginx or Apache cleanup, and WordPress recovery on a custom stack, that is a Linux administration problem, not just a WordPress problem. And if you genuinely need isolated application control, clean deployment discipline, and full stack ownership, then a virtual server may be the right destination, but only if it will actually be managed properly.

A Practical Post-Infection Decision Tree

Use this logic, and be honest:

  • If the infection was one-off, the entry path is known, core and plugins were reinstalled from clean sources, no persistence remains, and the hosting environment is clean, then harden and monitor.
  • If reinfection occurs, stop pretending it is just one bad plugin. Hunt persistence, inspect the server layer, and review every parallel install and scheduled task.
  • If logs, config, file ownership, or server rules are unavailable or confusing, move to managed help. Surface-level cleanup is not enough.
  • If the site’s revenue, leads, rankings, or customer trust depend on uptime and clean search results, do not gamble on repeated DIY cleanup cycles.

Conclusion

A hacked WordPress site is not secure because the visible malware is gone. It is secure when the access paths are rotated, persistence is gone, integrity is verified, the hosting layer is trustworthy, and the search fallout is actively addressed. If you cannot prove those things, you are not done.

If you want to secure WordPress after infection, think like an operator, not like someone closing a ticket. Cleanup is only the beginning. Hardening, validation, server review, and SEO recovery are what determine whether the site is actually safe or just temporarily quiet.

If you do not want to risk reinfection, SEO drag, or server-side guesswork, contact ServerSpan for hands-on help with WordPress recovery, server hardening, Linux administration, or migration into a cleaner managed environment where the next compromise is less likely to happen for the same reasons. Start with the contact page, and use the right path for the actual problem instead of treating every post-hack case like a plugin issue.

Source & Attribution

This article is based on original data belonging to serverspan.com blog. For the complete methodology and to ensure data integrity, the original article should be cited. The canonical source is available at: How to Secure WordPress After a Hack: Stop Reinfection, Recover SEO, and Know When DIY Is No Longer Enough.