A production-ready Model Context Protocol (MCP) server for cleaning malware from WordPress sites via SSH and WP-CLI. Designed for agencies and developers managing multiple WordPress installations.
Author: Varun Dubey Company: Wbcom Designs Version: 2.0.0
IMPORTANT SAFETY NOTICE
This tool performs irreversible operations on live WordPress sites including file deletion, database modification, password resets, and core file replacement. Always create a full backup before using any cleanup tool. The authors are not liable for data loss. See the Tool Risk Matrix below.
Hosting companies and agencies: See the Wiki for setup guides, daily scan automation, and the hosting company playbook.
- Before You Start
- Tool Risk Matrix
- Features
- Requirements
- Installation
- Configuration
- Quick Start
- Available Tools
- Usage Examples
- Cleanup Workflow
- Security Considerations
- Troubleshooting
- Contributing
- License
- Credits
Before using any cleanup or hardening tools on a live WordPress site:
-
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. -
Test on staging first if possible. Clone the infected site to a staging environment and run cleanup there before touching production.
-
Keep an SSH session open to monitor the server during cleanup. Watch for errors or unexpected behavior.
-
Note current admin passwords before running
wp_reset_passwords. After reset, the old passwords are gone permanently. -
Destructive tools require
confirm=True. Tools likewp_reinstall_core,wp_reset_passwords,wp_complete_cleanup, etc. will show a preview manifest when called withoutconfirm=True. Review the manifest before confirming.
All tools are classified into three risk tiers:
These tools only read data. No files or database records are modified.
| Tool | Description |
|---|---|
wp_full_scan |
Run all scans comprehensively |
wp_full_scan_verbose |
Full scan with detailed output |
wp_quick_scan |
Quick scan |
wp_deep_scan |
Deep scan |
wp_verify_core |
Verify WordPress core file integrity |
wp_verify_plugins |
Check plugins against WordPress.org |
wp_scan_mu_plugins |
Scan must-use plugins for malware |
wp_scan_suspicious_plugins |
Detect plugins with random/malware-like names |
wp_scan_hidden_plugins |
Detect self-hiding plugins |
wp_scan_hidden_admins |
Find suspicious admin accounts |
wp_scan_app_passwords |
Detect suspicious application passwords |
wp_scan_webshells |
Detect file manager backdoors |
wp_scan_uploads |
Find dangerous files in uploads |
wp_scan_malware_patterns |
Deep scan for malware signatures |
wp_scan_recently_modified |
Find files changed in last N days |
wp_scan_themes |
Scan themes for malware |
wp_check_db_injections |
Scan database for malware |
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_report |
Generate threat intelligence report |
wp_threat_export |
Export signatures |
wp_monitor_http_requests |
Monitor outgoing HTTP requests |
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_threat_learn_from_plugins |
Learn plugin signatures |
wp_threat_sync_wpscan |
Sync WPScan feed |
wp_threat_sync_patchstack |
Sync Patchstack feed |
wp_threat_sync_all |
Sync all threat feeds |
wp_threat_download_plugin_signatures |
Download plugin signatures |
wp_start_background_scan |
Start background scan task |
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 (16 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 |
— | 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 |
— | Delete injected core files |
wp_clean_db_spam |
Yes | Remove spam comments |
wp_delete_malware_options |
— | Delete malware markers from wp_options |
wp_remove_mu_plugin |
— | 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 |
- Add and manage 20+ WordPress sites from a single interface
- Persistent configuration storage
- Batch operations across all sites
- Status tracking and reporting
- Core File Verification - Compare against official WordPress checksums
- Plugin Integrity Check - Verify plugins against WordPress.org
- MU-Plugins Detection - Scan must-use plugins for backdoors
- Uploads Security - Find PHP files that shouldn't exist
- Deep Pattern Matching - Detect obfuscated code and known signatures
- Database Injection Scan - Find malicious content in posts/options
- Recently Modified Files - Identify infection timeline
- List and audit administrator accounts
- Track user activity before deletion
- Find recently created suspicious users
- Safe user deletion with content reassignment
- 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
- Reset all admin passwords
- Regenerate security salts
- Disable admin file editing
- Add .htaccess security rules
- Update WordPress, plugins, and themes
- Detailed cleanup reports
- Action logging per site
- Export configurations
- Status summaries
- macOS 13+ (Ventura or later)
- Homebrew
- Claude Code CLI
- uv (Python package manager)
- SSH access (password or key-based)
- WP-CLI installed and in PATH
- WordPress 5.0+
Complete setup from scratch on a fresh Mac. Takes ~5 minutes.
- Homebrew installed
- Claude Code CLI installed
- uv installed (
curl -LsSf https://astral.sh/uv/install.sh | sh)
# 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 sshpassgit clone https://github.com/vapvarun/wp-malware-cleanup-mcp.git ~/.claude/wp-malware-cleanup-mcp
cd ~/.claude/wp-malware-cleanup-mcp# Create venv with Python 3.12
uv venv --python 3.12 .venv
# Install dependencies into venv
uv pip install -r requirements.txt# 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.pyclaude mcp list
# Should show: wp-malware-cleanup: ... ✓ ConnectedClose and reopen Claude Code so the new MCP tools are loaded.
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"]
}
}
}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/YOUwith your actual home directory path.
The server stores data in ~/.wp-malware-cleanup/:
~/.wp-malware-cleanup/
├── sites.json # Site configurations
├── quarantine/ # Quarantined malicious files
├── reports/ # Generated cleanup reports
└── logs/ # Per-site action logs
After setup, restart Claude Code and use these tools in conversation:
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"
)
# 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
SSHPASSenvironment variable at runtime and discarded after the SSH session ends.
wp_full_scan("my-site", password="your-ssh-password")
wp_list_sites()
| 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 |
| Tool | Description |
|---|---|
wp_verify_core |
Verify WordPress core file integrity |
wp_verify_plugins |
Check plugins against WordPress.org |
wp_scan_suspicious_plugins |
Detect plugins with random/malware-like folder names |
wp_scan_hidden_admins |
Find suspicious admin accounts (typosquatted emails, recent creation) |
wp_scan_app_passwords |
Detect suspicious WordPress application passwords |
wp_scan_webshells |
Detect file manager backdoors and web shells |
wp_scan_mu_plugins |
Scan must-use plugins for malware |
wp_scan_uploads |
Find dangerous files in uploads |
wp_scan_malware_patterns |
Deep scan for malware signatures |
wp_scan_recently_modified |
Find files changed in last N days |
wp_scan_hidden_plugins |
Detect self-hiding plugins (on disk but invisible to wp plugin list) |
wp_scan_themes |
Scan themes for malware — fake themes, timestamp-named dirs, webshells |
wp_full_scan |
Run all scans comprehensively |
wp_full_scan_verbose |
Full scan with detailed command-by-command output |
| 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 |
| Tool | Description |
|---|---|
wp_complete_cleanup |
Full cleanup + hardening in one command (16 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_delete_malware_options |
Delete known malware campaign markers from wp_options |
wp_revoke_app_passwords |
Revoke all application passwords across all users |
wp_fix_permissions |
Fix file/directory permissions |
| 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 |
| Tool | Description |
|---|---|
wp_check_db_injections |
Scan database for malware |
wp_backup_database |
Create database backup |
wp_clean_db_spam |
Remove spam comments |
| Tool | Description |
|---|---|
wp_batch_scan |
Scan all configured sites |
wp_batch_update |
Update all clean sites |
| Tool | Description |
|---|---|
wp_generate_report |
Generate detailed cleanup report |
wp_generate_case_study |
Generate anonymized case study for public sharing |
wp_export_sites |
Export site configurations |
wp_version |
Show version information |
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
| 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 |
wp_threat_report |
Generate threat intelligence report |
# 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"
)# Scan all sites
wp_batch_scan()
# Scan only pending sites
wp_batch_scan(status_filter="pending")# 1. Backup first!
wp_backup_database("infected-site")
# 2. Run full scan
wp_full_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_full_scan("infected-site")
# 10. Generate report
wp_generate_report("infected-site")# 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)-
Backup Database
wp_backup_database("site-name") -
Run Full Scan
wp_full_scan("site-name") -
Check Recently Modified Files
wp_scan_recently_modified("site-name", days=14)
-
List Admin Users
wp_list_admins("site-name") -
Find Recent Users
wp_find_recent_users("site-name", days=30) -
Audit Suspicious Users
wp_audit_user("site-name", "suspicious_username") -
Delete Malicious Users
wp_delete_user("site-name", "hacker", "legitimate_admin", confirm=True)
-
Clean Uploads Directory
wp_clean_uploads_php("site-name", confirm=True) -
Remove Malicious MU-Plugins
wp_scan_mu_plugins("site-name") wp_remove_mu_plugin("site-name", "malware.php") -
Quarantine Suspicious Files
wp_quarantine_file("site-name", "/full/path/to/file.php")
-
Reinstall WordPress Core (preview first, then confirm)
wp_reinstall_core("site-name") # Preview manifest wp_reinstall_core("site-name", confirm=True) # Execute -
Verify Core Files
wp_verify_core("site-name") -
Reinstall Affected Plugins
wp_reinstall_plugin("site-name", "plugin-slug")
-
Reset All Passwords (preview first, then confirm)
wp_reset_passwords("site-name") # Preview affected users wp_reset_passwords("site-name", confirm=True) # ExecuteSave the new passwords securely!
-
Regenerate Salts (preview first, then confirm)
wp_regenerate_salts("site-name") # Preview wp_regenerate_salts("site-name", confirm=True) # Execute -
Disable File Editing
wp_disable_file_editing("site-name") -
Add Security Rules
wp_add_security_htaccess("site-name") -
Fix Permissions
wp_fix_permissions("site-name")
-
Update Everything
wp_update_all("site-name") -
Final Verification Scan
wp_full_scan("site-name") -
Generate Report
wp_generate_report("site-name")
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- Site configurations are stored locally in
~/.wp-malware-cleanup/ - Passwords are NEVER stored - provide them at runtime
- Quarantined files are kept on the remote server
- Reports may contain sensitive information - store securely
- Use a dedicated SSH user for cleanup operations
- Grant only necessary permissions
- Consider using sudo for specific WP-CLI commands
All actions are logged to ~/.wp-malware-cleanup/logs/{site-name}.log
- Verify the hostname and port are correct
- Check if SSH is running on the server
- Verify firewall allows SSH connections
- Test manually:
ssh -p PORT user@host
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- Check SSH key permissions:
chmod 600 ~/.ssh/id_rsa - Verify the user has access to the WordPress directory
- Check if the user can run WP-CLI:
wp --info
If using password authentication:
- Ubuntu/Debian:
sudo apt install sshpass - macOS:
brew install hudochenkov/sshpass/sshpass - Recommended: Use SSH keys instead
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
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.
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.
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 files are auto-recognized if the same hash appears on another site
cleanup_recordsbuilds a searchable history of every action across all sites- All recording is best-effort — a DB failure never blocks a cleanup operation
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()| File | Description |
|---|---|
community-signatures.json |
Malware detection patterns (50+ signatures) |
community-hashes.json |
Known malicious file hashes |
- 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
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
To contribute malware signatures:
- Use
wp_threat_export()to export your local signatures - Fork this repository
- Add your signatures to
community-signatures.jsonorcommunity-hashes.json - 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
git clone https://github.com/vapvarun/wp-malware-cleanup-mcp.git
cd wp-malware-cleanup-mcp
pip install -e .python -m pytest tests/This project is licensed under the MIT License - see the LICENSE file for details.
Author: Varun Dubey Company: Wbcom Designs
- Model Context Protocol (MCP) - Protocol for LLM integrations
- WP-CLI - Command-line interface for WordPress
- FastMCP - Python MCP server framework
- WordPress Security Team for security best practices
- The WP-CLI community for the excellent command-line tool
- Anthropic for the Model Context Protocol specification
For support, questions, or custom development:
- Website: https://wbcomdesigns.com
- GitHub Issues: Report a bug
- 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 - Patchstack and WPScan feed integration
- Anonymized case study generation
- v2 config, models, and utils modules
- Initial release
- Multi-site management
- Comprehensive malware scanning
- User audit capabilities
- Safe cleanup operations
- Security hardening tools
- Batch operations
- Detailed reporting