WordPress Hacked: The Step-by-Step Recovery Protocol

Most hacked WordPress sites are recoverable. The majority of compromises come from one of four entry points: an outdated plugin with a known vulnerability, a weak or reused admin password, an accessible XML-RPC endpoint, or credentials stolen from another service and tested here. Every one of these is fixable. The recovery protocol below is sequential and specific — it works whether you have never touched a server command line or manage WordPress professionally.
Find Your Situation: What Are You Seeing Right Now?
Different hack types require different starting points. The redirect hack that sends visitors to a casino site is a different infection pattern from the pharma hack that injects fake pages into Google. Starting with the right section saves hours. Use the table below to identify what you are dealing with and jump to the correct step.
| What You Are Seeing | Hack Type | Jump To |
|---|---|---|
| Visitors redirected to spam, casino, or pharma site | Redirect hack (most common type) | Section 2 then Step 3 |
| Spam links in page content, footer, or sidebar | SEO spam database injection | Section 2 then Step 4 |
| Google Search Console warning 'Dangerous site' | Google blacklist triggered | Section 1 first, then Section 4 |
| Hosting account suspended with malware notice | Host-detected malware in files | Section 1 first, then Section 3 |
| Admin locked out or unknown admin users present | Credential compromise | Section 2 then Step 2 |
| Fake pharmaceutical pages appearing in Google | Database injection, pharma hack | Section 2 then Step 4 |
| Site defaced — homepage replaced with attacker content | Full site compromise | All of Section 2 in sequence |
| White screen or errors after core files changed | Core file modification | Section 2 then Step 3 |
| Sudden organic traffic drop, no content changes | SEO spam or cloaking injection | Section 2 then Step 4, then Section 4 |
Section 1: Immediate Triage — Do These Four Things Before Anything Else
The temptation after discovering a hack is to start deleting files. Resist it. Rushed file deletion removes your forensic evidence, can break the site completely, and often misses the actual malware while deleting legitimate files. The four steps below take under 15 minutes and set up everything that makes the actual cleanup faster and more complete.

Put the site in maintenance mode
3 minutesDo not take the site fully offline yet. You may need to test pages and check behavior during the cleaning process. Maintenance mode lets you work while preventing visitors from reaching infected pages.
If you still have admin access, install the WP Maintenance Mode plugin and activate it. If admin access is locked out, add this directly to your theme's functions.php via cPanel File Manager or SFTP:
// Temporary maintenance mode — remove after recovery is complete
function whr_maintenance_mode() {
if ( ! current_user_can( 'edit_themes' ) || ! is_user_logged_in() ) {
wp_die(
'Site temporarily unavailable. Back soon.',
'Maintenance',
array( 'response' => 503 )
);
}
}
add_action( 'get_header', 'whr_maintenance_mode' );The 503 response code tells Google this is temporary downtime, not a permanent issue. Returning 503 during a hack cleanup preserves your SEO standing. Returning 200 with a "maintenance" HTML page tells Google to index it.
Change all passwords — in this order
10 minutesThe order matters because some credentials unlock others. Start with the highest-privilege access first.
- WordPress admin accounts — every account with admin privileges, not just the primary one
- Hosting control panel — cPanel, SPanel, Cloudways, or whatever your host uses
- FTP/SFTP credentials — any FTP account that has write access to your WordPress files
- Database password — change in cPanel under MySQL Databases, then update
DB_PASSWORDin wp-config.php to match - Admin email address — the email account used for WordPress password resets, if that email account was potentially accessible
Call your host's security team
5 minutesThis step is skipped by most people and it is a mistake. Your host's security team has seen the same attack patterns hundreds of times. They have access to server-level logs that show exactly which files were accessed, when, and from which IPs. That information tells you the attack entry point in minutes — information that would take you hours to reconstruct independently.
Ask your host specifically for: the access log for the last 7 days, any file modification alerts their system flagged, and whether their security scanner has already identified any infected files. Managed hosts (Cloudways, ScalaHosting, SiteGround) often have malware assistance included in their support. Ask whether cleanup assistance is available before spending money on third-party tools.
Take a full backup of the hacked site
10 minutesThis seems counterintuitive. Why back up an infected site? Three reasons. First: your content, media, and most database data are in the infected backup. After cleaning, you can recover content from it without restoring the infection. Second: it gives you a before-state to compare against after cleaning. Third: if cleaning goes wrong and you accidentally break something, you have the hacked version to revert to rather than losing everything.
Label the backup clearly: "[date] — hacked version — do NOT restore." Store it somewhere separate from your clean backup history.
- cPanel: Backup then Full Account Backup then Download to your computer
- Cloudways: Applications then Backups then Backup Now — this creates an immediately downloadable snapshot
- UpdraftPlus: Dashboard then Backup Now — backs up files and database separately to your configured remote storage
Section 2: The Recovery Protocol — Six Steps in Sequence
The recovery protocol below is sequential. Skipping steps or doing them out of order is how re-infections happen: a backdoor left in step 3 survives the database clean in step 4 and restores the malware within hours. Complete each step fully before moving to the next.
Step 1: Run a Malware Scan
The first scan is reconnaissance. Before you delete anything, you need a complete picture of what is infected. A scan that shows 3 files infected is not the same situation as a scan that shows 47 files infected across multiple plugins and your theme directory. The scope changes the recovery approach.

| Tool | Scan Type | What It Finds | Cost and Notes |
|---|---|---|---|
| MalCare | Server-side | Cloud-based analysis of your actual files. Detects obfuscated and encoded malware that signature-based scanners miss. One-click clean. | $99/year. Worth every dollar when you need it. Trial scan is free. |
| WordFence | Server-side (in WordPress) | Highlights modified core files, suspicious function calls, and known malware signatures. Good first step, less thorough than MalCare on obfuscated code. | Free tier functional. Premium ($119/yr) adds real-time signature updates. |
| Imunify360 | Server-level (host-provided) | If your host has it — SiteGround, A2, many cPanel hosts — it scans at the server level before requests reach WordPress. Extremely thorough. | Included on hosts that provide it. Check your host's security panel. |
| Sucuri SiteCheck | External (visitor-facing) | Scans your site as a visitor sees it. Catches redirects, visible injections, and blacklist status across major vendors. | Free. Cannot detect server-side backdoors. Use as confirmation after internal scan. |
| VirusTotal | External (URL check) | Checks your domain against 70+ security vendor databases. Good for confirming blacklist status and catching distribution-layer malware. | Free. URL-based. Complements rather than replaces file-level scanning. |
After the scan runs, look specifically for these four categories in the results:
- Modified core WordPress files in /wp-admin/ or /wp-includes/ — any file there that differs from the clean WordPress release is compromised
- PHP files in /wp-content/uploads/ — no legitimate PHP belongs in the uploads directory. Every match here is a backdoor or webshell.
- Obfuscated code — looks like
eval(base64_decode('...'))or$_GET[chr(99)](${'_POST'[1]})— these are backdoors hiding their function - Unknown admin user accounts — the scan may flag these or you will find them in step 2
Step 2: Remove Unknown Admin Users
Attackers who gain database access create admin accounts as persistent backdoors. They are invisible to site visitors but give the attacker re-entry even after all infected files are cleaned. This step must happen before file cleaning because an attacker with a working admin account can re-upload malware after you clean it.
- WordPress Admin then Users then All Users
- Filter by Role: Administrator
- Review every account. Any admin you did not create: hover, click Delete
- Check registration email addresses — attacker accounts typically use random Gmail, Proton, or temp-mail addresses
- Check Settings then General then Membership — if "Anyone can register" is enabled and you did not intentionally enable it, turn it off
If admin access is unavailable (locked out), remove attacker accounts directly via phpMyAdmin:
-- List all admin accounts with registration date (newest first):
SELECT u.ID, u.user_login, u.user_email, u.user_registered
FROM wp_users u
JOIN wp_usermeta m ON u.ID = m.user_id
WHERE m.meta_key = 'wp_capabilities'
AND m.meta_value LIKE '%administrator%'
ORDER BY u.user_registered DESC;
-- If you see an account you did not create, note its ID and delete:
DELETE FROM wp_users WHERE ID = [attacker_user_id];
DELETE FROM wp_usermeta WHERE user_id = [attacker_user_id];Step 3: Clean or Restore Core WordPress Files
Core file modification is how most redirect hacks persist: the attacker edits a file in /wp-admin/ or /wp-includes/ to execute their payload every time WordPress loads. The scan results tell you which files were changed. This step replaces them with verified clean versions.
Reinstall WordPress core via admin panel
WordPress Admin then Dashboard then Updates then scroll to the bottom — "Re-install version X.X.X now." This overwrites every file in /wp-admin/ and /wp-includes/ with a fresh download from wordpress.org. Your theme, plugins, uploads, and database are untouched. Takes under 2 minutes. This resolves the majority of core file compromises without touching a command line.
Replace modified files via SFTP
Download the clean WordPress version matching your installed version from wordpress.org/download/releases/. Compare /wp-admin/ and /wp-includes/ against your server files. Replace every file that differs. Any file on your server not present in the clean download: delete it.
After restoring core files, scan for backdoors in your theme and plugin files. These survive a core reinstall because they are in /wp-content/, which core reinstall does not touch:
# Search for the most common backdoor signatures:
grep -r "eval(base64_decode" /path/to/wordpress/wp-content/
grep -r "system(" /path/to/wordpress/wp-content/
grep -r "passthru(" /path/to/wordpress/wp-content/
grep -r "shell_exec" /path/to/wordpress/wp-content/
grep -r "assert(" /path/to/wordpress/wp-content/
# Find PHP files modified in the last 7 days (suspicious recent changes):
find /path/to/wordpress/wp-content/ -name "*.php" \
-newer /path/to/wordpress/wp-config.php \
-not -path "*/cache/*" \
| sort -k6 -r | head -30
# Each match needs manual review.
# Legitimate plugins rarely use eval(base64_decode) or passthru.
# The ones that do will have it documented in their source.Step 4: Clean the Database
File cleaning without database cleaning is incomplete recovery. The Sucuri 2024 Website Threat Report found that over 40% of WordPress infections include a database component — most commonly injected siteurl values that redirect visitors, spam links injected into post content, and malicious JavaScript stored in wp_options. A cleaned set of files with a dirty database means the site still redirects visitors and still serves spam links.

Start with the four most critical database checks. Run these in phpMyAdmin under your database's SQL tab:
-- 1. Verify the site URL has not been hijacked:
SELECT option_name, option_value
FROM wp_options
WHERE option_name IN ('siteurl', 'home', 'admin_email', 'blogdescription');
-- Expected: siteurl and home both point to your real domain.
-- If either points elsewhere: that is your redirect hack. Update them:
UPDATE wp_options SET option_value = 'https://yourdomain.com' WHERE option_name = 'siteurl';
UPDATE wp_options SET option_value = 'https://yourdomain.com' WHERE option_name = 'home';
-- 2. Check for injected code hiding in wp_options:
SELECT option_name, LEFT(option_value, 300)
FROM wp_options
WHERE option_value LIKE '%base64_decode%'
OR option_value LIKE '%eval(%'
OR option_value LIKE '%<script%'
OR option_value LIKE '%document.write%';
-- Any row returned here contains injected malware. Delete the row if the
-- option_name is not a known WordPress or plugin option.
-- 3. Check post content for spam link injection:
SELECT ID, post_title, post_status, LEFT(post_content, 200)
FROM wp_posts
WHERE post_content LIKE '%<a href%'
AND (post_content LIKE '%casino%'
OR post_content LIKE '%viagra%'
OR post_content LIKE '%pharmacy%'
OR post_content LIKE '%payday loan%')
AND post_status = 'publish';
-- Any result here is SEO spam injection into your posts.
-- 4. Find injected script tags in published content:
SELECT ID, post_title
FROM wp_posts
WHERE post_content LIKE '%<script%'
AND post_status = 'publish';For spam links injected across many posts — which is common in SEO spam hacks — Better Search Replace handles bulk removal without SQL knowledge. Install it from the WordPress plugin directory, run a dry-run search for the attacker's domain, verify the count of occurrences, then run the actual replace with an empty string. The dry-run mode shows you exactly how many rows are affected before any changes are made.
wp search-replace 'attacker-domain.com' '' --dry-run scans the entire database across all tables and shows affected rows before making any change. Add --all-tables to include non-WordPress tables in the same database.Step 5: Clean the /uploads/ Directory
The /uploads/ directory is the most common location for webshells and PHP backdoors after a file upload vulnerability is exploited. No legitimate PHP file belongs in /uploads/. Every PHP file found there is malicious — no exceptions, no investigation needed before deletion.
# List all PHP files in uploads — review before deleting:
find /path/to/wordpress/wp-content/uploads/ -name "*.php" -type f
# Common webshell names to look for specifically:
find /path/to/wordpress/wp-content/uploads/ \
-name "*.php" -o -name "c99*" -o -name "r57*" \
-o -name "shell*" -o -name "wso*" | head -20
# Once confirmed: delete all PHP files in uploads:
find /path/to/wordpress/wp-content/uploads/ -name "*.php" -type f -delete
# Confirm deletion worked:
find /path/to/wordpress/wp-content/uploads/ -name "*.php" -type f
# Expected output: nothing. Zero files returned.After removing PHP files from uploads, create a permanent block that prevents any PHP file in uploads from executing even if an attacker uploads one again. This is the hardening step that closes the upload directory attack vector permanently. Create this file:
# Block PHP execution in uploads directory.
# Any PHP file uploaded here will not execute.
<Files *.php>
deny from all
</Files>Step 6: Update Everything — Then Delete What You Are Not Using
After cleaning, every component in your installation needs to be at its latest version. The vulnerability that allowed the original compromise is almost certainly a known issue with a patch available. Installing the update closes the specific door the attacker used.
- WordPress core — Dashboard then Updates. Confirm you are on the latest release.
- All plugins — Dashboard then Updates then select all then Update Plugins. Check each plugin's changelog for recent security fix mentions — that is where your vulnerability likely was.
- All themes — Dashboard then Updates then Themes. Include inactive themes.
- Delete inactive plugins — deactivated plugins are still readable by PHP and still exploitable. If you are not using it, delete it. Appearance then Themes: delete every theme except your active one and one backup theme.
- Remove nulled/pirated plugins or themes — if any component came from outside the official plugin directory or the developer's own site, delete it now. Nulled plugins ship with pre-installed malware in approximately 80% of cases examined by Sucuri researchers.
Section 3: If Your Hosting Account Was Suspended for Malware
Hosting suspension for malware is common, it is fixable, and most hosts unsuspend within 1 to 24 hours of confirmed removal. The workflow below applies to the three most common hosting types: shared cPanel hosts, managed WordPress hosts, and cloud platforms like Cloudways. The key rule: fix the issue before contacting support. Hosts run an automated rescan before unsuspending — if a single infected file remains, the account stays suspended and the support ticket resets to the back of the queue.
| Step | What to Do | Important Detail |
|---|---|---|
| Read the suspension email | Contains the specific file paths and malware names the automated scanner found. This is your starting point. | Do this before calling support. The email tells you exactly what to fix. |
| Access files via cPanel File Manager | cPanel File Manager typically remains accessible even when the site is suspended. Navigate to the flagged file paths. | Log into cPanel directly, not your website URL. |
| Delete or quarantine the flagged files | Delete identified malicious files. For PHP files in /uploads/: delete all of them. For modified plugin files: replace with clean versions. | Check if the file is a legitimate plugin file first — compare against a clean install. |
| Run a full MalCare or WordFence scan | Confirm no other files are infected before contacting support. Hosts re-scan after unsuspension — one missed file means re-suspension. | Complete the scan before contacting support. Partial cleanup wastes everyone's time. |
| Contact support with specific details | Email or ticket: 'I have removed the malware. The files [list them] have been deleted/replaced. Please review and unsuspend.' Be specific. | Managed hosts (Cloudways, ScalaHosting) may assist with cleanup directly — ask. |
| Follow up within 24 hours if no response | Most hosts unsuspend within 1 to 24 hours after confirmed malware removal. Follow up once if you have not heard back. | Weekend timing affects response speed. Monday unsuspensions from Friday incidents are common. |
How to Access Your Files When the Site Is Suspended
Shared and cPanel hosting: cPanel itself stays accessible even when your website is suspended. Log into cPanel directly — typically yourdomain.com/cpanel or via the URL in your original welcome email. File Manager shows all your WordPress files and lets you edit, delete, and upload. The suspension blocks web visitors; it does not block your own cPanel access.
Cloudways: SSH and SFTP remain accessible during suspension. Your application's SSH credentials are in Cloudways Dashboard then Applications then Access Details. Connect via SFTP client (FileZilla, Cyberduck) and navigate to the public_html directory. Cloudways support also responds to security-related tickets faster than average because managed hosting security support is part of their offering.
ScalaHosting managed VPS: SPanel remains accessible during WordPress-level issues. SSH access stays functional. Their support team actively assists with malware removal as part of their managed service — open a security ticket with "malware cleanup request" and you will get a response within the support SLA. This is one of the concrete differences between managed and unmanaged hosting when security incidents happen. The managed versus unmanaged VPS guide covers the full breakdown of what managed hosting includes in these scenarios.
What to Say to Your Host When Requesting Unsuspension
Specificity matters. A vague "I think I fixed it" delays the response. A specific ticket that names the files removed gets a faster review. This template works:
"My account was suspended on [date] for malware at [file path from your notification email]. I have taken the following actions:
1. Deleted the identified malicious files: [list the specific file paths]
2. Removed unknown admin accounts
3. Ran a full MalCare/WordFence scan — no remaining infected files detected
4. Updated all plugins and themes to current versions
5. Changed all passwords including database and FTP credentials
Please rescan and unsuspend when confirmed clean. Let me know if you find anything remaining that requires my attention."
Section 4: If Google Blacklisted Your Site
A Google blacklist means Chrome shows "This site may harm your computer" or "Deceptive site ahead" before visitors reach your pages. Organic traffic collapses immediately because the warning stops roughly 95% of clicks. The warning does not self-resolve after you clean the malware — you must manually request a review. The review takes 24 to 72 hours. During that window, the warning stays visible.

The Exact Sequence to Remove Google's Blacklist Warning
- Complete Sections 2 and 3 first. Do not request a review before the malware is gone. If Google rescans and finds anything remaining, the review fails and the window resets. You want to submit one clean review request, not multiple failed ones — repeated failed reviews signal a persistent problem and can extend the review timeline significantly.
- Open Google Search Console. If your site is not verified, add it now via DNS TXT record (fastest verification method — under 10 minutes via your DNS manager or Cloudflare dashboard).
- Navigate to Security and Manual Actions then Security Issues. Google's flagged URLs and descriptions are here. Read them carefully — they show which specific pages were flagged and what Google detected. This is your checklist for confirming the issue is fully resolved.
- Verify every flagged URL is clean. Visit each URL Google listed. Check the page source for any injected scripts. Run Sucuri SiteCheck on your domain for external confirmation.
- Click "Request a Review." Write a specific description: "I identified and removed [describe what you found — redirect hack / injected spam links / etc.]. Specific actions: [list your cleanup steps]. All infected files deleted, database cleaned, all passwords rotated, all components updated."
- Wait for the review. Google sends an email when the review is complete. Do not resubmit while a review is pending — it resets the queue position.
Why Is Other Blacklists After Google Clears
Google's safe browsing verdict carries significant weight with other security vendors. McAfee SiteAdvisor, Norton Safe Web, ESET, and Yandex Safe Browsing all reference Google's feed as one input. Most auto-remove a site from their blacklists within 24 to 48 hours after Google's review completes. You do not need to manually submit removal requests to most of them.
Sucuri Blacklist Checker (sitecheck.sucuri.net) shows your site's status across multiple vendors simultaneously. Run it after Google confirms your review is approved. If any secondary vendor still shows a warning after 72 hours, visit that vendor's specific removal portal. Norton Safe Web, McAfee SiteAdvisor, and Yandex each have a URL submission form for dispute requests.
Section 5: Harden Against Re-infection — Do All of These Before Going Back Online
Most WordPress sites that get re-hacked within 30 days of recovery were cleaned but not hardened. Cleaning removes the current infection. Hardening closes the structural vulnerabilities that made infection possible. The average re-infection window on a cleaned-but-not-hardened site is under 72 hours. The steps below take under 2 hours total and need to happen before you take the site out of maintenance mode.

5a. Rotate WordPress Secret Keys in wp-config.php
WordPress secret keys are used to encrypt session cookies. If an attacker's existing session cookie was created before you rotated these keys, that session remains valid after every other cleanup step. Rotating the keys invalidates all existing sessions simultaneously — including every active session the attacker holds.
/* Step 1: Visit this URL to generate fresh keys:
https://api.wordpress.org/secret-key/1.1/salt/
It generates output like this (yours will be different):
*/
define('AUTH_KEY', 'x0I1 ~:t5#Tr^GfH=fFiZy-q%0+Y;|4v)n8%}FWB@1xo');
define('SECURE_AUTH_KEY', 'x9pX7$w%RiBV+GsT!^5m&L|y6Qz2uH_F9');
define('LOGGED_IN_KEY', 'Q7-8|5.Ft>3$cBnRpJ{&hK...etc');
define('NONCE_KEY', '...generate new values for all eight...');
define('AUTH_SALT', '...');
define('SECURE_AUTH_SALT', '...');
define('LOGGED_IN_SALT', '...');
define('NONCE_SALT', '...');
/* Step 2: In wp-config.php, find the existing KEYS AND SALTS section
and replace ALL eight lines with the freshly generated output.
Edit wp-config.php via:
- cPanel File Manager (right-click the file then Edit)
- SFTP client
- SSH: nano /path/to/wordpress/wp-config.php
*/5b. Lock Down wp-config.php File Permissions
wp-config.php contains your database credentials, secret keys, and table prefix. It should never be world-readable. The correct permission is 400 (owner read-only) or 440 (owner and group read-only). Most WordPress installations ship with 644 or 640 — readable by any process on the server.
# Set wp-config.php to owner read-only (most restrictive):
chmod 400 /path/to/wordpress/wp-config.php
# Verify the change:
ls -la /path/to/wordpress/wp-config.php
# Expected output: -r-------- 1 username username ... wp-config.php
# If 400 breaks your site (some server configs require write access):
chmod 440 /path/to/wordpress/wp-config.php5c. Enable Two-Factor Authentication on Every Admin Account
2FA is the single configuration change with the highest impact on preventing re-infection via credential attacks. An attacker who recovered your old password through a session, a keylogger, or a breach database cannot log in without the second factor. Two-factor authentication makes credential stuffing, brute force, and leaked password attacks irrelevant simultaneously.
Install WP 2FA (free, 100,000+ active installations, maintained by Melapress). Configure: Enforce 2FA for all Administrator roles. Set a 3-day grace period so existing admins can set up their TOTP before being locked out. Use TOTP (Google Authenticator, Authy, or any TOTP app) rather than email-based codes — TOTP works without email delivery and cannot be intercepted via a compromised email account.
Which 2FA plugin should you use?
WP 2FA (free): Best for most WordPress sites. TOTP and email codes, role enforcement, backup codes. No premium required for basic 2FA.
WordFence Login Security (free): If you are already running WordFence, this adds 2FA within the same plugin. Avoids adding a separate plugin.
Both are TOTP-compatible with Google Authenticator, Authy, 1Password, and Bitwarden's built-in authenticator.
5d. Install a Security Plugin with an Active Firewall
A security plugin sits between incoming requests and WordPress and blocks attack patterns before they execute. WordFence and MalCare are the two credible options. Both run an application-layer firewall that blocks brute force, SQLi attempts, and known exploit patterns. Do not install both — they intercept the same request pipeline and running both simultaneously does not improve detection coverage while adding real server overhead.
WordFence Free — Web Application Firewall with 30-day delayed rule updates, malware scanner, login protection, and 2FA via WordFence Login Security. Correct choice for sites that are now clean and need prevention going forward. Install, run the initial scan, accept the firewall optimization prompt (moves WordFence to load before WordPress, increasing blocking effectiveness).
WordFence Premium ($119/year) — Real-time firewall signatures. When a new WordPress plugin vulnerability is disclosed and attackers start scanning for it within hours of the CVE announcement, Premium gets the blocking rule immediately. The free tier gets it 30 days later. For any site processing e-commerce or storing personal data, real-time rules are worth the cost. One blocked attack typically covers the annual subscription.
MalCare ($99/year) — Better detection for obfuscated and encoded malware. If you experienced an infection that a basic scanner missed, MalCare's cloud-based analysis is worth running as the ongoing monitoring tool. Their login protection and firewall cover the same ground as WordFence's application layer.
5e. Enable Cloudflare — the Network Layer That Stops Attacks Before They Reach WordPress
A plugin-level firewall runs after the request arrives at your server. Cloudflare runs at the DNS layer — it intercepts requests before they reach your server at all. Volumetric DDoS, known malicious IP ranges, and bot traffic are absorbed at Cloudflare's edge network, which has over 300 Tbps of capacity. Your server never processes the attack traffic.
Cloudflare free tier: add your domain, point your nameservers to Cloudflare's nameservers, enable Always Use HTTPS, enable Bot Fight Mode. This alone blocks the majority of automated attack traffic with zero ongoing cost. Configure a rate limiting rule on /wp-login.php: 5 requests per 10 minutes per IP, block for 1 hour. This single rule stops brute force at the network edge without loading WordPress at all.
Cloudflare Pro at $20/month adds the OWASP Core Rule Set — a curated set of firewall rules targeting SQLi, XSS, and protocol-level attack patterns. For any site generating revenue, Pro is the correct configuration after a compromise. The WAF blocks attack patterns that would otherwise reach WordFence, reducing server load in addition to improving security coverage. The CDN guide covers the full Cloudflare setup sequence for WordPress including cache configuration, performance settings, and firewall rule priority.
5f. Additional Hardening Items That Take Under 10 Minutes Each
Limit login attempts
WordFence handles this automatically once installed. If you are using MalCare instead: install Limit Login Attempts Reloaded (free). Set lockout after 3 failed attempts, lockout duration 20 minutes, extend to 24 hours after 4 lockouts. This stops brute force before enough attempts to matter.
Disable user registration (if not needed)
Settings then General then Membership. If your site is not a membership site or e-commerce store requiring customer accounts, uncheck "Anyone can register." Open registration combined with a weak role assignment creates a low-privilege account that can be escalated through subsequent vulnerabilities.
Block XML-RPC if unused
XML-RPC's multicall method allows hundreds of login attempts in a single HTTP request, multiplying brute force rate by 500x and bypassing per-request rate limiting. Add to .htaccess: <Files xmlrpc.php> deny from all </Files>. Check first whether you use Jetpack or the WordPress mobile app — both require XML-RPC to function.
Change the database table prefix
The default prefix wp_ is assumed by automated SQL injection scripts. Changing it to a random string like xk7v_ eliminates automated injection attempts that hardcode the wp_ prefix. Use Brozzme DB Prefix and Tools Changer plugin — it handles the database rename safely. This requires a database backup before running. Not critical for a fresh setup, but worth doing post-recovery.
Set HTTP security headers
Add X-Frame-Options, X-Content-Type-Options, and a basic Content Security Policy via .htaccess or Cloudflare Transform Rules. These headers block clickjacking, MIME-type attacks, and constrain which external domains can load scripts on your pages. Cloudflare's free tier lets you add any response header via Transform Rules without touching your server configuration.
Move wp-config.php above web root
If your host allows directory writes above public_html: move wp-config.php one level up from your WordPress installation root. WordPress automatically looks for it there. Direct HTTP requests to wp-config.php return 404 because the file is outside the web-accessible directory. Not all shared hosts allow this — test before relying on it.
Section 6: The Monitoring Stack — Set These Up Once and Let Them Watch
The monitoring tools below alert you within minutes of the conditions that indicate a new attack or re-infection. Set them up in a single session after the recovery is complete. Combined, they cost nothing beyond about 45 minutes of setup and cover the detection gap that allowed the original hack to run undetected. A site without monitoring relies on a visitor email to detect its next compromise. That is a detection window measured in days to weeks.
| Tool | What It Monitors | Cost | Key Alert to Configure |
|---|---|---|---|
| UptimeRobot | Downtime and site availability | Free | 5-minute check intervals. Email alert within 5 minutes of any outage. Many hacks take the site offline — this is your fastest alert. |
| WordFence / MalCare | File changes, login attempts, malware | Free to $99/yr | Real-time file integrity monitoring. Alerts on any core file modification. WordFence sends email on blocked attacks. |
| Google Search Console | Google's security view of your site | Free | Security Issues tab. Email alert when Google detects malware or phishing. Often detects infections before site owners do. |
| WP Activity Log | Admin actions and WordPress events | Free | Logs who changed what, who logged in, who created accounts. After a re-infection, the log identifies how access was regained. |
| Cloudflare Analytics | Traffic patterns and bot activity | Free | Spike in blocked threats or unusual request patterns is an early attack indicator before the attack succeeds. |
The Backup Strategy That Makes Disaster Recovery Actually Work
Monitoring detects problems. Backups determine whether a future compromise costs you 2 hours or costs you everything. Three properties make a backup strategy real rather than theoretical:
Off-site storage. A backup stored on the same server as your WordPress installation gets encrypted or deleted in a ransomware attack. Google Drive, Dropbox, and Amazon S3 are all valid off-site targets. UpdraftPlus (free) supports all three. Configure it to send backups to Google Drive — it is free for up to 15 GB and takes under 5 minutes to authorize.
30 days of retention minimum. Some infections run silently for weeks before becoming visible. If you discover a compromise today that started 3 weeks ago, you need a backup from 4 weeks ago to have a clean restore point. A 7-day retention window is not sufficient for this scenario. UpdraftPlus free tier supports custom retention counts — set it to 30 daily backups.
Tested restores. An untested backup is a hypothetical backup. Every 90 days, download one of your backups and restore it to a staging environment. The WordPress multisite or a free Cloudways trial server work for this. If the restore fails, you find out now rather than during the emergency when it matters. This is the check that most WordPress site owners never run — and it is the most important one.
UpdraftPlus configuration for the setup described above: install the free plugin, Settings then UpdraftPlus then Settings, set Backup Schedule to Daily for both files and database, set Backup Retention to 30, connect to Google Drive under Remote Storage and authorize the connection. Total setup time: under 15 minutes. The backup and restore guide covers the complete UpdraftPlus configuration including multiple storage destinations, scheduled backups, and restore verification procedures.
Recovery Myths That Cause Re-infection
These are the specific beliefs that lead people to incomplete recoveries. Each one sounds reasonable. Each one leaves a specific gap that attackers exploit within days of a "completed" cleanup.
"I ran a scan and it came back clean, so the site is clean."
INCOMPLETE.
A malware scanner shows what its signatures detect. A scanner with no signature for a specific backdoor variant reports that backdoor as clean. Every malware scanner — MalCare, WordFence, Sucuri, all of them — has coverage gaps. The practical response: run two scans from different engines, and manually run the grep commands in Step 3 for common backdoor patterns. One scanner saying "clean" is not the same as one scanner and one manual grep saying "clean." The manual commands take under 2 minutes with SSH access and catch what signatures miss.
"I deleted the infected files. I do not need to clean the database too."
WRONG.
Database injections persist independently of file infections. A redirect hack where the attacker modified the siteurl value in wp_options survives every file cleaning step because it is a database row, not a file. Cleaning files without checking the database is the most common reason redirect hacks return within 24 hours of a "completed" cleanup. The database check in Step 4 takes under 10 minutes. There is no reason to skip it.
"Once I clean the site, Google's warning will go away automatically."
FALSE.
Google does not auto-remove blacklist warnings after you clean the malware. You must manually request a review in Search Console. Without the review request, the warning stays active indefinitely — typically until Google's crawler re-crawls your site and updates its assessment, which can take weeks to months. The review request in Section 4 takes 5 minutes and triggers a human review within 24 to 72 hours. Skipping it extends your warning period from 24 hours to potentially several weeks.
"My host suspended me, so they must have cleaned the malware."
NOT WHAT HAPPENED.
Hosts suspend accounts to protect their shared infrastructure from your infected site affecting neighboring accounts and their server reputation. Suspension is containment, not cleanup. The host stops your site from running; they do not remove malware from your files or database. You are responsible for the cleanup. Most hosts will confirm this explicitly in the suspension email: "Your account has been suspended pending malware removal." The removal is on you. Following the workflow in Section 3 of this guide and then providing the specific file list to your host support ticket is the correct process.
"I changed my WordPress admin password, so the attacker cannot get back in."
INSUFFICIENT.
A password change blocks access via the login form. It does not invalidate existing sessions, does not remove backdoor files, does not close webshells in /uploads/, and does not remove attacker admin accounts. An attacker with an active WordPress session cookie from before the password change can still be logged in. Rotating the secret keys in wp-config.php (Step 5a) invalidates all sessions. Removing unknown admin accounts (Step 2) removes direct backdoor accounts. A password change alone leaves all other access paths intact.
After Recovery: Building the Foundation That Prevents This from Happening Again
You have been through the complete recovery protocol. The cleanup is done. If you followed the hardening steps in Section 5, you have closed the structural vulnerabilities that made the original compromise possible. Three resources support what comes next:
The WordPress security threats guide covers the four primary attack vectors in detail — DDoS, brute force, SQL injection, and XSS — with live detection commands, log analysis, and prevention configuration for each. If you want to understand how to recognize an attack before it becomes a compromise, that guide provides the detection signatures. The managed versus unmanaged VPS guide covers how your hosting type affects the baseline security posture you are working with — managed hosts apply server-level security patches automatically and often include security assistance as part of the service, which changes the calculation when evaluating hosting after a security incident. The backup and restore guide covers the complete UpdraftPlus configuration, multi-destination backup setup, and restore testing procedures — the operational foundation that determines whether a future compromise costs 2 hours or costs everything.
If you are evaluating whether your current hosting provides the right security posture for your site going forward, the options that stood out in our testing for managed security support and fast response to security issues: ScalaHosting's managed VPS includes SShield security and active malware assistance as part of managed support. Cloudways provides SSH access, server-level firewalls, and active security support across five cloud providers — the right choice when you want managed infrastructure with control over your configuration. Both are meaningfully different from shared hosting when a security incident requires fast access and expert support.
WordPress Hack Recovery FAQ
How long does WordPress hack recovery actually take?
For a site with a standard shared hosting setup and a single hack vector, the active cleanup takes 1 to 3 hours using the protocol in this guide. That assumes you have hosting control panel access, can run a malware scanner, and have a recent clean backup as a reference. The two factors that extend this are: database injections that span hundreds of posts (using Better Search Replace speeds this up significantly), and backdoors left in obscure plugin files that survive an initial scan. Google blacklist removal adds 24 to 72 hours on top of the technical cleanup — that part is waiting, not working. If you are using a managed host with security assistance included (Cloudways, ScalaHosting), the host's security team can often cut active work time to under 30 minutes by identifying exactly which files were modified and when.
Should I restore from backup or clean the hacked site manually?
Restore from backup if the backup is clean, dated before the infection, and you know what caused the compromise and have fixed it. Restore is faster, more complete, and eliminates every infected file simultaneously. The risk: restoring to a backup that is itself infected, or restoring without understanding how the hack happened — which means the same vulnerability gets exploited again within days. Clean manually if you cannot confirm the backup predates the infection, if the backup is missing recent content you cannot afford to lose, or if the infection is isolated to known files. In practice: try to identify the earliest clean backup first, check it against the current database for the obvious injection markers (siteurl pointing to attacker domain, base64-encoded options values), and restore if it is clean. Manual cleaning is the fallback, not the first choice.
Why does my site keep getting re-infected after I clean it?
Re-infection after cleaning has four causes. First: a backdoor was not removed. Attackers frequently install multiple backdoors in different locations — one in a plugin, one in a theme file, one in an obscure /uploads/ subdirectory. Cleaning the obvious malware while missing a backdoor means the attacker regains control within hours and re-infects the site. Second: the original vulnerability was not patched — the outdated plugin or theme that allowed entry is still installed. Third: compromised admin credentials were not fully rotated — the attacker still has a working username and password. Fourth: the WordPress secret keys were not regenerated, which means existing sessions (including the attacker's) are still valid. The complete recovery protocol in this guide addresses all four causes in sequence.
Will Google automatically remove my site from the blacklist once it is clean?
No. Google does not automatically remove blacklist warnings after you clean the malware. You must manually request a review in Google Search Console under Security and Manual Actions then Security Issues. After the malware is completely removed, click Request a Review and describe specifically what you found and how you resolved it. Google's review team typically responds within 24 to 72 hours, occasionally up to one week for complex cases or sites with a history of repeated infections. During the review period, visitors using Chrome will still see the warning. The warning disappears from Chrome when Google confirms the review is complete and the site is clean. Bing Webmaster Tools has a separate review process if your site appears in Bing search results with a warning.
How did my WordPress site get hacked in the first place?
The Sucuri 2024 Website Threat Report found that over 60% of infected WordPress sites had at least one outdated component at the time of compromise. The ranking of entry vectors: number one is a vulnerable plugin, typically one that has a known CVE with a patch available but was not updated. Number two is a compromised admin credential — either a weak password guessed by brute force or a credential stolen from another service and tested against WordPress logins. Number three is a vulnerable theme, less common than plugins but the same mechanism. Number four is a compromised hosting account — FTP or cPanel credentials obtained through phishing or a host-level breach. Number five is a nulled (pirated) plugin or theme that came with malware pre-installed. After the recovery protocol is complete, WPScan — run as described in the security threats guide — identifies which of your current plugins have known vulnerabilities so you can patch the specific entry point.
Is MalCare better than WordFence for cleaning a hacked site?
For active malware cleanup specifically, yes — MalCare's detection is better on obfuscated code. Here is why: MalCare scans files on their cloud servers, applying a broader set of detection signatures that are updated continuously. WordFence runs its scanner within your WordPress installation, using a signature database that has a 30-day update delay on the free tier. Obfuscated malware — code that uses base64_decode, str_rot13, or variable function calls to hide its intent — is where MalCare's cloud analysis consistently outperforms WordFence's local scanner. For a site in active recovery, MalCare at $99/year is the right tool. Once clean and hardened, WordFence free tier's ongoing firewall and monitoring is sufficient for most small and medium sites. The critical rule: install one or the other, not both simultaneously. Running both creates false confidence and unnecessary load without additive detection coverage.
My host suspended my account. Can I still access my files?
Yes, in almost all cases. Shared hosting providers that suspend accounts for malware typically keep cPanel accessible even when the website itself is offline. Log into cPanel directly at yourdomain.com/cpanel or the specific cPanel URL your host provided during setup. File Manager remains functional and gives you access to all your WordPress files. The suspension notice in your email should include the specific file paths that triggered the suspension — go directly to those files first. Managed WordPress hosts handle suspension differently: Cloudways gives you SSH and SFTP access even during suspension, and their support team typically assists with cleanup directly. SiteGround's managed security team may initiate contact and offer cleanup assistance. For hosts where cPanel access is also blocked: contact support immediately by phone or chat, not just email — phone support can grant temporary file access faster than a ticket queue.
Should I tell my site visitors about the hack?
If the hack exposed visitor data — any personally identifiable information, email addresses, payment details, or login credentials stored in your database — you have a legal obligation to notify affected users in most jurisdictions. GDPR requires notification within 72 hours of discovering a personal data breach. US state laws (California CCPA, others) have their own requirements. Consult your jurisdiction's requirements if any user data was potentially accessible. If the hack was purely technical — malware inserted for SEO spam or redirects, with no user data accessed — public disclosure is not legally required, though transparent communication builds trust. The maintenance mode message during recovery is appropriate framing: 'Site undergoing security maintenance.' You do not need to say 'we were hacked' in the maintenance message. Post-recovery, if you want to be transparent, a brief 'we identified and resolved a security issue' notice is sufficient and earns more trust than silence.
What is a pharma hack and how do I remove it?
A pharma hack (also called a pharmaceutical hack or Japanese keyword hack) injects fake pharmaceutical product pages into your WordPress database that appear in Google search results but are invisible to you when you log in. The pages are served only to search engine crawlers and visitors arriving from Google — logged-in WordPress users and direct site visitors see the real site. This is why pharma hacks can run undetected for months. Detection: search Google for site:yourdomain.com and look for results with pharmaceutical keywords (Viagra, Cialis, Tramadol, or Japanese/Korean characters). If you see them, the injection is active. Removal: the injected pages are database rows in wp_posts with post_status set to publish but post_type set to a custom or standard type. A database search for those pharmaceutical terms using Better Search Replace will surface them. The injection also modifies .htaccess to serve cloaked content to Googlebot — check your .htaccess for any conditional redirect blocks added by the attacker. After removal, request Google reindexing of the affected URLs via Search Console.
Can I use my existing backup to restore without cleaning?
You can, and it is often the fastest path — with one critical caveat: the backup must predate the infection, and you must know when the infection occurred. The danger of restoring without this information: you restore to a backup that is also infected (attackers often compromise sites weeks before the infection becomes visible), effectively doing nothing. Before restoring, check your backup for the obvious injection markers: open phpMyAdmin on the backup database and run SELECT option_value FROM wp_options WHERE option_name = 'siteurl'. If that value points to your real domain, the backup is a good restore candidate. Also check: SELECT COUNT(*) FROM wp_posts WHERE post_content LIKE '%eval(%' — any non-zero count means database injections are present in that backup. A clean backup with a known pre-infection date is the fastest recovery tool you have. UpdraftPlus lets you restore from a specific dated backup without overwriting your current database first — use this to confirm the backup is clean before committing to the full restore.
