WordPress Hacked on cPanel? How to Find the Backdoor
Cleaning the obvious defacement or spam injection is not the same as removing the backdoor that let the attacker in, and left there, they will be back within days.
A WordPress site hacked on cPanel almost always has two layers to it: whatever visible damage got your attention, a defacement, a spam redirect, a flag from Google Search Console, and a backdoor left behind separately so the attacker can walk back in even after you clean up the visible part. Finding and fixing only the first layer is why so many sites get reinfected within a week of being cleaned.
Confirm the scope before you start cleaning
Do not fix the one file you noticed and call it done. Find every file modified around the same time, since an attacker who successfully got code execution rarely stops at one file.
find /home/USERNAME/public_html -type f -mtime -14 -printf '%T@ %p\n' | sort -n
Look for clusters, several files modified within the same minute or hour that are unrelated to any update you actually performed. Those clusters are your attacker's actual footprint, and they usually include at least one file you would never have found just by looking at the visible symptom.
Grep for the actual backdoor patterns
Most WordPress backdoors follow a small number of recognizable shapes. None of these patterns have a legitimate reason to exist in a normal theme or plugin file.
grep -rlE 'eval\s*\(\s*(base64_decode|gzinflate|str_rot13)' --include='*.php' /home/USERNAME/public_html
grep -rl 'FilesMan\|c99shell\|WSO' --include='*.php' /home/USERNAME/public_html
grep -rlE '\$_(GET|POST|REQUEST)\[.{1,20}\]\s*\(' --include='*.php' /home/USERNAME/public_html
The third pattern, a superglobal used directly as a function name, is a common way backdoors disguise a remote command as an ordinary-looking variable call. It produces some false positives in legitimate code, so verify each hit rather than deleting on sight, but it is worth checking every result.
| Where attackers hide it | Why it works |
|---|---|
Inside wp-content/uploads/ | PHP execution is often left enabled there by default, and the directory is rarely reviewed manually since it normally holds only media |
A file named to look like a core file, e.g. wp-load2.php | Blends into a directory listing next to legitimate WordPress core files |
Appended to the end of a legitimate, frequently-updated file like functions.php | Survives casual review since the rest of the file looks completely normal |
cat /home/USERNAME/public_html/wp-content/uploads/.htaccess 2>/dev/null
Confirm how they got in, not just what they left
Removing the backdoor without understanding the original entry point means the same route is often still open. Check for the usual causes in order of likelihood.
- An outdated plugin or theme with a known, published vulnerability. Cross-check installed versions against the WordPress Vulnerability Database or the plugin's own changelog for security fixes you missed.
- A weak or reused admin password, check
wp_usersfor accounts you do not recognize and review login history if a security plugin is logging it. - A file upload field with no type validation, common in older or poorly maintained contact form and file manager plugins.
- Credentials leaked from a different, unrelated breach and reused on this site, which an audit of the code cannot detect, only a password reset across every account fixes it.
Clean it properly
-
1
Take the site offline or into maintenance mode
Stops the attacker's existing backdoor from being actively used while you work, and stops the visible symptom from being seen by visitors or search engines in the meantime.
-
2
Remove every backdoor file found, not just the first one
Delete or quarantine each file confirmed as malicious from the searches above, keeping a copy off the server if you want to understand the attack further.
-
3
Update every plugin, theme and WordPress core to current versions
Closes the vulnerability that most likely let the attacker in in the first place, if it was a known exploit rather than a credential issue.
-
4
Rotate every credential the account touches
WordPress admin passwords, database password, cPanel password, and any API keys or SMTP credentials stored in
wp-config.phpor plugin settings.
Doing this thoroughly, once, on one compromised account is a few focused hours. Doing it correctly every time across dozens of hosted WordPress sites, and remembering to check the uploads folder and the modification-time clustering every single time, is where manual review breaks down. BashSecure scans every hosted account for these exact backdoor patterns, flags the full cluster of affected files together, and shows you the entry point evidence before you decide what to clean.
Finding every file a backdoor touched, not just the obvious one
Found the visible redirect in functions.php, appended 6 days ago. Found a second file in wp-content/uploads/2024/03/ disguised as an image with a .php extension, modified in the same minute. That second file is the actual backdoor, the redirect code alone would not survive a theme update.
| File | Modified | Role |
|---|---|---|
| functions.php | 6 days ago | visible redirect |
| uploads/2024/03/cache.php | 6 days ago, same minute | backdoor, re-injects on access |
Removing the injected code from functions.php, deleting the backdoor file, and adding a .htaccess rule to uploads/ denying PHP execution going forward.
echo '<Files *.php>\nDeny from all\n</Files>' > /home/USERNAME/public_html/wp-content/uploads/.htaccess
Try this on one of your own servers.
Start free trialVerify it is actually gone
Do not close this out on the visible symptom disappearing. Confirm the underlying access is closed.
grep -rlE 'eval\s*\(\s*(base64_decode|gzinflate|str_rot13)' --include='*.php' /home/USERNAME/public_html
An empty result confirms no remaining instance of the most common pattern. Also request a manual review in Google Search Console if the site was flagged there, and monitor file modification times for the next week or two, a backdoor that regenerates itself from a cron job or a second, undiscovered file will show up as new activity even after the first cleanup.
Prevent it happening again
- Deny PHP execution inside
wp-content/uploads/by default on every hosted WordPress account, not just the one that got hit. - Keep plugins, themes and core on a real update schedule rather than reactive patching after an incident.
- Run a recurring file integrity or malware scan rather than waiting for a visible symptom, since the backdoor is usually planted well before anything visible happens.