If you manage WordPress websites — whether it’s one site or fifty — you already know that WordPress is the most targeted CMS on the internet. Attackers are constantly scanning for vulnerable plugins, dropping webshells into upload directories, and injecting backdoors into core files. The commercial scanners catch some of it, but they miss things. And if you’re managing multiple client sites on shared hosting, you need something that can sweep the entire webroot in one pass.
That’s why we built an open-source bash script that proactively hunts for WordPress malware, PHP backdoors, obfuscated payloads, and living-off-the-land techniques across your entire /var/www/html directory tree. We’re releasing it for free because the WordPress community deserves better tooling to fight back.
What the Scanner Detects
This isn’t a simple grep for “eval(base64_decode” and call it a day. The scanner runs 15 distinct detection modules that cover the full spectrum of WordPress-specific attack techniques.
Known Webshell Signatures
The scanner matches over 30 known webshell and backdoor signatures including FilesMan, b374k, c99shell, r57shell, WSO, AnonymousFox, Gh0st, IndoXploit, alfashell, and the P.A.S. shell. When a signature hits, the file is immediately SHA256-hashed for incident correlation, and the finding is logged as CRITICAL.
Obfuscated Payloads
Modern WordPress malware almost never ships as readable PHP. Attackers obfuscate their code using base64 encoding, hex escape sequences, chr() concatenation chains, gzinflate/gzuncompress wrappers, and str_rot13. The scanner detects all of these patterns, with special escalation when obfuscation is chained with eval() — the classic eval(base64_decode(...)) pattern that powers the majority of PHP backdoors in the wild.
Dangerous PHP Functions
The scanner flags calls to dangerous functions like eval, exec, system, passthru, shell_exec, popen, proc_open, pcntl_exec, create_function, and assert. It intelligently skips WordPress core directories (wp-includes/ and wp-admin/) where these functions are used legitimately, but still flags them if they’re combined with obfuscation — because a legitimate core file should never contain eval(gzinflate(...)).
Superglobal Injection Vectors
This is the classic one-liner backdoor: eval($_POST['cmd']), system($_GET['c']), or include($_REQUEST['f']). The scanner detects any dangerous function call that directly consumes $_GET, $_POST, $_REQUEST, $_COOKIE, $_SERVER, or $_FILES as input.
Suspicious Files and Extensions
PHP files inside wp-content/uploads/ should never exist — that directory is for media, not executable code. The scanner flags these immediately as CRITICAL. It also detects double-extension bypass attempts (.php.jpg, .php.png, .php.ico), alternative PHP handlers (.pht, .php7, .phar), quarantined files (.suspected), leftover backups (.bak, .old, .orig), hidden dot-files, and the favicon.ico backdoor technique where attackers disguise PHP code inside .ico files.
.htaccess Hijacking
Attackers frequently modify .htaccess to redirect visitors to malicious domains or inject PHP execution into directories where it shouldn’t run. The scanner detects RewriteRule redirects pointing to suspicious TLDs (.tk, .ga, .ml, .cf, .xyz, etc.), auto_prepend_file injection (which prepends malicious PHP to every page load), and php_flag engine on directives that enable PHP execution in upload directories.
WordPress Core Integrity
If wp-cli is installed, the scanner runs wp core verify-checksums against every WordPress installation it finds under the webroot. This compares your core files against the official WordPress.org checksums and flags any modifications. It also enumerates outdated plugins with available updates — because unpatched plugins are the number one attack vector for WordPress compromise.
Persistence Mechanisms
The scanner checks WP-Cron hooks for suspicious entries (hooks containing curl, wget, eval, exec, etc.) and inspects system crontab entries that reference the webroot. It also examines wp-config.php for injected code and multiple DB_PASSWORD definitions, which can indicate credential harvesting.
Injected Content
Hidden iframes, external scripts loading from suspicious TLDs, and JavaScript eval obfuscation using unescape, String.fromCharCode, or atob are all detected. The scanner also identifies mailer and spam scripts that abuse PHP’s mail() function with superglobal input.
False-Positive Mitigation: Lessons from Production
We built this scanner because we needed it for our own client hosting environment — dozens of WordPress sites under one webroot. The first version of the script generated over 1,500 CRITICAL findings. After analysis, the vast majority were false positives caused by two specific sources.
Wordfence WAF Rule Files
If you run Wordfence (and you should), its Web Application Firewall stores rule definitions in wp-content/wflogs/. These rule files contain the actual text of threat signatures — strings like “AnonymousFox,” “Gh0st,” and “wso2” — because that’s how Wordfence detects them. A naive malware scanner will flag Wordfence’s own detection rules as infections. Version 2 of our scanner excludes wflogs/ from all signature scans.
WordPress ID3 Tag Parser
WordPress core includes an ID3 audio metadata parser at wp-includes/ID3/getid3.php. This file contains the string “Macker” in legitimate audio format metadata. Every WordPress installation on your server will trigger a false positive on this file. The scanner now excludes ID3/ paths from signature matching.
Other Exclusions
The scanner applies targeted exclusions to reduce noise without sacrificing detection. WordPress core directories (wp-includes/, wp-admin/) are skipped for dangerous function checks unless combined with obfuscation chains. The vendor/, node_modules/, and .git/ directories are excluded from encoded payload scans because libraries legitimately contain base64 data for fonts, certificates, and other binary assets. Legitimate PHPMailer library paths are excluded from mailer detection. And cache/, updraft/, and backup/ directories are excluded from recently-modified file checks.
The key design principle is that all signatures are retained — we don’t remove detection patterns. We only skip paths where those patterns are known to appear in legitimate, non-malicious code. If “AnonymousFox” shows up in a PHP file outside of wflogs/, it will still fire as CRITICAL.
How to Use the Scanner
The script is a single self-contained bash file with no external dependencies (wp-cli and YARA are optional enhancements). Download it, make it executable, and run it as root for full file permission checks.
Basic Usage
# Default: scans /var/www/html, logs to /root/logs/
sudo ./wordpress_malware_scan.sh
# Custom webroot and log directory
sudo ./wordpress_malware_scan.sh /var/www/clientsite /var/log/malware_scansLog Output
Every finding is written to a timestamped log file at /root/logs/wordpress_malware_YYYYMMDD_HHMMSS.log with severity levels (CRITICAL, HIGH, MEDIUM, LOW, INFO) and SHA256 hashes for flagged files. You can quickly review critical findings with:
grep 'CRITICAL' /root/logs/wordpress_malware_*.logScheduling Automated Scans
Add a cron entry to run the scanner on a regular schedule. Weekly is a good starting point for most environments:
# Weekly scan at 2 AM Sunday
0 2 * * 0 /root/scripts/wordpress_malware_scan.sh /var/www/html /root/logs 2>&1Configuration
The top of the script contains tunable variables. Set EXPECTED_OWNER to match your web server user (www-data on Debian/Ubuntu, apache on RHEL/CentOS). Adjust MODIFIED_DAYS to control the recently-modified file window. Point YARA_RULES at your YARA ruleset for an additional detection layer. The EXCLUDE_PATHS variable controls which directories are skipped globally — add additional paths here if your environment has other known false-positive sources.
Recommended Companion Tools
This scanner is designed to complement, not replace, your existing security stack. For the best coverage, pair it with Wordfence or Sucuri for real-time WAF protection, wp-cli for core integrity verification and plugin management, YARA with WordPress-specific rulesets for advanced signature matching, and a SIEM for centralized log analysis and correlation. If you’re running a multi-tenant WordPress hosting environment, consider piping the scanner output into your SIEM for automated alerting on CRITICAL findings.
Download the Scanner
The complete script is available for download below. It’s free to use, modify, and distribute. If you find it useful, we’d appreciate a link back to this post.
If you need help cleaning up a compromised WordPress site, hardening your hosting environment, or setting up proactive malware scanning for your business, contact Pendergrass Consulting. We provide managed WordPress security, incident response, and infrastructure hardening for small businesses across North Carolina and nationwide.












