Automate WordPress Security Scanning and Monitoring with WP-CLI

WordPress security requires constant vigilance—manually checking for plugin vulnerabilities, monitoring file changes, detecting malware, verifying core integrity, and reviewing user permissions. Manual security audits happen infrequently and miss threats between checks.

Automated WordPress security scanning with WP-CLI detects vulnerabilities continuously, monitors file integrity, checks for malware patterns, validates checksums, and alerts on suspicious changes. Run comprehensive security scans daily without manual intervention.

In this guide, you’ll build automated WordPress security monitoring systems using WP-CLI, from basic vulnerability checks to production-grade security automation that protects your sites 24/7.

Why Automate WordPress Security?

Manual WordPress security checks don’t provide continuous protection against evolving threats.

Manual Security Limitations

Infrequent checks: Manual audits happen weekly or monthly, leaving gaps.

Human error: Manual reviews miss subtle security indicators.

Time-consuming: Comprehensive security audits take hours per site.

No real-time alerts: Breaches go undetected until the next manual check.

Limited scope: Can’t check every file, user, and configuration regularly.

Automated Security Benefits

Continuous monitoring: Security checks run automatically every day.

Instant alerts: Get notified immediately when threats are detected.

Comprehensive coverage: Scan every file, plugin, theme, and configuration.

Historical tracking: Log all security events for forensic analysis.

Multi-site management: Monitor dozens of WordPress sites from one system.

According to Sucuri research, automated security monitoring detects breaches 85% faster than manual audits.

Core File Integrity Verification

Detect unauthorized modifications to WordPress core files.

Checksum Verification

#!/bin/bash
# verify-core-integrity.sh

echo "WordPress Core Integrity Check"
echo "==============================="

# Verify core file checksums
if wp core verify-checksums; then
    echo "✓ Core files verified - no modifications detected"
else
    echo "✗ ALERT: Core files modified or corrupted"
    echo "Details:"
    wp core verify-checksums --format=json | jq -r '.[] | "  - \(.)"'

    # Send alert
    echo "Core file integrity check failed on $(hostname)" | \
        mail -s "WordPress Security Alert" admin@example.com
fi

Automated Daily Verification

#!/bin/bash
# daily-integrity-check.sh

LOG_FILE="/var/log/wp-security.log"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $@" | tee -a "$LOG_FILE"
}

log "Starting core integrity check"

# Check WordPress core
if ! wp core verify-checksums 2>&1 | tee -a "$LOG_FILE"; then
    log "✗ Core integrity check FAILED"

    # Create detailed report
    {
        echo "WordPress Core Integrity Failure"
        echo "================================="
        echo "Timestamp: $(date)"
        echo "Server: $(hostname)"
        echo "WordPress version: $(wp core version)"
        echo ""
        echo "Modified files:"
        wp core verify-checksums 2>&1 | grep "^Error:"
    } | mail -s "URGENT: WordPress Core Modified" security@example.com

    exit 1
fi

log "✓ Core integrity check passed"

Learn about WordPress file integrity.

Plugin and Theme Vulnerability Detection

Check for known security vulnerabilities in plugins and themes.

WP-CLI Vulnerability Scanner

#!/bin/bash
# scan-vulnerabilities.sh

echo "WordPress Vulnerability Scan"
echo "============================"

# Check if WPScan CLI is available
if ! command -v wpscan &> /dev/null; then
    echo "Installing WPScan..."
    gem install wpscan
fi

# Update WPScan database
wpscan --update

# Scan WordPress installation
SCAN_RESULTS=$(wpscan --url "$(wp option get siteurl)" \
    --format json \
    --random-user-agent \
    --disable-tls-checks)

# Parse vulnerabilities
VULN_COUNT=$(echo "$SCAN_RESULTS" | jq '.plugins | to_entries[] | select(.value.vulnerabilities | length > 0) | .value.vulnerabilities | length' | awk '{s+=$1} END {print s}')

if [ "$VULN_COUNT" -gt 0 ]; then
    echo "✗ ALERT: $VULN_COUNT vulnerabilities detected"

    # Generate detailed report
    echo "$SCAN_RESULTS" | jq -r '.plugins | to_entries[] | select(.value.vulnerabilities | length > 0) | "Plugin: \(.key)\nVulnerabilities:\n\(.value.vulnerabilities[] | "  - \(.title) (Severity: \(.vuln_type))\n    Fixed in: \(.fixed_in // "No fix available")\n")"'

else
    echo "✓ No known vulnerabilities detected"
fi

Check Plugin Updates for Security Fixes

#!/bin/bash
# check-security-updates.sh

echo "Checking for security updates..."

# Get plugins with available updates
UPDATES=$(wp plugin list --update=available --format=json)

if [ "$UPDATES" != "[]" ]; then
    echo "Plugins with available updates:"
    echo "$UPDATES" | jq -r '.[] | "- \(.name) (Current: \(.version), Available: \(.update_version))"'

    # Check update changelogs for security keywords
    echo ""
    echo "Checking changelogs for security mentions..."

    echo "$UPDATES" | jq -r '.[].name' | while read PLUGIN; do
        CHANGELOG=$(wp plugin get "$PLUGIN" --field=update_changelog 2>/dev/null)

        if echo "$CHANGELOG" | grep -qi 'security\|vulnerability\|xss\|sql injection\|exploit'; then
            echo "⚠ SECURITY UPDATE AVAILABLE: $PLUGIN"
            echo "  Update immediately using: wp plugin update $PLUGIN"
        fi
    done
else
    echo "✓ All plugins up to date"
fi

Learn about WordPress security best practices.

File Change Monitoring

Detect unauthorized file modifications.

File Integrity Database

#!/bin/bash
# create-file-baseline.sh - Create baseline of file checksums

BASELINE_FILE="/var/backups/wp-file-baseline.txt"
WP_PATH="/var/www/html"

echo "Creating file integrity baseline..."

cd "$WP_PATH"

# Generate checksums for all WordPress files
find . -type f \
    -not -path "./wp-content/uploads/*" \
    -not -path "./wp-content/cache/*" \
    -not -path "./wp-content/backup/*" \
    -exec md5sum {} \; | sort > "$BASELINE_FILE"

echo "✓ Baseline created: $BASELINE_FILE"
echo "Total files: $(wc -l < $BASELINE_FILE)"

Detect File Changes

#!/bin/bash
# detect-file-changes.sh

BASELINE_FILE="/var/backups/wp-file-baseline.txt"
WP_PATH="/var/www/html"
REPORT_FILE="/tmp/file-changes-$(date +%Y%m%d).txt"

if [ ! -f "$BASELINE_FILE" ]; then
    echo "ERROR: Baseline file not found. Run create-file-baseline.sh first."
    exit 1
fi

echo "Scanning for file changes..."

cd "$WP_PATH"

# Generate current checksums
find . -type f \
    -not -path "./wp-content/uploads/*" \
    -not -path "./wp-content/cache/*" \
    -not -path "./wp-content/backup/*" \
    -exec md5sum {} \; | sort > /tmp/current-checksums.txt

# Compare with baseline
{
    echo "WordPress File Change Report"
    echo "============================="
    echo "Date: $(date)"
    echo ""

    # Modified files
    echo "Modified Files:"
    comm -13 "$BASELINE_FILE" /tmp/current-checksums.txt | awk '{print $2}' | while read file; do
        if grep -q "$file" "$BASELINE_FILE"; then
            echo "  MODIFIED: $file"
        fi
    done

    echo ""

    # New files
    echo "New Files:"
    comm -13 "$BASELINE_FILE" /tmp/current-checksums.txt | awk '{print $2}' | while read file; do
        if ! grep -q "$file" "$BASELINE_FILE"; then
            echo "  ADDED: $file"
        fi
    done

    echo ""

    # Deleted files
    echo "Deleted Files:"
    comm -23 "$BASELINE_FILE" /tmp/current-checksums.txt | awk '{print $2}' | while read file; do
        echo "  DELETED: $file"
    done

} > "$REPORT_FILE"

# Check if changes detected
CHANGE_COUNT=$(cat "$REPORT_FILE" | grep -c "MODIFIED:\|ADDED:\|DELETED:")

if [ "$CHANGE_COUNT" -gt 0 ]; then
    echo "✗ ALERT: $CHANGE_COUNT file changes detected"
    echo "Report: $REPORT_FILE"

    # Email report
    mail -s "WordPress File Changes Detected" admin@example.com < "$REPORT_FILE"
else
    echo "✓ No file changes detected"
fi

# Cleanup
rm /tmp/current-checksums.txt

Malware Pattern Scanning

Detect common malware patterns in WordPress files.

Basic Malware Scanner

#!/bin/bash
# scan-malware.sh - Detect common malware patterns

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

echo "WordPress Malware Scan"
echo "======================"

# Suspicious patterns to check
declare -a PATTERNS=(
    "eval(base64_decode"
    "eval(gzinflate"
    "eval(str_rot13"
    "system(\$_"
    "shell_exec"
    "passthru"
    "base64_decode.*eval"
    "FilesMan"
    "r57shell"
    "c99shell"
    "WSO shell"
)

{
    echo "Malware Scan Report"
    echo "==================="
    echo "Date: $(date)"
    echo "Path: $WP_PATH"
    echo ""

    for PATTERN in "${PATTERNS[@]}"; do
        echo "Checking for: $PATTERN"

        MATCHES=$(grep -r -l -i "$PATTERN" "$WP_PATH" \
            --exclude-dir=wp-content/uploads \
            --exclude-dir=wp-content/cache \
            --exclude-dir=node_modules \
            --include="*.php" 2>/dev/null)

        if [ ! -z "$MATCHES" ]; then
            echo "✗ SUSPICIOUS: Files matching '$PATTERN':"
            echo "$MATCHES" | while read file; do
                echo "  - $file"
            done
            echo ""
        fi
    done

} > "$REPORT_FILE"

# Check if suspicious files found
SUSPICIOUS_COUNT=$(grep -c "✗ SUSPICIOUS:" "$REPORT_FILE" || echo 0)

if [ "$SUSPICIOUS_COUNT" -gt 0 ]; then
    echo "✗ ALERT: Potential malware detected"
    echo "Report: $REPORT_FILE"

    # Send alert
    mail -s "URGENT: Potential Malware Detected" security@example.com < "$REPORT_FILE"
else
    echo "✓ No malware patterns detected"
fi

Check for Suspicious Files

#!/bin/bash
# check-suspicious-files.sh

WP_PATH="/var/www/html"

echo "Checking for suspicious files..."

# Check for unusual file types in wp-content
echo "Checking for executable files in wp-content..."
find "$WP_PATH/wp-content" \
    -type f \
    \( -name "*.exe" -o -name "*.sh" -o -name "*.bat" \) \
    -print

# Check for PHP files in uploads directory
echo "Checking for PHP files in uploads..."
find "$WP_PATH/wp-content/uploads" -name "*.php" -print

# Check for recently modified files (last 24 hours)
echo "Recently modified PHP files (last 24 hours)..."
find "$WP_PATH" -name "*.php" -mtime -1 -type f -print

# Check for files with suspicious permissions
echo "Files with 777 permissions..."
find "$WP_PATH" -type f -perm 0777 -print

Learn about WordPress malware detection.

User Account Security Auditing

Monitor user accounts for security issues.

User Security Audit

#!/bin/bash
# audit-users.sh

echo "WordPress User Security Audit"
echo "=============================="

# Check for users with admin privileges
echo "Administrator Accounts:"
wp user list --role=administrator --format=table --fields=ID,user_login,user_email,user_registered

ADMIN_COUNT=$(wp user list --role=administrator --format=count)
if [ "$ADMIN_COUNT" -gt 3 ]; then
    echo "⚠ WARNING: $ADMIN_COUNT administrator accounts (recommended: 1-2)"
fi

echo ""

# Check for weak usernames
echo "Checking for common/weak usernames..."
WEAK_USERS=("admin" "administrator" "root" "test" "demo")

for USERNAME in "${WEAK_USERS[@]}"; do
    if wp user get "$USERNAME" &>/dev/null; then
        echo "✗ WARNING: Common username detected: $USERNAME"
        echo "  Recommended: Delete or rename this account"
    fi
done

echo ""

# Check for inactive admin accounts
echo "Inactive Administrator Accounts (no posts/pages):"
wp user list --role=administrator --format=json | \
    jq -r '.[] | select(.posts == "0") | "- \(.user_login) (registered: \(.user_registered))"'

echo ""

# Check user capabilities
echo "Users with 'delete_users' capability:"
wp user list --format=json | \
    jq -r '.[] | select(.roles[] | contains("administrator")) | .user_login'

Password Policy Check

#!/bin/bash
# check-password-policy.sh

echo "Password Policy Check"
echo "===================="

# This requires custom code to check password strength
# WordPress doesn't expose password hashes via WP-CLI for security

# Check for recent password changes
echo "Users who haven't changed password recently:"
# This would require custom user meta tracking

# Check for 2FA status (if plugin installed)
if wp plugin is-installed two-factor; then
    echo "2FA Status:"
    wp user list --format=json | \
        jq -r '.[] | "\(.user_login): \(if .two_factor_enabled then "Enabled" else "DISABLED" end)"'
fi

# List users who can install plugins/themes
echo ""
echo "Users with plugin/theme installation privileges:"
wp user list --role=administrator,editor --format=csv --fields=user_login,roles

Comprehensive Security Report

Generate complete security assessment reports.

Master Security Script

#!/bin/bash
# comprehensive-security-check.sh

REPORT_FILE="/tmp/wordpress-security-report-$(date +%Y%m%d).txt"
LOG_FILE="/var/log/wp-security.log"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $@" | tee -a "$LOG_FILE"
}

{
    echo "WordPress Comprehensive Security Report"
    echo "========================================"
    echo "Generated: $(date)"
    echo "Server: $(hostname)"
    echo ""

    # Core integrity
    echo "1. Core File Integrity"
    echo "----------------------"
    if wp core verify-checksums; then
        echo "✓ PASS: Core files verified"
    else
        echo "✗ FAIL: Core file modifications detected"
    fi
    echo ""

    # Plugin security
    echo "2. Plugin Security"
    echo "------------------"
    PLUGIN_UPDATES=$(wp plugin list --update=available --format=count)
    echo "Plugins needing updates: $PLUGIN_UPDATES"

    if [ "$PLUGIN_UPDATES" -eq 0 ]; then
        echo "✓ PASS: All plugins up to date"
    else
        echo "⚠ WARNING: Plugin updates available"
        wp plugin list --update=available --format=table --fields=name,version,update_version
    fi
    echo ""

    # Theme security
    echo "3. Theme Security"
    echo "-----------------"
    THEME_UPDATES=$(wp theme list --update=available --format=count)
    echo "Themes needing updates: $THEME_UPDATES"
    echo ""

    # User accounts
    echo "4. User Account Security"
    echo "------------------------"
    ADMIN_COUNT=$(wp user list --role=administrator --format=count)
    echo "Administrator accounts: $ADMIN_COUNT"

    if [ "$ADMIN_COUNT" -gt 3 ]; then
        echo "⚠ WARNING: Too many administrator accounts"
    else
        echo "✓ PASS: Administrator count acceptable"
    fi
    echo ""

    # SSL/HTTPS check
    echo "5. SSL/HTTPS Configuration"
    echo "--------------------------"
    SITE_URL=$(wp option get siteurl)
    if [[ "$SITE_URL" == https://* ]]; then
        echo "✓ PASS: HTTPS enabled"
    else
        echo "✗ FAIL: Site not using HTTPS"
    fi
    echo ""

    # File permissions
    echo "6. File Permissions"
    echo "-------------------"
    INSECURE_FILES=$(find . -type f -perm 0777 | wc -l)
    echo "Files with 777 permissions: $INSECURE_FILES"

    if [ "$INSECURE_FILES" -eq 0 ]; then
        echo "✓ PASS: No files with overly permissive permissions"
    else
        echo "⚠ WARNING: Insecure file permissions detected"
    fi
    echo ""

    # WordPress version
    echo "7. WordPress Version"
    echo "--------------------"
    CURRENT_VERSION=$(wp core version)
    LATEST_VERSION=$(wp core check-update --format=json | jq -r '.[0].version // empty')

    echo "Current version: $CURRENT_VERSION"
    echo "Latest version: ${LATEST_VERSION:-$CURRENT_VERSION}"

    if [ -z "$LATEST_VERSION" ]; then
        echo "✓ PASS: WordPress is up to date"
    else
        echo "⚠ WARNING: WordPress update available"
    fi

} > "$REPORT_FILE"

log "Security report generated: $REPORT_FILE"

# Email report
mail -s "WordPress Security Report - $(hostname)" admin@example.com < "$REPORT_FILE"

echo "✓ Security report complete: $REPORT_FILE"

Automated Scheduling

Run security scans automatically with cron.

Cron Configuration

# Add to crontab: crontab -e

# Daily core integrity check at 2 AM
0 2 * * * /usr/local/bin/verify-core-integrity.sh >> /var/log/wp-security.log 2>&1

# Daily vulnerability scan at 3 AM
0 3 * * * /usr/local/bin/scan-vulnerabilities.sh >> /var/log/wp-security.log 2>&1

# Daily file change detection at 4 AM
0 4 * * * /usr/local/bin/detect-file-changes.sh >> /var/log/wp-security.log 2>&1

# Weekly comprehensive security report (Mondays at 8 AM)
0 8 * * 1 /usr/local/bin/comprehensive-security-check.sh

# Monthly user audit (first day of month)
0 9 1 * * /usr/local/bin/audit-users.sh | mail -s "Monthly User Audit" admin@example.com

Learn about WordPress security monitoring.

Next Steps

You now have automated WordPress security scanning and monitoring capabilities with WP-CLI.

Week 1: Core security

  • Implement core integrity checks
  • Set up vulnerability scanning
  • Test alerting systems

Week 2: File monitoring

  • Create file baselines
  • Configure change detection
  • Add malware scanning

Week 3: User security

  • Audit user accounts
  • Check permissions
  • Implement password policies

Week 4: Automation

  • Schedule all security checks
  • Configure comprehensive reports
  • Integrate with monitoring tools

Advanced Topics

  1. Intrusion Detection Systems – Advanced threat detection
  2. Security Information and Event Management (SIEM) – Centralized security monitoring
  3. Automated Incident Response – Automatic threat mitigation

Get More Resources

Download security scripts including:

  • Complete scanning system
  • Monitoring tools
  • Report templates

Join our email course for:

  • Weekly WP-CLI tutorials
  • Security best practices
  • Threat response strategies

Conclusion

Automated WordPress security scanning with WP-CLI provides continuous protection against vulnerabilities, malware, and unauthorized changes—detecting threats before they compromise your sites.

What we covered:

✅ Core file integrity verification
✅ Plugin and theme vulnerability detection
✅ File change monitoring and alerting
✅ Malware pattern scanning
✅ User account security auditing
✅ Comprehensive automated security reports

Implement these security automation systems, and you’ll detect threats immediately—protecting WordPress sites 24/7 without constant manual monitoring.

Ready for more? Learn incident response or WordPress hardening.

Questions about WordPress security automation? Drop a comment below!

Found this helpful? Share with other WordPress administrators.