If your WordPress site keeps getting hacked after you have already cleaned it, the malware is not coming back. It never left. Something on that server is putting it back, and until you find that something, you will repeat the same cleanup every few days until you give up.
This is not another malware removal guide. Those exist by the hundred and they all finish in the same place: replace the files, run a scanner, change the password. That advice is fine for a first infection. It falls apart on the second one, because a repeat infection is proof that the cleanup missed the way in.
What follows is the part nobody writes about. How attackers keep access after a site looks clean, where they hide, and how to close the door properly.
Why cleaning a hacked WordPress site rarely works the first time
When most people clean an infected site, they remove what they can see. Redirect code in the theme header, strange files in the uploads folder, an unfamiliar plugin. All of that is the payload. It is what the attack does, not how the attack persists.
Persistence is separate. Somewhere in the installation there is usually a small piece of code whose only job is to accept instructions and write new files. It does not redirect anyone. It does not inject spam. It sits quietly and waits, which is exactly why scanners miss it and why a site that looked spotless on Monday is serving pharmaceutical spam again by Thursday.
There is a second possibility that is easier to overlook. The attacker may not need code on your site at all. If they took your hosting password, your FTP details, or your database credentials during the first breach, they can simply log back in and start again. No malicious file survives the cleanup, and the site still gets hacked a week later.
Restoring from a backup taken after the first infection. The backup contains the backdoor. The site comes back looking healthy, and the attacker is already inside. Always check the date of the backup against the date the trouble started.
The four ways attackers get back in
In our maintenance work across WordPress sites, repeat infections almost always trace to one of four things. Working through them in order saves a great deal of wasted effort.
1. A backdoor sitting outside the obvious folders
Backdoors are rarely dropped in the theme folder where a scanner will trip over them. They are placed where nobody looks and where a plausible filename does not raise questions. A file called wp-cache-config.php in the root looks like it belongs. A file inside wp-includes looks like part of WordPress itself.
Some are a single line long. A backdoor does not need to be clever to work, and its short length is precisely why a quick visual scan of a folder will not find it.
2. Administrator accounts you did not create
The moment an attacker gains write access, one of the first things they do is create a user with administrator rights. Sometimes the username is obvious rubbish. More often it is designed to blend in, sitting alongside your real accounts with a name like wpsupport or a copy of an existing username with one character changed.
They may also raise the role of an existing subscriber account. If your site accepts registrations and you have never audited the user list, this is worth checking even when nothing appears wrong.
3. Scheduled tasks that rebuild the infection
WordPress has its own scheduling system, WP-Cron, and it will run whatever it has been told to run. An attacker can register a task that recreates deleted files on a timer. You clean the site, everything looks correct, and the task fires overnight and writes the malicious files back.
This one confuses people badly, because the reinfection appears without any visitor doing anything and without any obvious external access.
4. Stolen credentials from the first breach
Hosting control panel, FTP or SFTP, the database user, the WordPress admin accounts, and any deployment tool connected to the site. If any of those were captured during the original attack, changing your WordPress password alone accomplishes nothing.
Cleaning removes what the attacker did. It does not remove how the attacker got in, and it does not remove how they plan to return.
Before you touch anything, take a snapshot
This feels wrong when a site is actively infected and the instinct is to start deleting. Take a full copy anyway, files and database together, and label it clearly as infected.
Two reasons. If the cleanup breaks the site, that copy is the only route back. And if the infection returns, comparing the new state against the old copy tells you what changed and when, which is often how the persistence mechanism is found.
Keep it off the server. A copy sitting in a folder on the same hosting account is not a backup.
Step 1: Find what Google and your host can already see
Start with the evidence you have not gathered yet. Most owners find out about a hack through a customer complaint, then work from that single symptom and never look at anything else.
- Google Search ConsoleOpen the Security Issues report. Google will often name the type of problem and list sample affected URLs, which saves hours of hunting.
- Your hosting panelAsk your provider for the malware scan log and the access log. Indian hosts including Hostinger, BigRock and GoDaddy will usually supply both on request.
- File modification datesSort every file by date modified. Files changed on a day when nobody was working on the site are the shortlist.
- The site as Googlebot sees itUse the URL Inspection tool and view the rendered page. This is how cloaked spam is caught.
That last one matters more than it sounds. A large share of WordPress infections are cloaked: the page looks perfectly normal to you, and serves gambling or pharmaceutical content only to search engine crawlers. Owners in this situation clean what they can see, declare the job done, and cannot understand why their traffic keeps falling. If your rankings dropped around the same time, the two are connected, and repairing the damage afterwards is a separate piece of work our SEO team handles once a site is secure.
Step 2: Hunt the backdoor properly
This is the part that decides whether you are doing a cleanup or a permanent fix.
Compare against a fresh copy of WordPress
Download the same WordPress version from wordpress.org and compare it against your installation, file by file. Anything present in yours that is absent from the clean copy is suspect. This single technique finds more backdoors than any scanner, because it does not rely on recognising a known signature.
Do the same for plugins and themes. Delete them completely and reinstall from the original source rather than updating over the top. Updating leaves existing files in place, which is exactly what a backdoor needs.
Check the folders people forget
| Location | Why attackers like it | What to look for |
|---|---|---|
| Site root | Plausible filenames blend with real WordPress files | Any PHP file not part of a stock install |
| wp-includes | Nobody edits it, so nobody inspects it | Files with recent modification dates |
| wp-content/uploads | Writable by design, and usually excluded from scans | Any file ending in .php |
| Inactive themes and plugins | Still executable even when switched off | Anything you do not use, which should be deleted |
| wp-config.php | Loads on every request | Appended code below the stop-editing line |
| .htaccess | Controls redirects before PHP runs | Rules you did not write, often near the bottom |
The uploads folder deserves particular attention. It exists to hold images and documents. It has no reason to contain a single executable PHP file, so anything you find there is worth treating as hostile until proven otherwise.
Search for the functions backdoors depend on
Most backdoors need to run code that arrives from outside, and there is a short list of PHP functions that make this possible. Search every file for eval, base64_decode, gzinflate, str_rot13, assert and preg_replace used with the /e modifier.
Legitimate plugins do occasionally use some of these, so a match is not automatic proof of anything. What should concern you is a long unreadable string of characters, or a file where these appear and nothing else does.
If the site is small and you have a clean older backup, rebuilding is often faster and safer than hunting. Install WordPress fresh, install plugins from source, import only the database after checking it, and copy across only genuine media files. A site with ten pages can be rebuilt in an afternoon. Two days of file-by-file inspection is a poor trade.
Step 3: Audit users, scheduled tasks and the database
Files are only part of it. The database holds three things worth checking, and skipping them is a common reason a site is reinfected after what looked like a thorough cleanup.
- Every administrator accountOpen the user list, sort by role, and confirm you know who each administrator is. Delete anything you cannot account for, and do not simply demote it.
- Registration settingsIf Anyone Can Register is switched on and the default role is anything above Subscriber, switch it off unless your site genuinely needs it.
- Scheduled tasksList the WP-Cron entries and remove anything unfamiliar. A task recreating a file on a timer will undo everything else you have done.
- Options and posts tablesSearch for script tags and iframe tags in the options table and in post content. Injected code often lives here rather than in a file.
Step 4: Change every credential the site touches
Change all of these together, within the same session. Changing them one at a time over several days gives an attacker who still has one of them the chance to reinstate the others.
- Every WordPress administrator password, and force a logout of all sessions
- The hosting control panel password
- FTP and SFTP accounts, including any you no longer use
- The database user password, updating
wp-config.phpat the same time - Security keys and salts in
wp-config.php, which invalidates stolen login cookies - Any connected service with write access, such as a deployment tool or a staging sync
Rotating the salts is the step most often missed. Without it, a stolen session cookie keeps working even after every password on the account has been replaced.
Step 5: Confirm the site is genuinely clean
A scanner reporting nothing is weak evidence. Scanners find what they already know about, and a custom backdoor written for one site will not be in anyone’s signature list. Use these checks instead.
- 72 hoursWatch file modification dates before declaring the job finished
- 0PHP files that belong in the uploads folder
- 2 scansRun two different scanners, since each misses what the other finds
Then request a review in Google Search Console. Google will recheck the site and remove the warning if it agrees. Doing that too early is counterproductive, because a failed review lengthens the wait on the next attempt.
Keep watching for a fortnight. Most reinfections surface within seventy-two hours, but a scheduled task set to a weekly interval will take longer to reveal itself.
How they got in the first time
Closing the return route is urgent. Working out the original entry point matters almost as much, because it tells you what to change so the same thing does not happen from scratch in six months.
Across the WordPress sites we look after, the first breach usually traces to one of five routes.
| Route in | How it happens | What closes it |
|---|---|---|
| An outdated plugin | A flaw is published, automated scanners find unpatched sites within hours | Update within days, and remove plugins you no longer use |
| Nulled themes and plugins | Paid software offered free, with code added before it reached you | Buy the licence, or pick a free alternative from the official directory |
| A weak or reused admin password | Automated login attempts against wp-login.php, running constantly | Long unique passwords, two-factor authentication, limit login attempts |
| An abandoned staging or demo site | An old copy on a subdomain, never updated, sharing the same account | Delete old copies, or keep them patched like the live site |
| A compromised computer | Malware on a laptop reads saved FTP passwords from the editor | Stop saving passwords in FTP clients, scan the machine that manages the site |
The third route is worth dwelling on, because it is the one most owners assume does not apply to them. Login attempts against WordPress are constant and automated. Nobody chose your site. A script works through a list of addresses, tries a few thousand common passwords on each, and moves on. A site with a short password will eventually be reached whether anyone has heard of the business or not.
The fourth route catches out a surprising number of businesses that have had a site rebuilt. The old version often stays on a subdomain, forgotten, running plugins that stopped receiving updates two years ago. It is on the same hosting account as the new site, which means an attacker who gets into the old one can usually reach the new one.
Why shared hosting reinfects sites that were cleaned properly
There is a scenario where everything above is done correctly and the site still gets hacked again. It is more common in India than most guides acknowledge, because shared hosting is what most small businesses run on.
On a poorly configured shared server, accounts are not fully isolated from each other. If another site on the same server is infected and permissions are loose, the infection can cross into your files no matter how carefully you cleaned them. Symmetric infections across several sites on one hosting account point to the same problem.
Ask your host directly whether other accounts on your server have reported malware, and whether your account is isolated. If you host several of your own sites in one cPanel account, that is the likeliest route. Separate hosting accounts, or a small VPS, removes the problem permanently and costs far less than repeating a cleanup every month.
What actually stops it happening a third time
Security software helps. It is not what keeps a site clean. Most reinfections we are asked to sort out happen on sites that were running a security plugin the whole time.
Four habits matter more than any plugin.
- Update within days, not monthsAttackers scan for known plugin flaws within hours of disclosure. A site patched weekly is a far harder target than one patched twice a year.
- Delete what you do not useDeactivated plugins and old themes still sit on the server and can still be executed. If it is not in use, remove it.
- Never install nulled themes or pluginsPaid software offered free almost always carries something extra. This remains one of the most common ways Indian small business sites are compromised in the first place.
- Keep backups off the server, and test oneAn untested backup is a hope, not a plan. Restore one to a staging site once a quarter and confirm it works.
None of this needs an agency. It needs someone to actually do it every month, which is the part that quietly stops happening once a site is live and everyone is busy. That is the whole reason website maintenance plans exist, and why we treat updates, monitoring and off-server backups as routine work rather than something to arrange after a problem.
The plugins worth installing, and the ones to skip
Security plugin advice usually arrives as a list of twelve options with no guidance on which to pick or how to set any of them up. You need three things running: one security plugin, one backup plugin, and two-factor authentication. Adding more than that tends to slow the site down without making it safer.
Install one security plugin, not three
Running Wordfence next to Solid Security next to a third scanner is a common and counterproductive setup. They hook into the same parts of WordPress, duplicate firewall rules, and produce conflicting alerts, which trains you to ignore all of them. Worse, two plugins both trying to write firewall rules into .htaccess can lock you out of your own site.
Pick one and set it up properly.
| Plugin | What the free version covers | Suits |
|---|---|---|
| Wordfence Security | Firewall, malware scanner, login limits, file comparison against the official repository, two-factor | Most small business sites. The best free option if you only install one thing. |
| Solid Security (was iThemes) | Login hardening, file change detection, two-factor, user logging | Sites where Wordfence feels heavy. Lighter, with no bundled firewall in the free tier. |
| Patchstack | Virtual patching, which blocks known plugin flaws before you have updated | Sites running many plugins where updating quickly is not realistic. |
| Sucuri Security | File integrity monitoring, post-hack audit trail, hardening checks | Sites already compromised. Its audit log is good for working out what happened. |
| MalCare | Off-server scanning, one-click cleanup | Sites on cheap shared hosting where an on-server scan is too slow to finish. |
Wordfence, and the settings that actually matter
Installing Wordfence and leaving it on defaults gives you maybe half of what it can do. The firewall in particular does very little until you finish setting it up, which is the step most people skip.
- Switch the firewall to Extended ProtectionGo to Wordfence, then Firewall, then Manage Firewall, then Optimize the Wordfence Firewall. On defaults the firewall loads as a WordPress plugin, which means an attacker hitting a PHP file directly bypasses it entirely. Extended Protection loads it before WordPress starts. Pick your server type when prompted, and download the backup of
.htaccessit offers. - Leave Learning Mode on for a weekIt watches normal activity so it does not block you or your editors later. After seven days set it to Enabled and Protecting. Skipping this usually ends with someone locked out mid-edit.
- Turn on the deeper scan optionsUnder Scan, then Scan Options and Scheduling, switch on scanning files outside the WordPress installation, scanning images and binary files as though they were executable, and scanning for signatures in the uploads folder. The default scan skips exactly the places backdoors sit.
- Block code execution in uploadsFirewall, then Options, then find Disable Code Execution for Uploads directory. One checkbox that closes one of the most used routes back in.
- Set brute force protection properlyLock out after 5 failed attempts, lock for 4 hours, and switch on Immediately block the IP of users who try to sign in as a username that does not exist. That last one stops most automated attempts in a single request.
- Turn off the alerts you will not readWordfence emails a great deal by default. Keep alerts for admin logins, plugin changes and scan results. Turn the rest off, so the ones that arrive still mean something.
On shared hosting a full Wordfence scan can exhaust your CPU allowance and slow the site badly. Run the first one late at night, and if it stalls, lower the scan resource use under Scan Options. If it still cannot finish, an off-server scanner such as MalCare is a better fit for that hosting plan.
Backups belong in a separate plugin
Security plugins are not backup plugins, and a backup sitting on the same server as the site is not a backup. If the account is suspended or the server is compromised, both go together.
UpdraftPlus is the usual choice, and its free version does what a small business needs. Set it up like this:
- Send backups off-siteGoogle Drive, Dropbox or Amazon S3. This is the whole point. A backup written to a folder on your hosting account solves nothing.
- Database daily, files weeklyThe database holds orders, enquiries and content and changes constantly. Files change rarely.
- Keep at least four setsInfections are often noticed days late. Keeping only the most recent backup means the only copy you have already contains the problem.
- Restore one every quarterRestore to a staging site and confirm it works. An untested backup is a hope, not a plan.
Two-factor authentication on every administrator
This single change makes a stolen password almost useless, and it takes about five minutes per user. Wordfence Login Security is free and works as a standalone plugin if you use a different security plugin. WP 2FA is a good alternative with a friendlier setup flow for non-technical staff.
Apply it to every account with an administrator or editor role, not just your own. The account that gets compromised is usually the one belonging to somebody who left two years ago.
What about WP Hide and login URL changers
Worth being straight about these, because they are recommended more confidently than the evidence supports.
WP Hide, WPS Hide Login and similar plugins change your login address from /wp-login.php to something private, and can mask the signs that a site runs WordPress at all. The benefit is real but narrow: it cuts down the volume of automated login attempts hitting your server, which reduces log noise and load.
It is not a security control. Anyone deliberately targeting your business will find the login page. It also carries two practical risks: plugins that expect the standard login path can break, and if you forget the new address without saving it, getting back in means editing the database.
Use a login URL changer if the constant automated traffic is bothering you. Write the new address down somewhere outside the site. Do not count it as protection, and never install it in place of two-factor authentication and strong passwords.
Hardening that needs no plugin at all
Some of the most useful changes are a few lines in files you already have. They cost nothing, add no load, and cannot conflict with anything.
Four lines in wp-config.php
Add these above the line that reads that is all, stop editing.
define( 'DISALLOW_FILE_EDIT', true );
define( 'FORCE_SSL_ADMIN', true );
define( 'WP_AUTO_UPDATE_CORE', 'minor' );
define( 'DISALLOW_FILE_MODS', false );The first one removes the theme and plugin editor from the dashboard. That editor is how a great many attacks write their first file: gain access to one account, paste code into the theme, and the site is theirs. Almost nobody uses it legitimately.
The second forces the admin area over HTTPS. The third keeps WordPress applying its own security releases automatically.
The fourth is left off on purpose. Setting DISALLOW_FILE_MODS to true blocks all plugin and theme installs and updates from the dashboard, which is a strong protection but only workable if somebody is updating through SFTP or WP-CLI instead. Switch it on only if that is genuinely happening, because a site nobody can update is more dangerous than one with an active editor.
Stop PHP running in the uploads folder
Your uploads folder exists for images and documents. It has no reason to run code. Create a file at wp-content/uploads/.htaccess containing this, on Apache or LiteSpeed hosting:
<Files *.php>
Require all denied
</Files>On older Apache versions the equivalent is:
<Files *.php>
Order Deny,Allow
Deny from all
</Files>On Nginx this cannot be done from a file in the folder and needs a location block in the server config, which your host will usually add on request. Wordfence has a checkbox for the same thing, mentioned above, if you would rather not touch files.
Get file permissions right
| What | Permission | Why |
|---|---|---|
| Folders | 755 | Readable and traversable, writable only by the owner |
| Files | 644 | Readable by the server, writable only by the owner |
| wp-config.php | 600 or 640 | Holds your database password. Nothing else needs to read it. |
| Anything set to 777 | Change it today | Writable by anyone with access to the server, including other accounts on shared hosting |
If a plugin or a support agent ever asks you to set a folder to 777 to fix an upload problem, the real problem is file ownership on the server. Ask the host to correct the ownership rather than opening the folder to everybody.
Turn off what you are not using
- XML-RPC, at
xmlrpc.php, is used by the older WordPress mobile app and by Jetpack. Most sites do not need it, and it is a common target for password guessing at scale. Wordfence and Solid Security can both switch it off. - The REST API user endpoint lists your usernames to anyone who asks. Restricting it removes half of a login attempt before it starts.
- Author archives at
/author/username/expose login names on many themes. If you do not publish under bylines, switch them off. - Directory listing, so that visiting a folder without an index file shows nothing rather than a file list.
- PHP version. Running an unsupported PHP release means known flaws in the language itself go unpatched. Check it in Tools, then Site Health, and ask your host to move you up if you are behind.
A maintenance rhythm that keeps it that way
All of the above is setup work. It holds only if somebody keeps doing the small recurring part, which is where most sites quietly slip.
| How often | What | How long |
|---|---|---|
| Weekly | Apply plugin, theme and WordPress updates. Read the scan summary. Glance at the user list. | 15 to 20 minutes |
| Monthly | Confirm a backup completed and downloaded off-site. Check Search Console for security notices. Remove plugins nobody uses. | 20 minutes |
| Quarterly | Restore a backup to staging and confirm it works. Review who still has administrator access. Check the PHP version. | About an hour |
| Yearly | Rotate passwords and the wp-config salts. Audit every connected service with write access. | About an hour |
Twenty minutes a week is the entire difference between a site that stays clean and one that gets hacked twice a year. It is not difficult work. It is just work that nobody remembers to do once the site is live and everyone is busy with the business, which is the honest reason most small sites end up compromised.
When to stop and bring in help
Working through this yourself is reasonable in most cases. There are four situations where continuing alone tends to cost more than it saves.
- The site has been reinfected three or more times
- Your host has suspended the account and wants proof of cleanup before restoring it
- Customer data may have been accessed, which changes this from a technical problem into a legal one
- You are not confident reading PHP, and the site earns money every day it is down
Recovery pricing in India varies widely. A straightforward single-site cleanup usually runs between ₹5,000 and ₹15,000. Persistent reinfection with a rebuild sits higher. Set against that, a maintenance plan that keeps the site patched costs a fraction of one cleanup per year, which is the arithmetic most owners work out only after the second incident.
If you would rather not test that arithmetic personally, our WordPress development team handles recovery and hardening together, so the site does not go straight back onto the same shaky footing it was on before.