<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>wordpress malware cleanup Archives - WP-CLI Mastery</title>
	<atom:link href="https://wpclimastery.com/blog/tag/wordpress-malware-cleanup/feed/" rel="self" type="application/rss+xml" />
	<link>https://wpclimastery.com/blog/tag/wordpress-malware-cleanup/</link>
	<description>Automate WordPress Like a DevOps Pro.</description>
	<lastBuildDate>Mon, 24 Nov 2025 11:16:48 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://wpclimastery.com/wp-content/uploads/2025/11/cropped-favicon-32x32.webp</url>
	<title>wordpress malware cleanup Archives - WP-CLI Mastery</title>
	<link>https://wpclimastery.com/blog/tag/wordpress-malware-cleanup/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>WordPress Malware Detection and Cleanup Using WP-CLI</title>
		<link>https://wpclimastery.com/blog/wordpress-malware-detection-and-cleanup-using-wp-cli/</link>
		
		<dc:creator><![CDATA[Krasen]]></dc:creator>
		<pubDate>Mon, 24 Nov 2025 11:16:24 +0000</pubDate>
				<category><![CDATA[WordPress Security & Maintenance]]></category>
		<category><![CDATA[malware detection wordpress]]></category>
		<category><![CDATA[wordpress hack cleanup]]></category>
		<category><![CDATA[wordpress malware cleanup]]></category>
		<category><![CDATA[wordpress security tools]]></category>
		<category><![CDATA[wp-cli security]]></category>
		<guid isPermaLink="false">https://wpclimastery.com/?p=217</guid>

					<description><![CDATA[<p>WordPress malware infections compromise site security, steal sensitive data, and damage reputation. WP-CLI provides powerful command-line tools for detecting, analyzing, and removing malware efficiently, often faster and more thoroughly than...</p>
<p>The post <a href="https://wpclimastery.com/blog/wordpress-malware-detection-and-cleanup-using-wp-cli/">WordPress Malware Detection and Cleanup Using WP-CLI</a> appeared first on <a href="https://wpclimastery.com">WP-CLI Mastery</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>WordPress malware infections compromise site security, steal sensitive data, and damage reputation. WP-CLI provides powerful command-line tools for detecting, analyzing, and removing malware efficiently, often faster and more thoroughly than manual cleanup or GUI-based security plugins.</p>



<h2 class="wp-block-heading" id="understanding-wordpress-malware">Understanding WordPress Malware</h2>



<p>Malware manifests in various forms: backdoors granting unauthorized access, spam injection contaminating content, redirect scripts hijacking visitors, cryptominers consuming server resources, and data exfiltration code stealing information. Understanding these patterns helps identify and remove infections effectively.</p>



<p>Common infection vectors include vulnerable plugins or themes, weak passwords, compromised hosting environments, and outdated WordPress core. WP-CLI enables systematic scanning and cleanup across all potential infection points.</p>



<h2 class="wp-block-heading" id="initial-assessment-and-backup">Initial Assessment and Backup</h2>



<p>Before attempting cleanup, assess the infection scope and create comprehensive backups. This ensures you can recover if cleanup causes issues.</p>



<pre class="wp-block-code"><code>#!/bin/bash
<em># pre-cleanup-assessment.sh - Initial malware assessment</em>

WP_PATH="/var/www/html"
BACKUP_DIR="/backups/malware-cleanup"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)

mkdir -p "$BACKUP_DIR"

echo "=== Pre-Cleanup Assessment ==="

<em># Create complete backup</em>
echo "Creating backup..."
wp --path="$WP_PATH" db export "$BACKUP_DIR/database-$TIMESTAMP.sql"
tar -czf "$BACKUP_DIR/files-$TIMESTAMP.tar.gz" -C "$(dirname $WP_PATH)" "$(basename $WP_PATH)"

<em># Get WordPress version</em>
WP_VERSION=$(wp --path="$WP_PATH" core version)
echo "WordPress Version: $WP_VERSION"

<em># Check for core file modifications</em>
echo "Checking core file integrity..."
wp --path="$WP_PATH" core verify-checksums

<em># List all users (especially admins)</em>
echo "Admin users:"
wp --path="$WP_PATH" user list --role=administrator --fields=ID,user_login,user_email

<em># Check for suspicious users</em>
echo "Recently created users:"
wp --path="$WP_PATH" user list --format=json | \
    jq -r '.&#91;] | select(.roles | contains(&#91;"administrator"])) | "\(.ID)\t\(.user_login)\t\(.user_registered)"'

<em># List active plugins</em>
echo "Active plugins:"
wp --path="$WP_PATH" plugin list --status=active --fields=name,version,update

<em># Check for suspicious scheduled tasks</em>
echo "Scheduled cron events:"
wp --path="$WP_PATH" cron event list --format=table

echo "Assessment completed. Backup saved to: $BACKUP_DIR"
</code></pre>



<h2 class="wp-block-heading" id="core-file-integrity-verification">Core File Integrity Verification</h2>



<p>WordPress core files rarely need modification. Any changes often indicate compromise.</p>



<pre class="wp-block-code"><code><em># Verify core file checksums</em>
wp core verify-checksums

<em># Get detailed output of modified files</em>
wp core verify-checksums --format=json | jq -r '.&#91;] | select(.status == "modified") | .file'

<em># Reinstall WordPress core (preserves wp-content and wp-config.php)</em>
wp core download --force --skip-content

<em># Verify specific file</em>
wp core verify-checksums wp-admin/index.php
</code></pre>



<p>Automated core file restoration:</p>



<pre class="wp-block-code"><code>#!/bin/bash
<em># restore-core-files.sh - Restore modified core files</em>

WP_PATH="/var/www/html"

echo "Checking for modified core files..."

<em># Get list of modified files</em>
MODIFIED_FILES=$(wp --path="$WP_PATH" core verify-checksums --format=csv | grep -v "^file,status$" | grep "should_not_exist\|not_found\|modified" | cut -d',' -f1)

if &#91; -z "$MODIFIED_FILES" ]; then
    echo "No modified core files found"
    exit 0
fi

echo "Modified files found:"
echo "$MODIFIED_FILES"

<em># Backup modified files before restoration</em>
BACKUP_DIR="/backups/core-files-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$BACKUP_DIR"

echo "$MODIFIED_FILES" | while read -r file; do
    if &#91; -f "$WP_PATH/$file" ]; then
        BACKUP_PATH="$BACKUP_DIR/$(dirname $file)"
        mkdir -p "$BACKUP_PATH"
        cp "$WP_PATH/$file" "$BACKUP_PATH/"
        echo "Backed up: $file"
    fi
done

<em># Reinstall core</em>
echo "Reinstalling WordPress core..."
wp --path="$WP_PATH" core download --force --skip-content

<em># Verify restoration</em>
if wp --path="$WP_PATH" core verify-checksums; then
    echo "Core files successfully restored"
else
    echo "Warning: Some core files still show modifications"
fi
</code></pre>



<h2 class="wp-block-heading" id="database-scanning-and-cleanup">Database Scanning and Cleanup</h2>



<p>Malware often injects malicious code into the database, particularly in posts, options, and user metadata.</p>



<pre class="wp-block-code"><code><em># Search database for common malware patterns</em>
wp db query "SELECT * FROM wp_posts WHERE post_content LIKE '%base64_decode%' OR post_content LIKE '%eval(%' OR post_content LIKE '%gzinflate%'"

<em># Search options table</em>
wp db query "SELECT * FROM wp_options WHERE option_value LIKE '%eval(%' OR option_value LIKE '%base64_decode%'"

<em># Find suspicious JavaScript injections</em>
wp db query "SELECT post_id, post_title FROM wp_posts WHERE post_content LIKE '%&lt;script%' AND post_type='post'"

<em># Check for malicious admin users</em>
wp db query "SELECT * FROM wp_users WHERE user_login LIKE '%admin%' OR user_login REGEXP '^&#91;0-9]+$'"

<em># Find posts with suspicious meta data</em>
wp db query "SELECT meta_id, post_id, meta_key, meta_value FROM wp_postmeta WHERE meta_value LIKE '%&lt;script%' OR meta_value LIKE '%eval(%'"
</code></pre>



<p>Comprehensive database scanning script:</p>



<pre class="wp-block-code"><code>#!/bin/bash
<em># scan-database.sh - Scan database for malware patterns</em>

WP_PATH="/var/www/html"
REPORT_FILE="/var/log/malware-scan-$(date +%Y%m%d-%H%M%S).txt"

echo "=== WordPress Database Malware Scan ===" | tee "$REPORT_FILE"
echo "Date: $(date)" | tee -a "$REPORT_FILE"
echo "" | tee -a "$REPORT_FILE"

<em># Malware patterns to search for</em>
PATTERNS=(
    "base64_decode"
    "eval("
    "gzinflate"
    "str_rot13"
    "preg_replace.*\/e"
    "assert("
    "stripslashes"
    "iframe src"
    "script src=.*http"
    "document.write"
)

<em># Tables to scan</em>
TABLES=(
    "wp_posts"
    "wp_options"
    "wp_postmeta"
    "wp_usermeta"
    "wp_comments"
)

for pattern in "${PATTERNS&#91;@]}"; do
    echo "Searching for pattern: $pattern" | tee -a "$REPORT_FILE"

    for table in "${TABLES&#91;@]}"; do
        COUNT=$(wp --path="$WP_PATH" db query "SELECT COUNT(*) as count FROM $table" --skip-column-names 2&gt;/dev/null)

        if &#91; "$COUNT" -gt 0 ]; then
            <em># Get column names for table</em>
            COLUMNS=$(wp --path="$WP_PATH" db query "SHOW COLUMNS FROM $table" --skip-column-names | awk '{print $1}' | grep -E 'content|value|text')

            for column in $COLUMNS; do
                MATCHES=$(wp --path="$WP_PATH" db query "
                    SELECT COUNT(*) FROM $table
                    WHERE $column LIKE '%$pattern%'
                " --skip-column-names 2&gt;/dev/null || echo "0")

                if &#91; "$MATCHES" -gt 0 ]; then
                    echo "  Found $MATCHES matches in $table.$column" | tee -a "$REPORT_FILE"

                    <em># Get sample matches</em>
                    wp --path="$WP_PATH" db query "
                        SELECT * FROM $table
                        WHERE $column LIKE '%$pattern%'
                        LIMIT 3
                    " &gt;&gt; "$REPORT_FILE"
                fi
            done
        fi
    done
    echo "" | tee -a "$REPORT_FILE"
done

echo "Scan completed. Report saved to: $REPORT_FILE"
</code></pre>



<h2 class="wp-block-heading" id="plugin-and-theme-scanning">Plugin and Theme Scanning</h2>



<p>Compromised or nulled plugins/themes are common infection sources.</p>



<pre class="wp-block-code"><code><em># List all plugins</em>
wp plugin list --fields=name,status,version,update

<em># Check for plugins from suspicious sources</em>
wp plugin list --status=active --format=json | jq -r '.&#91;] | select(.update == "available") | .name'

<em># Deactivate all plugins (for diagnosis)</em>
wp plugin deactivate --all

<em># Reactivate plugins one by one</em>
wp plugin activate plugin-name

<em># Delete inactive plugins</em>
wp plugin delete $(wp plugin list --status=inactive --field=name)

<em># Check theme integrity</em>
wp theme list --fields=name,status,version,update

<em># Switch to default theme</em>
wp theme activate twentytwentyfour

<em># Delete unused themes</em>
wp theme delete $(wp theme list --status=inactive --field=name)
</code></pre>



<p>Scan for malicious code in plugins and themes:</p>



<pre class="wp-block-code"><code>#!/bin/bash
<em># scan-plugins-themes.sh - Scan for malware in plugins and themes</em>

WP_PATH="/var/www/html"
SCAN_LOG="/var/log/plugin-theme-scan-$(date +%Y%m%d).txt"

echo "=== Scanning Plugins and Themes for Malware ===" | tee "$SCAN_LOG"

<em># Malicious code patterns</em>
PATTERNS=(
    "eval\s*\("
    "base64_decode"
    "gzinflate"
    "str_rot13"
    "system\s*\("
    "exec\s*\("
    "shell_exec"
    "passthru"
    "preg_replace.*\/e"
    "\$_GET\&#91;.*\]\(.*\)"
    "\$_POST\&#91;.*\]\(.*\)"
)

<em># Scan plugins</em>
echo "Scanning plugins..." | tee -a "$SCAN_LOG"
for plugin_dir in "$WP_PATH/wp-content/plugins/"*/; do
    PLUGIN_NAME=$(basename "$plugin_dir")
    echo "Checking: $PLUGIN_NAME" | tee -a "$SCAN_LOG"

    for pattern in "${PATTERNS&#91;@]}"; do
        MATCHES=$(grep -r -i -E "$pattern" "$plugin_dir" 2&gt;/dev/null | wc -l)

        if &#91; "$MATCHES" -gt 0 ]; then
            echo "  WARNING: Found $MATCHES matches for '$pattern'" | tee -a "$SCAN_LOG"
            grep -r -i -n -E "$pattern" "$plugin_dir" | head -5 &gt;&gt; "$SCAN_LOG"
        fi
    done
done

<em># Scan themes</em>
echo "Scanning themes..." | tee -a "$SCAN_LOG"
for theme_dir in "$WP_PATH/wp-content/themes/"*/; do
    THEME_NAME=$(basename "$theme_dir")
    echo "Checking: $THEME_NAME" | tee -a "$SCAN_LOG"

    for pattern in "${PATTERNS&#91;@]}"; do
        MATCHES=$(grep -r -i -E "$pattern" "$theme_dir" 2&gt;/dev/null | wc -l)

        if &#91; "$MATCHES" -gt 0 ]; then
            echo "  WARNING: Found $MATCHES matches for '$pattern'" | tee -a "$SCAN_LOG"
            grep -r -i -n -E "$pattern" "$theme_dir" | head -5 &gt;&gt; "$SCAN_LOG"
        fi
    done
done

echo "Scan completed. Results in: $SCAN_LOG"
</code></pre>



<h2 class="wp-block-heading" id="removing-malicious-users-and-content">Removing Malicious Users and Content</h2>



<p>Delete unauthorized admin accounts and clean infected content.</p>



<pre class="wp-block-code"><code><em># List all administrators</em>
wp user list --role=administrator --format=table

<em># Delete suspicious user</em>
wp user delete 999 --yes --reassign=1

<em># Remove spam posts</em>
wp post delete $(wp post list --post_status=spam --format=ids) --force

<em># Clean spam comments</em>
wp comment delete $(wp comment list --status=spam --format=ids) --force

<em># Remove posts with malicious content</em>
wp db query "DELETE FROM wp_posts WHERE post_content LIKE '%malicious-pattern%'"

<em># Clean options table</em>
wp option delete suspicious_option_name

<em># Remove malicious scheduled tasks</em>
wp cron event delete suspicious_hook
</code></pre>



<p>Automated malicious user cleanup:</p>



<pre class="wp-block-code"><code>#!/bin/bash
<em># cleanup-users.sh - Remove suspicious WordPress users</em>

WP_PATH="/var/www/html"

echo "Scanning for suspicious users..."

<em># Get all admin users</em>
ADMIN_USERS=$(wp --path="$WP_PATH" user list --role=administrator --format=json)

<em># Check for users with suspicious characteristics</em>
echo "$ADMIN_USERS" | jq -r '.&#91;] | select(
    .user_login | test("^&#91;0-9]+$|admin&#91;0-9]+|wp&#91;-_]admin|support&#91;0-9]+")
) | .ID' | while read -r user_id; do
    USER_LOGIN=$(wp --path="$WP_PATH" user get $user_id --field=user_login)
    USER_EMAIL=$(wp --path="$WP_PATH" user get $user_id --field=user_email)
    USER_REGISTERED=$(wp --path="$WP_PATH" user get $user_id --field=user_registered)

    echo "Suspicious user found:"
    echo "  ID: $user_id"
    echo "  Login: $USER_LOGIN"
    echo "  Email: $USER_EMAIL"
    echo "  Registered: $USER_REGISTERED"

    <em># Uncomment to actually delete</em>
    <em># wp --path="$WP_PATH" user delete $user_id --yes --reassign=1</em>
    <em># echo "  Deleted"</em>
done

<em># Check for users with no posts and recently created</em>
echo "Checking for recently created users with no activity..."
wp --path="$WP_PATH" user list --format=json | jq -r '.&#91;] |
    select(.roles | contains(&#91;"administrator"])) |
    "\(.ID)\t\(.user_login)\t\(.user_registered)"'
</code></pre>



<h2 class="wp-block-heading" id="file-system-cleanup">File System Cleanup</h2>



<p>Search for and remove malicious files in the WordPress installation.</p>



<pre class="wp-block-code"><code>#!/bin/bash
<em># filesystem-scan.sh - Scan for suspicious files</em>

WP_PATH="/var/www/html"
SCAN_LOG="/var/log/filesystem-scan-$(date +%Y%m%d).txt"

echo "=== File System Malware Scan ===" | tee "$SCAN_LOG"

<em># Find recently modified files (last 7 days)</em>
echo "Recently modified files:" | tee -a "$SCAN_LOG"
find "$WP_PATH" -type f -mtime -7 -not -path "*/cache/*" -not -path "*/uploads/*" | tee -a "$SCAN_LOG"

<em># Find PHP files with suspicious names</em>
echo "Suspicious PHP files:" | tee -a "$SCAN_LOG"
find "$WP_PATH" -type f \( \
    -name "*.php.*" -o \
    -name "*.suspected" -o \
    -name "*.bak.php" -o \
    -name "*eval*.php" -o \
    -name "*base64*.php" -o \
    -iname "wp-config.php.bak" \
\) | tee -a "$SCAN_LOG"

<em># Find files with suspicious permissions (world-writable)</em>
echo "World-writable files:" | tee -a "$SCAN_LOG"
find "$WP_PATH" -type f -perm -0002 | tee -a "$SCAN_LOG"

<em># Find hidden PHP files</em>
echo "Hidden PHP files:" | tee -a "$SCAN_LOG"
find "$WP_PATH" -type f -name ".*\.php" | tee -a "$SCAN_LOG"

<em># Find files owned by wrong user (should be www-data or similar)</em>
echo "Files with incorrect ownership:" | tee -a "$SCAN_LOG"
find "$WP_PATH" -type f ! -user www-data ! -user root | head -20 | tee -a "$SCAN_LOG"

<em># Search for base64 encoded strings in PHP files</em>
echo "Files containing base64 encoding:" | tee -a "$SCAN_LOG"
grep -r -l "base64_decode" "$WP_PATH"/*.php "$WP_PATH"/wp-includes/*.php "$WP_PATH"/wp-admin/*.php 2&gt;/dev/null | tee -a "$SCAN_LOG"

echo "Scan completed: $SCAN_LOG"
</code></pre>



<h2 class="wp-block-heading" id="security-hardening-post-cleanup">Security Hardening Post-Cleanup</h2>



<p>After malware removal, implement security measures to prevent reinfection.</p>



<pre class="wp-block-code"><code>#!/bin/bash
<em># security-hardening.sh - Harden WordPress after cleanup</em>

WP_PATH="/var/www/html"

echo "Applying security hardening..."

<em># Update all components</em>
wp --path="$WP_PATH" core update
wp --path="$WP_PATH" plugin update --all
wp --path="$WP_PATH" theme update --all

<em># Set secure file permissions</em>
find "$WP_PATH" -type d -exec chmod 755 {} \;
find "$WP_PATH" -type f -exec chmod 644 {} \;
chmod 600 "$WP_PATH/wp-config.php"

<em># Disable file editing</em>
wp --path="$WP_PATH" config set DISALLOW_FILE_EDIT true --raw --type=constant

<em># Force SSL for admin</em>
wp --path="$WP_PATH" config set FORCE_SSL_ADMIN true --raw --type=constant

<em># Set security keys</em>
wp --path="$WP_PATH" config shuffle-salts

<em># Remove inactive plugins and themes</em>
wp --path="$WP_PATH" plugin delete $(wp --path="$WP_PATH" plugin list --status=inactive --field=name)
wp --path="$WP_PATH" theme delete $(wp --path="$WP_PATH" theme list --status=inactive --field=name)

<em># Disable XML-RPC if not needed</em>
cat &gt;&gt; "$WP_PATH/wp-config.php" &lt;&lt; 'EOF'
add_filter('xmlrpc_enabled', '__return_false');
EOF

<em># Install and configure security plugin</em>
wp --path="$WP_PATH" plugin install wordfence --activate
wp --path="$WP_PATH" option update wordfence_scan_enabled 1

<em># Change all user passwords</em>
echo "Resetting all user passwords..."
for user_id in $(wp --path="$WP_PATH" user list --field=ID); do
    NEW_PASS=$(openssl rand -base64 16)
    wp --path="$WP_PATH" user update $user_id --user_pass="$NEW_PASS"
    echo "User ID $user_id password reset"
done

<em># Clean and optimize database</em>
wp --path="$WP_PATH" db optimize

echo "Security hardening completed"
</code></pre>



<h2 class="wp-block-heading" id="monitoring-and-prevention">Monitoring and Prevention</h2>



<p>Set up monitoring to detect future compromises early.</p>



<pre class="wp-block-code"><code>#!/bin/bash
<em># monitor-integrity.sh - Monitor WordPress for changes</em>

WP_PATH="/var/www/html"
HASH_FILE="/var/backups/wp-hashes.txt"
ALERT_EMAIL="admin@example.com"

<em># Create hash database if it doesn't exist</em>
if &#91; ! -f "$HASH_FILE" ]; then
    echo "Creating initial hash database..."
    find "$WP_PATH" -type f ! -path "*/uploads/*" ! -path "*/cache/*" -exec md5sum {} + &gt; "$HASH_FILE"
    echo "Hash database created"
    exit 0
fi

<em># Check for changes</em>
TEMP_HASH="/tmp/wp-hashes-temp.txt"
find "$WP_PATH" -type f ! -path "*/uploads/*" ! -path "*/cache/*" -exec md5sum {} + &gt; "$TEMP_HASH"

<em># Compare hashes</em>
CHANGES=$(diff "$HASH_FILE" "$TEMP_HASH" | grep "^&#91;&lt;&gt;]" | wc -l)

if &#91; "$CHANGES" -gt 0 ]; then
    echo "WARNING: $CHANGES files have changed"

    <em># Send alert</em>
    diff "$HASH_FILE" "$TEMP_HASH" | mail -s "WordPress File Changes Detected" "$ALERT_EMAIL"

    <em># Update hash database</em>
    mv "$TEMP_HASH" "$HASH_FILE"
else
    echo "No changes detected"
    rm "$TEMP_HASH"
fi
</code></pre>



<h2 class="wp-block-heading" id="related-links">Related Links</h2>



<ul class="wp-block-list">
<li><a href="https://wordpress.org/support/article/hardening-wordpress/">WordPress Security Documentation</a></li>



<li><a href="https://developer.wordpress.org/cli/commands/">WP-CLI Security Commands</a></li>



<li><a href="https://sucuri.net/guides/what-is-website-malware/">Sucuri Security Guide</a></li>



<li><a href="https://www.wordfence.com/blog/">Wordfence Security Blog</a></li>



<li><a href="https://owasp.org/www-community/vulnerabilities/">OWASP WordPress Security</a></li>
</ul>
<p>The post <a href="https://wpclimastery.com/blog/wordpress-malware-detection-and-cleanup-using-wp-cli/">WordPress Malware Detection and Cleanup Using WP-CLI</a> appeared first on <a href="https://wpclimastery.com">WP-CLI Mastery</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
