Security 7 min read

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.

By BashPilot Team
BashSecure Malware & vulnerability protection Scan, find and remove malware across every hosted account. Explore BashSecure

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.

every file modified in the last 14 days
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.

the most common backdoor signatures
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 itWhy 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.phpBlends into a directory listing next to legitimate WordPress core files
Appended to the end of a legitimate, frequently-updated file like functions.phpSurvives casual review since the rest of the file looks completely normal
check if PHP execution is disabled where it should be
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_users for 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. 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. 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. 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. 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.php or 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.

In BashPilot

Finding every file a backdoor touched, not just the obvious one

app.bashpilot.com
wordpress site on this account is redirecting to a spam page, find what's causing it
BashPilot

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.

FileModifiedRole
functions.php6 days agovisible redirect
uploads/2024/03/cache.php6 days ago, same minutebackdoor, re-injects on access
remove both and lock down the uploads folder
BashPilot

Removing the injected code from functions.php, deleting the backdoor file, and adding a .htaccess rule to uploads/ denying PHP execution going forward.

bash
echo '<Files *.php>\nDeny from all\n</Files>' > /home/USERNAME/public_html/wp-content/uploads/.htaccess
Example output, not a screenshot of a specific customer's server.

Try this on one of your own servers.

Start free trial

Verify it is actually gone

Do not close this out on the visible symptom disappearing. Confirm the underlying access is closed.

re-scan for the same patterns after cleanup
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.
Share LinkedIn X
Questions

Frequently asked questions

How do I find a WordPress backdoor after cleaning up an obvious hack?

Search for files modified within the same time window as the symptom you noticed, using `find /home/USERNAME/public_html -type f -mtime -14 -printf '%T@ %p\n' | sort -n`, then grep those results for common patterns like `eval(base64_decode(` or superglobals used as function calls. The backdoor is very often a separate file from whatever visible damage got your attention.

Why does WordPress keep getting reinfected after I clean it?

The most common reason is that only the visible symptom was removed while the actual backdoor, usually a separate disguised file, was left in place. The second most common reason is that credentials were changed but the original vulnerability, an outdated plugin or an unrestricted uploads folder, was never actually fixed.

Is it safe to just restore WordPress from a backup after finding a hack?

Only if you know exactly when the compromise happened and the backup predates it. Restoring from a backup taken after the backdoor was planted just reinstates the same infection. Confirm the backup's file modification dates against your findings before relying on it as the fix.

Should PHP execution be disabled in the wp-content/uploads folder?

Yes, in almost every case. Legitimate media uploads never need to execute as PHP, so denying execution there with a `.htaccess` rule (or the web server equivalent) closes off the single most common place attackers hide a backdoor, with no impact on normal site functionality.

How do I know if an attacker still has access after I change the WordPress admin password?

A changed admin password alone does not remove server-level backdoors, database access gained separately, or other admin accounts the attacker may have created. Check `wp_users` for accounts you do not recognize, rotate the database and hosting passwords as well, and re-scan for backdoor files rather than assuming a single password change closed every route in.

Put your servers on autopilot.

Connect a server in about a minute. The first week is on us.