1. Conduid
  2. Content
  3. Wp Malware Cleanup MCP
MCP server · Content

Wp Malware Cleanup MCP

MCP server for cleaning malware from WordPress sites via SSH and WP-CLI. Batch operations for 20+ sites.

Unclaimed MIT content
61Good

Scored 1 hours ago · breakdown

About Wp Malware Cleanup MCP

Wp Malware Cleanup MCP is an MCP server published by vapvarun in the Content category: mCP server for cleaning malware from WordPress sites via SSH and WP-CLI. Batch operations for 20+ sites.

The repository has 32 stars and 5 forks, with the last commit a month ago. Recent commit activity is the strongest signal that reported issues will get attention.

Install

From source
git clone https://github.com/vapvarun/wp-malware-cleanup-mcp

This server has no ConduID identity, so agent calls to it are not receipted. Pin the version you install and review the source before granting it credentials.

Tools (24)

wp_audit_userDetailed audit of user activity

Parameters not published.

wp_batch_scanScan all configured sites

Parameters not published.

wp_check_cron_eventsScan cron events for suspicious hooks

Parameters not published.

wp_export_sitesExport site configurations

Parameters not published.

wp_find_recent_usersFind users created recently

Parameters not published.

wp_fleet_statusFleet scorecard across all sites

Parameters not published.

wp_generate_case_studyGenerate anonymized case study

Parameters not published.

wp_generate_reportGenerate cleanup report

Parameters not published.

wp_get_siteGet site information

Parameters not published.

wp_host_group_statusOne account's sites + reinfection check

Parameters not published.

Show all 24 tools
wp_list_adminsList all administrator users

Parameters not published.

wp_list_scansList scan tasks

Parameters not published.

wp_list_sitesList all configured sites

Parameters not published.

wp_monitor_http_requestsMonitor outgoing HTTP requests

Parameters not published.

wp_read_fileRead file contents for analysis

Parameters not published.

wp_scanAll malware scans via one tool; `scope=` selects depth (quick/full/deep) or a category (uploads/webshells/themes/cron/wpconfig/…)

Parameters not published.

wp_scan_resultGet background scan results

Parameters not published.

wp_scan_statusCheck background scan status

Parameters not published.

wp_test_connectionTest SSH and WP-CLI connectivity

Parameters not published.

wp_threat_check_fileCheck file against threat database

Parameters not published.

wp_threat_db_statsShow threat database statistics

Parameters not published.

wp_threat_exportExport signatures

Parameters not published.

wp_threat_top_signaturesShow most detected signatures

Parameters not published.

wp_versionShow version information

Parameters not published.

Ask AI

✦

Ask AI about Wp Malware Cleanup MCP

Powered by Claude · Grounded in docs

I know everything about Wp Malware Cleanup MCP. Ask me about installation, configuration, usage, or troubleshooting.

Security checks

Static checks derived from the repository 1 hours ago. Heuristics on the source, not an audit.

  • ✓README presentThe repository ships documentation.
  • ✓License declaredUsable under a stated license.
  • ✓Tests presentA test suite exists in the repository.
  • ✓Dependencies pinnedA lockfile pins dependency versions.
  • !No dynamic code executionSource scan found eval or shell execution. Review how tool inputs reach it before granting credentials.
  • !Scoped permissionsDoesn't declare a permission scope. Assume it can do anything its process can.

Releases

v3.0.0v3.0.0
v1.0.0v1.0.0

README

WordPress Malware Cleanup MCP Server

Free and Open Source Python MCP WordPress Works with Claude

Last commit Open issues PRs welcome Stars

Find and remove WordPress malware - the whole kill chain, not just the visible shell - from a single site or an entire fleet, with an AI assistant that previews every change before it touches your server.

Free and open source (GPL), for any WordPress site owner: a solo blogger with one site, a freelancer cleaning up a client hack, or a host managing thousands of installs. You drive it in plain language through Claude; it does the SSH and WP-CLI work, shows you a preview, and never does anything irreversible without your confirmation and a backup.

By Wbcom Designs (Varun Dubey) · Ongoing threat research: WP Vanguard


Why this exists

Most scanners grep for known signatures and call a site "clean." Real WordPress infections do not work that way - they reinfect. They leave a fake mu-plugin that re-drops the payload, a rogue admin, a cron job, a poisoned .htaccess, an SSH key, a zero-byte decoy a signature scan cannot even see. Delete the visible shell and it is back within the hour.

This tool hunts the entire persistence chain and removes it safely:

  • Finds what signature scanners miss - zero-byte decoys, drop-in backdoors (object-cache.php / db.php), DB-payload options, cron-guard hooks, theme functions.php injections, rogue admin accounts, SSH-key backdoors, and UA-cloak .htaccess rules.
  • Safe by construction - scans are read-only by default; every destructive action shows a preview manifest and requires confirm=True; deletions quarantine first (recoverable) and refuse to run without a recent backup.
  • Works anywhere - one site or a whole fleet, cPanel or Plesk or plain SSH, over your existing SSH and WP-CLI. Nothing to install on the infected site.

Proven on a real fleet

The SC/SCOCV drop-in backdoor case study documents a live cleanup of a self-reinfecting backdoor family across a 22-account cPanel server: the reinfection vectors, the detection gaps that let it survive earlier cleanups, and how each layer was removed. More write-ups live in docs/case-studies, with new threat research published at WP Vanguard.


How to use it (in plain English)

You do not write code or run commands. Install the server once, then just talk to Claude in plain language - it does the SSH and WP-CLI work and shows you a preview before it changes anything.

1. Install it once (about 5 minutes - see Installation).

2. Add your site so Claude knows how to reach it. Tell it something like:

"Add my site example.com - SSH host 203.0.113.10, port 22, user bob, WordPress at /home/bob/public_html, using my SSH key."

3. Ask for what you need, in plain English. For example:

"Scan example.com for malware and show me what you find." "My site got hacked - find the backdoors and clean it up." "Check all my sites and tell me which ones are infected." "Reset the admin passwords on example.com and remove any rogue admin accounts." "Harden example.com, but keep automatic plugin updates working."

4. Review the preview, then confirm. Scans are always read-only. Anything destructive (deleting files, resetting passwords, replacing core) shows you exactly what it will do and waits for your go-ahead, and it refuses to run irreversible steps without a recent backup.

That is the whole loop: ask, preview, confirm, re-scan. New to it? Start with Your First Scan or the task-by-task Usage Guide.


SAFETY: This tool performs irreversible operations on live sites (file deletion, database modification, password resets, core replacement). Always take a full backup first. Destructive tools require confirm=True and show a preview manifest before running. See the Tool Risk Matrix. The authors are not liable for data loss.

New here? The Usage Guide walks the backup → preview → execute → re-scan workflow task by task. Hosts and agencies: the Wiki has setup guides, daily-scan automation, and the fleet playbook.

Table of Contents


Before You Start

Before using any cleanup or hardening tools on a live WordPress site:

  1. Create a full server backup (files + database). Use your hosting provider's backup tool or:

    wp_backup_database("site-name")
    

    A database backup alone is not sufficient - back up the entire wp-content/ directory as well.

  2. Test on staging first if possible. Clone the infected site to a staging environment and run cleanup there before touching production.

  3. Keep an SSH session open to monitor the server during cleanup. Watch for errors or unexpected behavior.

  4. Note current admin passwords before running wp_reset_passwords. After reset, the old passwords are gone permanently.

  5. Destructive tools require confirm=True. Tools like wp_reinstall_core, wp_reset_passwords, wp_complete_cleanup, etc. will show a preview manifest when called without confirm=True. Review the manifest before confirming.


Tool Risk Matrix

All tools are classified into three risk tiers:

SAFE (read-only)

These tools only read data. No files or database records are modified.

Tool Description
wp_scan All malware scans via one tool; scope= selects depth (quick/full/deep) or a category (uploads/webshells/themes/cron/wpconfig/…)
wp_fleet_status Fleet scorecard across all sites
wp_host_group_status One account's sites + reinfection check
wp_check_cron_events Scan cron events for suspicious hooks
wp_list_admins List all administrator users
wp_audit_user Detailed audit of user activity
wp_find_recent_users Find users created recently
wp_list_sites List all configured sites
wp_get_site Get site information
wp_test_connection Test SSH and WP-CLI connectivity
wp_read_file Read file contents for analysis
wp_version Show version information
wp_export_sites Export site configurations
wp_generate_report Generate cleanup report
wp_generate_case_study Generate anonymized case study
wp_batch_scan Scan all configured sites
wp_scan_status Check background scan status
wp_scan_result Get background scan results
wp_list_scans List scan tasks
wp_threat_db_stats Show threat database statistics
wp_threat_check_file Check file against threat database
wp_threat_top_signatures Show most detected signatures
wp_threat_export Export signatures
wp_monitor_http_requests Monitor outgoing HTTP requests

MODERATE (reversible changes)

These tools make changes that can be undone or automatically create backups.

Tool Description
wp_backup_database Create database backup
wp_quarantine_file Move file to quarantine (recoverable)
wp_add_site Add a site to configuration
wp_update_site Update site configuration
wp_remove_site Remove site from configuration
wp_harden_wpconfig Add security constants to wp-config.php
wp_add_security_htaccess Add security rules to .htaccess
wp_install_security_mu_plugin Install security MU-plugin
wp_fix_permissions Set secure file permissions
wp_disable_file_editing Disable theme/plugin editor
wp_threat_db_sync Sync community threat signatures
wp_threat_add_signature Add malware signature to local DB
wp_threat_learn_from_cleanup Record malware hash for future detection
wp_start_background_scan Start background scan task

DESTRUCTIVE (irreversible - requires confirm=True)

These tools permanently delete files, reset credentials, or overwrite data. Always create a backup first. Tools marked with confirm will show a preview manifest when called without confirm=True.

Tool confirm gate Description
wp_complete_cleanup Yes Full cleanup + hardening (20 destructive steps)
wp_reinstall_core Yes Overwrite wp-admin/, wp-includes/, root PHP files
wp_reinstall_all_plugins Yes Reinstall all plugins from WordPress.org
wp_reinstall_all_themes Yes Reinstall all themes from WordPress.org
wp_reset_passwords Yes Reset all administrator passwords
wp_regenerate_salts Yes Replace security salts, invalidate all sessions
wp_revoke_app_passwords Yes Delete all application passwords
wp_reinstall_plugin Yes (since 2.1.0) Reinstall a single plugin from repo
wp_delete_user Yes Delete a WordPress user
wp_clean_uploads_php Yes Remove all PHP files from uploads
wp_clean_core_injections Yes (since 2.1.0) Delete injected core files (also supports dry_run=True)
wp_clean_db_spam Yes Remove spam comments
wp_delete_malware_options Yes (since 2.1.0) Delete malware markers from wp_options (also supports dry_run=True)
wp_remove_mu_plugin Yes (since 2.1.0) Quarantine an mu-plugin
wp_update_all - Update core, plugins, themes
wp_batch_update - Update all clean sites
wp_full_harden - Complete hardening in one command

Features

Multi-Site Management

  • Add and manage 20+ WordPress sites from a single interface
  • Persistent configuration storage
  • Batch operations across all sites
  • Status tracking and reporting

Comprehensive Malware Scanning

  • Core File Verification - Compare against official WordPress checksums
  • Plugin Integrity Check - Verify plugins against WordPress.org
  • Known-Vulnerable Plugin Detection - Flag outdated plugins with known CVEs (e.g. the WP File Manager RCE) by version
  • File-Manager Plugin Policy - Flag any file-manager-class plugin for removal on sight (a common RCE entry vector, no visitor value)
  • MU-Plugins Detection - Scan must-use plugins for backdoors, including zero-byte decoys
  • Uploads Security - Find PHP files and time-stamped webshells that should not exist
  • Deep Pattern Matching - Detect obfuscated code and known signatures
  • Database Injection Scan - Find malicious content in posts/options (aborts loudly rather than reporting "clean" over an unreachable DB)

Persistence and reinfection vectors that signature scanners miss:

  • SC/SCOCV drop-in backdoors - obfuscated object-cache.php / db.php / advanced-cache.php, hidden .sc_* directories, DB-payload options, cron-guard hooks, theme functions.php injection, and self-reinfecting mu-plugins, in one dedicated tool
  • Rogue admin accounts - the SC/wp2shell/mail-daemon naming families, aligned across scan and clean
  • SSH-key backdoors - flags unlabeled or forced-command keys in ~/.ssh/authorized_keys (survives every file/DB cleanup)
  • UA-cloak .htaccess - the "Block for Chrome" / #KH..YS marker rules, including at the site root
  • Recently Modified Files - identify the infection timeline

User Security

  • List and audit administrator accounts
  • Track user activity before deletion
  • Find recently created suspicious users
  • Safe user deletion with content reassignment

Safe Cleanup Operations

  • Quarantine System - Move files instead of deleting (allows recovery)
  • Automatic Backups - Database export before changes
  • Core Reinstallation - Restore official WordPress files
  • Plugin Reinstallation - Fresh install from repository
  • Permission Fixes - Set secure file permissions

Security Hardening

  • Reset all admin passwords
  • Regenerate security salts
  • Disable admin file editing
  • Add .htaccess security rules
  • Update WordPress, plugins, and themes

Reporting & Logging

  • Detailed cleanup reports
  • Action logging per site
  • Export configurations
  • Status summaries

Requirements

Your Mac (Client)

WordPress Servers

  • SSH access (password or key-based)
  • WP-CLI installed and in PATH
  • WordPress 5.0+

macOS Setup Guide

Complete setup from scratch on a fresh Mac. Takes ~5 minutes.

Prerequisites

  • Homebrew installed
  • Claude Code CLI installed
  • uv installed (curl -LsSf https://astral.sh/uv/install.sh | sh)

Step 1: Install System Dependencies

# Python 3.12 (macOS system Python is too old for the mcp package)
brew install python@3.12

# sshpass (required for password-based SSH auth)
brew install sshpass

Step 2: Clone the Repository

git clone https://github.com/vapvarun/wp-malware-cleanup-mcp.git ~/.claude/wp-malware-cleanup-mcp
cd ~/.claude/wp-malware-cleanup-mcp

Step 3: Create Virtual Environment & Install Dependencies

# Create venv with Python 3.12
uv venv --python 3.12 .venv

# Install dependencies into venv
uv pip install -r requirements.txt

Step 4: Register MCP Server with Claude Code

# Register globally (available in all Claude Code sessions)
claude mcp add -s user wp-malware-cleanup -- \
  ~/.claude/wp-malware-cleanup-mcp/.venv/bin/python \
  ~/.claude/wp-malware-cleanup-mcp/server.py

Step 5: Verify

claude mcp list
# Should show: wp-malware-cleanup: ... ✓ Connected

Step 6: Restart Claude Code

Close and reopen Claude Code so the new MCP tools are loaded.


Configuration

Claude Code (Recommended)

The claude mcp add command in Step 4 automatically writes to ~/.claude.json:

{
  "mcpServers": {
    "wp-malware-cleanup": {
      "command": "/Users/YOU/.claude/wp-malware-cleanup-mcp/.venv/bin/python",
      "args": ["/Users/YOU/.claude/wp-malware-cleanup-mcp/server.py"]
    }
  }
}

Claude Desktop (Optional)

Add to ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "wp-malware-cleanup": {
      "command": "/Users/YOU/.claude/wp-malware-cleanup-mcp/.venv/bin/python",
      "args": ["/Users/YOU/.claude/wp-malware-cleanup-mcp/server.py"]
    }
  }
}

Note: Replace /Users/YOU with your actual home directory path.

Data Storage Locations

~/.wp-sites/
└── sites.json          # Site configurations (shared with wp-site-doctor-mcp)

~/.wp-malware-cleanup/
├── sites.json          # Legacy copy (kept in sync for backward compatibility)
├── quarantine/         # Quarantined malicious files
├── reports/            # Generated cleanup reports
├── scans/              # Persisted scan results, one JSON per run (since 2.2.0)
│   └── <site>/<scan_id>.json
├── logs/               # Per-site action logs
└── threat_intelligence.db  # Local threat intel SQLite DB

Site configurations live at ~/.wp-sites/sites.json so both this MCP and wp-site-doctor-mcp see the same sites. A copy is also written to the legacy location so any existing tooling that reads the old path keeps working.

The shared registry is read tolerantly (since 2.2.0): unknown keys written by another MCP are ignored rather than crashing the loader, so the two servers can evolve their own fields without corrupting the shared file.

Every whole-site wp_scan run (quick/full/deep) also writes a structured result record to ~/.wp-malware-cleanup/scans/<site>/, so scan history is queryable and can be diffed before/after a cleanup.


Quick Start

After setup, restart Claude Code and use these tools in conversation:

1. Add Your First Site

With password auth (common for InstaWP, managed hosting):

wp_add_site(
    name="my-site",
    host="147.182.198.163",
    username="sshuser",
    wp_path="/home/sshuser/web/example.com",
    auth_type="password",
    site_url="https://example.com"
)

With SSH key auth (recommended for production):

wp_add_site(
    name="client-blog",
    host="example.com",
    username="deploy",
    wp_path="/var/www/html",
    auth_type="key",
    key_path="~/.ssh/id_rsa"
)

Grouping sites that share a server / cPanel account (host_group):

# Two sites under the same cPanel user - group them so cross-site reinfection
# can be reasoned about. host_group defaults to `host` when omitted.
wp_add_site(name="shop-acme", host="srv12.host.net", username="acme",
            wp_path="/home/acme/shop", auth_type="key", host_group="acme")
wp_add_site(name="blog-acme", host="srv12.host.net", username="acme",
            wp_path="/home/acme/blog", auth_type="key", host_group="acme")

On shared hosting, one infected site commonly reinfects its siblings under the same account. Setting a shared host_group records that relationship for fleet-wide reasoning. Update it any time with wp_update_site("blog-acme", host_group="acme").

2. Test the Connection

# Password auth - provide password each time (not stored on disk for security)
wp_test_connection("my-site", password="your-ssh-password")

# Key auth - no password needed
wp_test_connection("client-blog")

Security note: Passwords are never stored on disk. They are passed via the SSHPASS environment variable at runtime and discarded after the SSH session ends.

3. Run a Full Scan

wp_scan("my-site", password="your-ssh-password")

4. View All Sites

wp_list_sites()

5. See the Whole Fleet at a Glance

wp_fleet_status()                 # instant scorecard from the last stored scans
wp_fleet_status(refresh=True)     # quick-scan every site first, then report
wp_host_group_status("acme")      # one cPanel account + reinfection assessment

Available Tools

Site Management

Tool Description
wp_add_site Add a new WordPress site
wp_update_site Update site configuration
wp_get_site Get detailed site information
wp_list_sites List all sites with status
wp_remove_site Remove a site from configuration
wp_test_connection Test SSH and WP-CLI connectivity

Fleet (since 2.2.0)

Tool Description
wp_fleet_status At-a-glance scorecard across all sites, worst-first, with risk scores. Instant from stored scans; pass refresh=True to quick-scan the fleet first. Flags clean siblings of an infected site as AT RISK.
wp_host_group_status All sites in one server / cPanel account (host_group) plus a cross-site reinfection assessment and clean order.

Scanning - one tool, many scopes

All scans run through a single tool, wp_scan(name, scope="full"). Pick a scope for depth or a specific area; if unsure, use the default full.

wp_scan("my-site")                          # full scan (default)
wp_scan("my-site", scope="quick")           # 2-3 min triage
wp_scan("my-site", scope="deep")            # most thorough, step-by-step
wp_scan("my-site", scope="uploads")         # one targeted category
scope Scans
quick Fast triage (core + key plugins + uploads)
full (default) All categories comprehensively
deep Full scan with step-by-step progress
verbose Full scan showing every command run
core WordPress core checksums
plugins Plugins vs WordPress.org
suspicious-plugins Random/malware-named plugin folders
hidden-plugins Self-hiding plugins
themes Malware themes
mu-plugins Must-use plugin malware
uploads Dangerous files in uploads
webshells Web shells / file-manager backdoors
hidden-admins Suspicious admin accounts
app-passwords Suspicious application passwords
malware-patterns Malware signature patterns
recently-modified Recently changed files
db Database injection check
cron Suspicious wp-cron events
wpconfig wp-config.php injection (read-only)

Whole-site scopes (quick/full/deep/verbose) persist a result for the fleet scorecard (wp_fleet_status); targeted scopes report without changing the site's overall verdict.

User Audit Tools

Tool Description
wp_list_admins List all administrator users
wp_audit_user Detailed audit of user activity
wp_find_recent_users Find users created recently
wp_delete_user Delete user after audit

Cleanup Tools

Tool Description
wp_complete_cleanup Full cleanup + hardening in one command (20 steps). Use without confirm for preview manifest.
wp_quarantine_file Move malicious file to quarantine (auto-learns hash)
wp_read_file Read file contents for analysis
wp_remove_mu_plugin Quarantine an mu-plugin
wp_reinstall_core Reinstall WordPress core files
wp_reinstall_plugin Reinstall a plugin from repo
wp_clean_uploads_php Remove all PHP from uploads
wp_clean_core_injections Delete injected core files that wp core download --force misses
wp_clean_db_spam Delete spam/trash comments (backup-gated - see below)
wp_delete_malware_options Delete known malware campaign markers from wp_options (backup-gated)
wp_clean_cron_events Delete malicious wp-cron events (the #1 reinfection vector)
wp_clean_malicious_htaccess Quarantine hostile .htaccess/.user.ini in uploads/wp-content
wp_revoke_app_passwords Revoke all application passwords across all users
wp_fix_permissions Fix file/directory permissions

Backup gate (since 2.2.0). Tools that delete data they cannot restore - wp_clean_db_spam, wp_delete_malware_options - refuse to run unless a recent backup is found in the action log (within 30 minutes). Run wp_backup_database("site") first, or pass force=True to override when you accept the risk. Reversible tools (quarantine-based, like wp_quarantine_file and wp_clean_uploads_php) are not gated - their preview explains recovery.

Security Hardening

Tool Description
wp_reset_passwords Reset all admin passwords
wp_regenerate_salts Regenerate security salts
wp_disable_file_editing Disable theme/plugin editor
wp_harden_wpconfig Apply security constants to wp-config.php
wp_install_security_mu_plugin Install persistent security MU-plugin
wp_full_harden Complete hardening in one command
wp_update_all Update core, plugins, themes
wp_add_security_htaccess Add security rules to .htaccess

Database Tools

Tool Description
wp_scan (scope="db") Scan database for injected malware
wp_backup_database Create database backup
wp_clean_db_spam Remove spam comments

Batch Operations

Tool Description
wp_batch_scan Scan all configured sites
wp_batch_update Update all clean sites

Reporting

Tool Description
wp_generate_report Generate detailed cleanup report
wp_incident_report Client-facing incident report: timeline, IOCs, before/after, clean sign-off
wp_generate_case_study Generate anonymized case study for public sharing
wp_export_sites Export site configurations
wp_version Show version information

Case Studies

Anonymized malware case studies are available in docs/case-studies/. These document real-world infections with:

  • Detection signatures and IOCs
  • Code analysis and behavior
  • Remediation steps
  • Lessons learned

Threat Intelligence Database

Tool Description
wp_threat_db_stats Show database statistics (signatures, detections)
wp_threat_db_sync Sync with GitHub community signatures
wp_threat_add_signature Add new malware signature to local database
wp_threat_learn_from_cleanup Learn malware hash from cleanup for future detection
wp_threat_check_file Check specific file against threat database
wp_threat_export Export signatures for GitHub contribution
wp_threat_top_signatures Show most frequently detected signatures

Usage Examples

Adding Multiple Sites

# Site with SSH key
wp_add_site(
    name="site1",
    host="server1.example.com",
    username="deploy",
    wp_path="/var/www/site1",
    auth_type="key",
    key_path="~/.ssh/id_rsa"
)

# Site with different port
wp_add_site(
    name="site2",
    host="server2.example.com",
    port=2222,
    username="admin",
    wp_path="/home/admin/public_html",
    auth_type="key",
    key_path="~/.ssh/server2_key"
)

Batch Scanning All Sites

# Scan all sites
wp_batch_scan()

# Scan only pending sites
wp_batch_scan(status_filter="pending")

Complete Cleanup Workflow

# 1. Backup first!
wp_backup_database("infected-site")

# 2. Run full scan
wp_scan("infected-site")

# 3. Audit suspicious users
wp_list_admins("infected-site")
wp_audit_user("infected-site", "suspicious_user")

# 4. Delete malicious user
wp_delete_user("infected-site", "suspicious_user", "real_admin", confirm=True)

# 5. Clean malicious files
wp_clean_uploads_php("infected-site", confirm=True)
wp_remove_mu_plugin("infected-site", "malware.php")

# 6. Reinstall core and plugins (confirm=True required for destructive tools)
wp_reinstall_core("infected-site", confirm=True)

# 7. Harden security (confirm=True required)
wp_reset_passwords("infected-site", confirm=True)
wp_regenerate_salts("infected-site", confirm=True)
wp_disable_file_editing("infected-site")
wp_add_security_htaccess("infected-site")

# 8. Update everything
wp_update_all("infected-site")

# 9. Verify cleanup
wp_scan("infected-site")

# 10. Generate report
wp_generate_report("infected-site")

One-Command Cleanup (with preview)

# Preview what will happen (dry run - no changes made)
wp_complete_cleanup("infected-site")

# Review the manifest, then execute
wp_complete_cleanup("infected-site", confirm=True)

Cleanup Workflow

Phase 1: Assessment

  1. Backup Database

    wp_backup_database("site-name")
    
  2. Run Full Scan

    wp_scan("site-name")
    
  3. Check Recently Modified Files

    wp_scan("site-name", scope="recently-modified")
    

Phase 2: User Audit

  1. List Admin Users

    wp_list_admins("site-name")
    
  2. Find Recent Users

    wp_find_recent_users("site-name", days=30)
    
  3. Audit Suspicious Users

    wp_audit_user("site-name", "suspicious_username")
    
  4. Delete Malicious Users

    wp_delete_user("site-name", "hacker", "legitimate_admin", confirm=True)
    

Phase 3: File Cleanup

  1. Clean Uploads Directory

    wp_clean_uploads_php("site-name", confirm=True)
    
  2. Remove Malicious MU-Plugins

    wp_scan("site-name", scope="mu-plugins")
    wp_remove_mu_plugin("site-name", "malware.php")
    
  3. Quarantine Suspicious Files

    wp_quarantine_file("site-name", "/full/path/to/file.php")
    

Phase 4: Core Restoration

  1. Reinstall WordPress Core (preview first, then confirm)

    wp_reinstall_core("site-name")              # Preview manifest
    wp_reinstall_core("site-name", confirm=True) # Execute
    
  2. Verify Core Files

    wp_scan("site-name", scope="core")
    
  3. Reinstall Affected Plugins

    wp_reinstall_plugin("site-name", "plugin-slug")
    

Phase 5: Security Hardening

  1. Reset All Passwords (preview first, then confirm)

    wp_reset_passwords("site-name")              # Preview affected users
    wp_reset_passwords("site-name", confirm=True) # Execute
    

    Save the new passwords securely!

  2. Regenerate Salts (preview first, then confirm)

    wp_regenerate_salts("site-name")              # Preview
    wp_regenerate_salts("site-name", confirm=True) # Execute
    
  3. Disable File Editing

    wp_disable_file_editing("site-name")
    
  4. Add Security Rules

    wp_add_security_htaccess("site-name")
    
  5. Fix Permissions

    wp_fix_permissions("site-name")
    

Phase 6: Updates & Verification

  1. Update Everything

    wp_update_all("site-name")
    
  2. Final Verification Scan

    wp_scan("site-name")
    
  3. Generate Report

    wp_generate_report("site-name")
    

Security Considerations

SSH Key Authentication (Recommended)

Always use SSH keys instead of passwords:

# Generate SSH key
ssh-keygen -t ed25519 -C "malware-cleanup"

# Copy to server
ssh-copy-id -i ~/.ssh/id_ed25519 user@server

Data Storage Security

  • Site configurations are stored locally in ~/.wp-sites/sites.json (shared with wp-site-doctor-mcp) and mirrored to ~/.wp-malware-cleanup/sites.json for backward compatibility.
  • Passwords are NEVER stored - provide them at runtime via the tool's password parameter; they pass through as an env var to sshpass, never appearing on the command line.
  • Database credentials never appear in ps - tools that need to run SQL go through WpConfigService.run_query(), which delegates to WP-CLI's wp db query. Credentials stay inside the WP-CLI process. Fixed in 2.1.0.
  • Quarantined files are kept on the remote server under wp-content/quarantine/. Originals are renamed with a timestamp + hash for traceability.
  • Reports may contain sensitive information - store securely.

Principle of Least Privilege

  • Use a dedicated SSH user for cleanup operations
  • Grant only necessary permissions
  • Consider using sudo for specific WP-CLI commands

Audit Trail

All actions are logged to ~/.wp-malware-cleanup/logs/{site-name}.log


Troubleshooting

"Connection refused" or "Connection timed out"

  1. Verify the hostname and port are correct
  2. Check if SSH is running on the server
  3. Verify firewall allows SSH connections
  4. Test manually: ssh -p PORT user@host

"WP-CLI not found"

Install WP-CLI on the WordPress server:

curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp

"Permission denied"

  1. Check SSH key permissions: chmod 600 ~/.ssh/id_rsa
  2. Verify the user has access to the WordPress directory
  3. Check if the user can run WP-CLI: wp --info

"sshpass not found"

If using password authentication:

  • Ubuntu/Debian: sudo apt install sshpass
  • macOS: brew install hudochenkov/sshpass/sshpass
  • Recommended: Use SSH keys instead

Command Timeout

For large sites, increase the timeout:

  • Database exports may take longer
  • Full scans on large sites need more time
  • Consider running scans during low-traffic periods

False Positives in Malware Scan

Some legitimate code may trigger false positives:

  • Base64 encoding in plugins (e.g., for image handling)
  • Minified JavaScript
  • Vendor libraries

Review each finding manually before taking action.


Threat Intelligence & Auto-Learning

This project includes a threat intelligence database that automatically learns from every cleanup. No manual steps required - every scan and cleanup action feeds data back into the local DB.

Auto-Learning Pipeline

Every detection and cleanup action is automatically recorded to the threat database:

Action What Gets Recorded
Quarantine a file File hash + path + auto-added to known_malicious_files for cross-site recognition
Scan finds hidden plugin Plugin slug + risk flags (self-hiding, user-hiding, self-healing)
Scan finds malware theme Theme slug + detection reasons (timestamp name, webshells, wp-config.php)
Delete injected core file File path of each removed injection
Delete malware DB option Option name + value that was removed
Revoke app passwords User ID + username for each revocation
Complete cleanup Summary with total steps completed
MU-plugin user-hiding detected Filenames of MU-plugins with user-hiding hooks

This means:

  • Quarantined file hashes are stored in known_malicious_files and can be matched against any file with wp_threat_check_file("site", "/path/to/file"), including on a different site.
  • Learned and community signatures feed the scanner. Since 2.7.0, wp_scan(scope="malware-patterns") (and the full scan) greps every active threat-DB signature across the site - so a signature learned while cleaning site A detects on site B. String signatures match literally; regex signatures use PCRE.
  • cleanup_records builds a searchable history of every action across all sites
  • All recording is best-effort - a DB failure never blocks a cleanup operation

Community Database

Sync with community-contributed signatures and contribute back:

# Sync latest signatures from GitHub
wp_threat_db_sync()

# Check current database stats (includes cleanup_records count)
wp_threat_db_stats()

# After confirming malware, teach the system
wp_threat_learn_from_cleanup("/path/to/malware.php", "abc123hash", "backdoor", "Description")

# Export for contribution
wp_threat_export()

Community Files

File Description
community-signatures.json Malware detection patterns (50+ signatures)
community-hashes.json Known malicious file hashes

Security Features

  • Secure Random Filenames: All backup files, reports, and quarantine directories use cryptographically secure random names to prevent attackers from guessing file locations
  • Restricted Permissions: Quarantine and backup directories are created with 700 permissions
  • No Predictable Paths: File naming uses SHA256-based random tokens

Project Structure

Since v2.1.0 the codebase is split into a thin entry point plus three packages:

wp-malware-cleanup-mcp/
├── server.py                  # 60-line entry point: setup_logging() + import tools + mcp.run()
├── config.py                  # Config dataclass + every malware/cron/HTTP detection constant
├── models.py                  # SiteConfig, ScanResult, DatabaseCredentials, exception hierarchy
├── database_v2.py             # Threat-intel SQLite store (thread-safe, WAL)
├── threat_feeds_v2.py         # GitHub community-signature sync + pattern analysis
│
├── core/                      # Shared services - pure logic, no MCP coupling
│   ├── sites.py               #   SiteManager (mtime-cached, dual-write to shared registry)
│   ├── paths.py               #   WpPaths helpers (uploads_dir, plugins_dir, …)
│   ├── wpconfig.py            #   WpConfigService.get_db_credentials + run_query via WP-CLI
│   ├── safety.py              #   require_confirm(), safety_banner(), log_action()
│   ├── reports.py             #   ScanReport / CleanupReport markdown formatters
│   ├── orchestrator.py        #   Step / Orchestrator primitives for scan + cleanup pipelines
│   ├── threat_db.py           #   facade over database_v2 + threat_feeds_v2
│   └── legacy.py              #   compat shims for helpers still in transition
│
├── tools/                     # One module per tool category - each registers @mcp.tool()
│   ├── _registry.py           #   shared FastMCP instance
│   ├── sites.py               #   add/update/list/get/remove/test_connection  (6 tools)
│   ├── scanning.py            #   verify/scan_* + quick/deep/full scans       (17 tools)
│   ├── cleanup.py             #   quarantine/clean_*/complete_cleanup/backup  (8 tools)
│   ├── hardening.py           #   permissions/salts/wpconfig/mu-plugin/etc.   (7 tools)
│   ├── reinstall.py           #   core/plugin/all-plugins/all-themes          (4 tools)
│   ├── users.py               #   list_admins/audit/find/delete/reset/revoke  (6 tools)
│   ├── threat.py              #   wp_threat_* (db stats, sync, learn, …)      (13 tools)
│   ├── reporting.py           #   generate_report/case_study/export_sites     (3 tools)
│   ├── batch.py               #   batch_scan/batch_update/update_all          (3 tools)
│   ├── background.py          #   start_background_scan/status/result/list    (4 tools)
│   ├── misc.py                #   version/read_file/check_cron/monitor_http   (4 tools)
│   └── interactive_scans.py   #   internal worker for background scans
│
├── utils/                     # Low-level helpers
│   ├── ssh.py                 #   SSHConnectionPool (ControlMaster), run_ssh_command, run_wpcli
│   ├── validation.py          #   path-traversal defense, shell escaping, log redaction
│   └── progress.py            #   ProgressReporter, TaskManager, BackgroundTask
│
├── scripts/
│   ├── count_tools.py         #   walks the FastMCP registry; `--diff` checks tools-baseline.txt
│   └── tools-baseline.txt     #   frozen 75-tool roster; CI's parity check
│
└── tests/
    ├── conftest.py            #   MockSSH fixture + with_site fixture
    ├── test_sites.py          #   SiteManager (mtime-invalidation, dual-write, migration)
    ├── test_wpconfig.py       #   asserts DB password never appears on `mysql` command line
    ├── test_safety.py         #   confirm gate, backup warning, banner
    ├── test_confirm_gates.py  #   the four destructive tools that need confirm=True
    ├── test_scanning_integration.py  #   MockSSH-driven smoke tests for scanning tools
    └── …                      #   paths, reports, orchestrator, validation, models

Dependency rule (one-way): tools/ → core/ → utils/ → models/. Tools never import from server; server.py only knows about tools._registry.mcp and side-effect imports the tools package to trigger registration. This lets you add or rename tool modules without touching server.py.


Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes (with tests where it makes sense)
  4. Run make smoke && make parity && make test before submitting
  5. Submit a pull request

Contributing Signatures

To contribute malware signatures:

  1. Use wp_threat_export() to export your local signatures
  2. Fork this repository
  3. Add your signatures to community-signatures.json or community-hashes.json
  4. Submit a pull request with a description of what malware the signatures detect

Guidelines:

  • Only submit confirmed malware signatures
  • Include clear descriptions
  • Test for false positives before submitting
  • Do not include sensitive information

Development Setup

git clone https://github.com/vapvarun/wp-malware-cleanup-mcp.git
cd wp-malware-cleanup-mcp

# Create a venv (Python 3.10+) and install dev dependencies
python3.12 -m venv .venv
source .venv/bin/activate
make install         # equivalent to: pip install -e ".[dev]"

Adding a new tool

  1. Pick the right category module under tools/ (or create a new one - register it in tools/__init__.py so the side-effect import wires it up).
  2. Decorate with @mcp.tool() (import mcp from tools._registry).
  3. Use core.get_site_manager() for site lookups, core.WpPaths for path construction, and - for destructive tools - core.safety.require_confirm() for the confirm gate.
  4. Add the tool name to scripts/tools-baseline.txt (or regenerate the file).
  5. Add at least one integration test against the mock_ssh + with_site fixtures in tests/conftest.py.

Running tests / quality gates

make smoke     # python -c "import server"
make parity    # asserts tools/__init__ wires up exactly the 75 baseline tools
make test      # full pytest run (excludes the 6 known-pre-existing validation
               # failures tracked separately)
make test-all  # everything, including the known failures
make lint      # ruff check (config in pyproject.toml)

MockSSH (in tests/conftest.py) replaces utils.ssh.run_ssh_command and run_wpcli with a deterministic stub - register responses with mock_ssh.expect(substr_or_callable, (success, output)) and inspect issued commands via mock_ssh.calls. Integration tests for scanning/cleanup/threat tools should go through this fixture rather than hitting a real server.


License

This project is free software, licensed under the GNU General Public License v2.0 or later (GPL-2.0-or-later) - the same license as WordPress core. See the LICENSE file for the full text. You are free to use, study, share, and modify it; derivative works must remain under the GPL.


Credits

Author: Varun Dubey Company: Wbcom Designs

Built With

Acknowledgments

  • WordPress Security Team for security best practices
  • The WP-CLI community for the excellent command-line tool
  • Anthropic for the Model Context Protocol specification

Support

For support, questions, or custom development:


Changelog

Version 3.0.0 (2026)

A fleet-operations release that turns the per-site cleanup tool into a fleet incident-response console, plus a deep re-audit that fixed a large amount of functionality the 2.1.0 package-split refactor had shipped silently broken.

Breaking

  • Scan tools consolidated under wp_scan(name, scope="full"). The 17 separate scan tools (wp_full_scan, wp_quick_scan, wp_deep_scan, wp_scan_uploads, wp_scan_webshells, …) are removed as individual tools; scope selects depth (quick/full/deep/verbose) or a category (uploads, webshells, themes, core, plugins, hidden-admins, cron, wpconfig, db, …). Scripts calling the old tool names must switch to wp_scan(scope=...).
  • Removed 6 non-functional threat tools (wp_threat_sync_wpscan, wp_threat_sync_patchstack, wp_threat_sync_all, wp_threat_download_plugin_signatures, wp_threat_learn_from_plugins, wp_threat_report) - they called methods that did not exist and crashed at runtime, advertising external feeds the server could not fetch.

New - fleet console

  • wp_fleet_status - at-a-glance scorecard across all sites, worst-first, risk-scored. Instant from stored scans, or refresh=True to quick-scan first. Clean siblings of an infected site (same host_group) are flagged AT RISK.
  • wp_host_group_status - one server / cPanel account's sites plus a cross-site reinfection assessment and suggested clean order.
  • host_group on wp_add_site / wp_update_site to record which sites share an account.

New - incident response

  • wp_incident_report - client-facing "proof of clean": infection timeline, IOCs (path + hash), before/after comparison, and a clean sign-off when the latest whole-site scan is clean. Anonymized by default.
  • wp_clean_cron_events - delete malicious wp-cron hooks (the #1 reinfection vector).
  • wp_clean_malicious_htaccess - quarantine hostile .htaccess/.user.ini that re-enable PHP execution or redirect traffic.
  • wp_scan(scope="wpconfig") - read-only scan for injected code in wp-config.php (survives core reinstalls).
  • wp_complete_cleanup now removes cron + .htaccess, scans wp-config.php, then runs a post-cleanup verification scan and sets status from the result - it no longer reports "clean" unconditionally.

New - threat intelligence

  • The threat DB now feeds the scanner (it was write-only). wp_scan(scope="malware-patterns") greps every active signature - community-synced and learned-from-cleanup - so a signature learned cleaning one site detects on the next. (grep -F for strings, grep -P for regex, invalid patterns dropped, best-effort.)
  • Persistent scan results - every whole-site scan writes a structured record to ~/.wp-malware-cleanup/scans/<site>/ (capped at 200/site), enabling history and before/after diffs. Targeted scans are recorded but never set the fleet verdict.

Improve

  • Detection - web-shell detection requires ≥2 distinct file-manager indicators (cuts false positives from a lone scandir/is_writable); backup/migration plugins added to the false-positive paths; the obfuscation scan now also catches eval($var) and variable-function backdoors ($f($_GET[...])).
  • Safety - backup gate on irreversible data deletion (wp_clean_db_spam, wp_delete_malware_options) with a force=True override.
  • Resilience - the shared sites.json loader tolerates unknown keys instead of renaming the file to .bak, so it coexists with other MCPs.

Fix (refactor-orphaned silent failures)

  • wp_complete_cleanup was a near-no-op - it called ~14 functions never imported into its module; wrapped in try/except, every step failed silently. All imports fixed; a full-chain test now guards it.
  • wp_generate_report, wp_generate_case_study, wp_export_sites, wp_quick_scan, wp_deep_scan, wp_batch_scan, wp_threat_db_sync, wp_threat_export, and wp_full_scan steps all referenced names removed by the refactor and failed silently. Fixed and covered by a static undefined-name (F821) sweep and an execute-every-tool smoke test.
  • wp_audit_user crashed (UnboundLocalError) on a user with a missing registration date.
  • Case studies and reports were written into the installed package instead of the data dir.
  • Validation: validate_hostname rejects invalid IPv4; generate_secure_filename keeps the extension dot (backups were missing .sql); sanitize_filename returns unnamed for blank input.

Tools: 75 → 59. Tests: 152 passing, no skips.

Version 2.1.0 (2026)

  • Package-split refactor - server.py shrank from 8,176 to 60 lines; 75 tools moved into per-category modules under tools/ (sites, scanning, cleanup, hardening, reinstall, users, threat, reporting, batch, background, misc).
  • New core/ package - SiteManager, WpPaths, WpConfigService, require_confirm(), ScanReport, CleanupReport, threat DB facade, scan orchestrator.
  • Confirm gates added to wp_reinstall_plugin, wp_clean_core_injections, wp_delete_malware_options, wp_remove_mu_plugin. Each now requires confirm=True; without it they return a preview manifest.
  • DB-password leak fix - wp_scan_hidden_admins and wp_scan_app_passwords previously built mysql -u <user> -p<pass> commands visible in ps on the target. They now route through WP-CLI via WpConfigService.run_query(), keeping credentials inside the WP-CLI process.
  • v1 modules (database.py, threat_feeds.py) deleted; V2_MODULES_AVAILABLE branching removed; legacy fallback SSH impls removed.
  • pyproject.toml, Makefile, and MockSSH test fixture added. Test count: 75 (up from 33 unit tests in 2.0.0).

Version 2.0.0 (2026)

  • Auto-learning pipeline - every scan/cleanup action auto-records to threat DB
  • Cross-site hash recognition - quarantined files are auto-detected on other sites
  • SSH connection pooling and thread-safe DB connections
  • Signature caching with TTL and pre-compiled regex
  • New tools: wp_scan_hidden_plugins, wp_scan_themes, wp_clean_core_injections, wp_delete_malware_options, wp_revoke_app_passwords, wp_complete_cleanup, wp_scan_hidden_admins, wp_scan_app_passwords, wp_scan_webshells, wp_harden_wpconfig, wp_install_security_mu_plugin, wp_full_harden, wp_generate_case_study
  • GitHub community signature sync (wp_threat_db_sync)
  • Anonymized case study generation
  • v2 config, models, and utils modules

Version 1.0.0 (2024)

  • Initial release
  • Multi-site management
  • Comprehensive malware scanning
  • User audit capabilities
  • Safe cleanup operations
  • Security hardening tools
  • Batch operations
  • Detailed reporting

README fetched from the repository 1 hours ago. The original is authoritative.

Questions

About Wp Malware Cleanup MCP

How do I install Wp Malware Cleanup MCP?

No package has been published for this server, so install it from source: clone the repository and follow its README.

Is Wp Malware Cleanup MCP safe to use with an AI agent?

Its trust score is 61 out of 100 (good). It passes 4 of the 6 static security checks run so far; the failures are listed above. It has no ConduID identity yet, so agent calls to it are not receipted.

Is Wp Malware Cleanup MCP still maintained?

Yes — the last commit was a month ago. The repository has 32 stars and 5 forks and 1 open issues.