Skip to content

Instantly share code, notes, and snippets.

@daviddarke
Created December 2, 2025 15:54
Show Gist options
  • Select an option

  • Save daviddarke/cded25cd27e27265ac9ec8a3cac8bc6b to your computer and use it in GitHub Desktop.

Select an option

Save daviddarke/cded25cd27e27265ac9ec8a3cac8bc6b to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
#
# Scan a WordPress theme (or themes directory) for suspicious code.
#
# Usage examples:
# # from WP root, scan ALL themes:
# bash scan_wp_theme.sh wp-content/themes
#
# # scan a specific theme:
# bash scan_wp_theme.sh wp-content/themes/twentytwentyfive
#
# # with absolute path:
# bash scan_wp_theme.sh /var/www/html/wp-content/themes
#
THEME_DIR="${1:-wp-content/themes}"
if [ ! -d "$THEME_DIR" ]; then
echo "Directory not found: $THEME_DIR" >&2
exit 1
fi
echo "Scanning theme directory: $THEME_DIR"
echo
#################################
# 1) List PHP files we will scan
#################################
echo "=== PHP files found (for awareness) ==="
find "$THEME_DIR" -type f -name "*.php" -print
echo
###########################################
# 2) Recently modified PHP files (top 30)
###########################################
echo "=== Recently modified PHP files (top 30) ==="
# Adjust -mtime if you only care about last N days, e.g. -mtime -7 for 7 days
find "$THEME_DIR" -type f -name "*.php" -printf "%TY-%Tm-%Td %TH:%TM:%TS %p\n" \
| sort -r \
| head -n 30
echo
#####################################################
# 3) Grep PHP for common malware / obfuscation signs
#####################################################
echo "=== Searching PHP for suspicious patterns ==="
# Common suspicious constructs seen in WP malware
PATTERN_MALICIOUS='
(eval *\()|
(assert *\()|
(preg_replace *\(.*/e)|
(create_function *\()|
(base64_decode *\()|
(gzinflate *\()|
(str_rot13 *\()|
(shell_exec *\()|
(system *\()|
(passthru *\()|
(popen *\()|
(proc_open *\()|
(error_reporting *\(0\))|
(@ini_set *\()|
(@include *\()|
(@require *\()|
(\$\w+ *= *\$\{\$)|
(GLOBALS\[\$\w+\])|
(\\x[0-9a-fA-F]{2})|
(base64_encode *\()|
(goto +[a-zA-Z_])
'
# Compact whitespace in the regex (so the above is readable)
PATTERN_MALICIOUS=$(echo "$PATTERN_MALICIOUS" | tr -d '\n')
echo "--- Suspicious PHP function / pattern matches ---"
find "$THEME_DIR" -type f -name "*.php" -print0 \
| xargs -0 -r grep -nE "$PATTERN_MALICIOUS" 2>/dev/null \
|| echo "No suspicious patterns found (or none matched)."
echo
###################################################
# 4) PHP files containing URLs (possible callbacks)
###################################################
echo "=== PHP files with embedded URLs (could be legit, but worth a look) ==="
find "$THEME_DIR" -type f -name "*.php" -print0 \
| xargs -0 -r grep -nE "https?://[a-zA-Z0-9./_-]+" 2>/dev/null \
|| echo "No URLs found in PHP files."
echo
###############################################
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment