WordPress Malware Removal
Audit, clean, and harden a WordPress site — end to end, with an AI agent.
Three things every WordPress owner needs, in one open-source tool:
- Audit — how hackable is your site right now? A read-only security posture score (vulnerable plugins, exposure, code risk, hardening state) with a ranked fix list.
- Remove — if it's already hacked, clean it — including the hidden stuff scanners miss (cloaking, web-root backdoors, database injections), safely, and find out how they got in.
- Harden — lock the doors so it doesn't happen again (2FA, permissions, REST/XML-RPC, and more) — applied safely, reversible.
It looks at your site the way Google and an attacker do — not just the way a browser does — cleans safely (it won't touch a thing until you've taken a backup, nothing deleted blind, auto-rollback if a change breaks the site), and always tells you how they got in.
Free · open-source (AGPL-3.0) · runs with any AI coding agent — Claude Code, Cursor, Codex, or any MCP client.
Install (30 seconds)
git clone https://github.com/adityaarsharma/wordpress-malware-removal.git
cd wordpress-malware-removal
./install.sh # installs all three skills into ~/.claude/skills
Options: ./install.sh --dir PATH (custom skills dir for Codex/Cursor/other), --skill wp-hardening
(install one), --list (preview), --uninstall. Re-run any time to update. Helper scripts need Python
3.8+ and have zero third-party dependencies.
This installs three self-contained, gateway-agnostic skills — each runs over any SSH+WP-CLI or any WordPress MCP (SproutOS recommended):
| Skill | Ask it | What it does |
|---|---|---|
| wp-security-audit | "How hackable is this site?" | Read-only A–F posture score: vulns + code + exposure + ranked fixes. Touches nothing. |
| wp-malware-removal | "This site is hacked — clean it" | 12-layer forensic scan → verify → quarantine-first removal → prove clean → entry vector. |
| wp-hardening | "Lock the doors" | Idempotent, reversible hardening — auto-applies safe fixes, asks before risky ones. |
Table of contents
- Install
- What it does
- Works with your AI agent
- How it compares
- How to use it
- Keeping it updated
- How it works (the 12-layer scan)
- Connecting your site (gateways)
- What it detects (38 families)
- Standalone scripts
- How it cleans safely
- Documentation
- FAQ
- A real example
- Contributing
- License
What it does — three modes
| Mode | When | What it does |
|---|---|---|
| Audit | "Am I safe?" | Read-only posture check → an A–F score + ranked fixes. Cross-checks your plugins/themes against known vulnerabilities, tests exposure (REST user-leaks, XML-RPC, public debug.log, security headers…), audits risky code, and reports hardening state. Weighted so credential hygiene (2FA) counts most — stolen logins are the #1 real breach vector. |
| Remove | "I'm hacked" | Deep-cleans malware — including the hidden stuff scanners miss: SEO-spam cloaking, the Japanese keyword hack, redirect malware, web-shells, and backdoors. Backs up first, quarantines instead of deleting, auto-rolls-back if a change breaks the site, and reconstructs how the attacker got in. |
| Harden | "Lock it down" | Applies hardening safely — the reversible, low-risk fixes automatically (file permissions, disable file editing, security headers, block PHP in uploads), and asks before anything that could break a plugin (XML-RPC off, REST restriction, 2FA enforcement). |
Not sure which you need? Run Audit first — it tells you whether to Remove, Harden, or relax.
Works with your AI agent
Not just Claude. This is designed to be agent-agnostic:
- The Python scripts run on their own — no AI needed. Scan, detect cloaking, verify core integrity, and check vulnerabilities straight from your terminal.
- The cleanup methodology works with any capable AI coding agent — Claude Code, Cursor, Codex, or anything that can read a project and run commands. Point your agent at this repo and ask it to scan or clean.
- It connects to your site over MCP (an open standard) or SSH — so any MCP-compatible client can drive it. SproutOS is the recommended gateway (no SSH needed).
- Claude Code gets the tightest fit — it loads this as a native skill, so a plain "scan my site" just works.
One tool, your choice of agent. Nothing here is locked to a single vendor.
How it compares
These are all good tools that do different things. The table describes each one's publicly documented approach — it's a comparison of design, not a claim that any product is better or worse. Run this alongside your existing security plugin; a second, independent look never hurts.
| Manual cleaning | Wordfence | MalCare | Sucuri | This tool | |
|---|---|---|---|---|---|
| What it is | Do-it-yourself | Security plugin | Plugin + cloud | Plugin + remote service | AI agent / Claude skill |
| Where it works | You, on the server | Inside WordPress | Synced copy on its cloud | Remote scan + cloud firewall | Over a connection or SSH — whole server |
| How it finds malware | Your own inspection | Signature matching | Behavioral signals | Signatures + remote checks | Reads each file in context |
| Looks at | Wherever you look | WordPress files & DB | WordPress files & DB | Public pages + files (with agent) | Whole server, DB, logs, users |
| Checks pages as Googlebot (spam shown only to Google) | Only if you know to | Scans files, not a crawler fetch | Scans files on its cloud | Remote scanner reads public pages | Yes — as Googlebot & at the origin |
Scans outside wp-content |
If you check there | WordPress-focused | WordPress-focused | Public URLs; server scan via agent | Yes — web root and above |
| Explains how the site was hacked | Only if you dig through logs | Live traffic / login logging | Activity-log add-on | Post-hack analysis (paid) | Built-in log forensics + free vuln check |
| Reduces false alarms | Depends on your skill | Pattern rules | Signal scoring | Signature rules | Reads each file before flagging |
| Risk of breaking the site | High — easy to delete the wrong file | Low–medium | Low | Low | Low — backup, quarantine, auto-rollback |
| Skill required | High | Low | Low | Low | Low — the AI drives it |
| Undo / rollback | Your own backups | Manual restore | Restore from backup | Restore from backup | Quarantine + automatic rollback |
| Open source | n/a | Free plugin is GPL | Plugin GPL; engine proprietary | Plugin GPL; platform proprietary | Fully open (AGPL-3.0) |
| Price | Your time | Freemium | Freemium | Paid platform (free remote scan) | Free |
Comparison of each option's publicly documented approach as of 2026, for orientation only — not a claim that any product is better or worse, and features change often, so please check current versions. Product names are trademarks of their respective owners. These tools are complementary; running an independent second scan is always sensible.
What this tool adds on top: it checks your pages as a search engine (to catch spam shown only to Google), scans outside wp-content (web root and above), removes threats quarantine-first with an automatic health check, and explains how the site was hacked.
How to use it
Step 1 — Get it.
git clone https://github.com/adityaarsharma/wordpress-malware-removal.git
Step 2 — Point your agent at it.
- Claude Code (native skill):
ln -s "$(pwd)/wordpress-malware-removal" ~/.claude/skills/wordpress-malware-removal - Cursor / Codex / other agents: open the folder in your agent and tell it to follow
SKILL.md. - No agent: run the scripts directly.
Step 3 — Connect your site (see gateways) — SproutOS (no SSH) or SSH.
Step 4 — Just ask (or run the scripts):
"Scan example.com for malware" "My site shows gambling spam in Google — clean it" "Remove the Japanese keyword hack" "How was this site hacked?"
The free Wordfence Intelligence feed (free account, no usage cap, commercial use allowed) lets the tool cross-check your installed plugins/themes against known vulnerabilities to find the likely way in.
export WORDFENCE_API_KEY=your_free_key
This is optional — the core malware detection works without it. Setup details: references/wordfence-integration.md.
Keeping it updated
New malware appears constantly, so the detection is built to grow.
- Update the tool:
git pull— you get the latest detection patterns and fixes. - Vulnerability data updates itself: the Wordfence feed refreshes automatically (force it with
python3 scripts/wordfence_client.py --refresh). - Add your own patterns: the signature list (
scripts/signatures.json) is easy to extend, and a built-in test corpus + CI make sure a new pattern catches real malware without flagging clean code. Full guide: references/growing-the-database.md.
Contributions welcome — open a PR or an issue.
How it works
Every scan runs these layers (each degrades gracefully to the access you actually have). Full commands per layer: references/detection-playbook.md.
| # | Layer | What it checks |
|---|---|---|
| 1 | External cloaking | Fetches pages as Googlebot vs a browser (and at the origin behind your CDN) to catch spam shown only to search engines |
| 2 | Web-root sweep | Files/folders outside wp-content — where a lot of malware hides |
| 3 | Core integrity | Modified or extra WordPress core files |
| 4 | Plugin/theme integrity | Nulled/hidden plugins, injected code, fake plugins, unauthenticated REST routes |
| 5 | Uploads | Executable PHP where it shouldn't be |
| 6 | mu-plugins & drop-ins | db.php, object-cache.php, must-use plugins that load on every request |
| 7 | Web-shells & backdoors | File managers and tiny auto-login backdoors |
| 8 | Obfuscation | eval(base64…), packed/encoded code |
| 9 | Database | Injection in posts, options, users, redirects, and log tables |
| 10 | Persistence | Cron, .htaccess, PHP prepend, stream-wrappers, server-level backdoors |
| 11 | Users & sessions | Unexpected admins, rogue application passwords |
| 12 | Log forensics | Reconstructs the attack timeline and finds the entry point + attacker IP |
Flow:
Scan (12 layers) -> verify each finding in context (reduce false alarms) -> back up ->
quarantine -> health-check + rollback -> re-check as Googlebot -> harden -> report
It never deletes on a pattern match alone. For every suspicious item it:
- Reads the actual file/row in context and decides, like an engineer, whether it's malicious or legitimate (a minified library, a code-snippet plugin, an AMP handler, etc.).
- Classifies it as confirmed, needs a human, or false alarm. Only confirmed items are removed.
- When unsure, it flags for review instead of deleting. A file it leaves for you is recoverable; a wrongly deleted file that breaks your site is not.
Connecting your site
| Gateway | Needs | Best for |
|---|---|---|
| SproutOS (recommended) | An Application Password | No SSH — connects right inside WordPress |
| Any other WordPress MCP | The MCP connected | If you already run one |
| SSH + WP-CLI | Shell access | Most complete access |
SproutOS turns any WordPress site into an MCP server over an Application Password — no SSH needed. It's a doorway, not a dependency. Command mapping for each gateway: references/mcp-gateways.md.
What it detects
SEO-spam cloaking · the Japanese keyword hack · pharma & gambling spam · redirect malware · web-shells · auto-login backdoors · uploader scripts · PHP stream-wrapper payloads hidden in images · fake "core function" loaders that rebuild from the database · unauthenticated REST-route backdoors · PHP object injection · wp-config.php injection · malicious .htaccess rules and DirectoryIndex hijacks · ?g= query-string spam · malicious cron jobs · unexpected admin accounts · rogue application passwords · card skimmers · cryptominers · SSH-key backdoors · files disguised as images · core-filename typosquats · double-extension shells · injected sitemaps · server-level persistence · and more.
Full, explained list: references/signature-library.md · the deep-dive on each family and how it hides: references/malware-families.md.
Standalone scripts
You don't need Claude to use the core scripts:
# 1. Check for spam shown only to search engines, across your whole sitemap
python3 scripts/cloaking_diff.py --sitemap https://example.com/sitemap.xml --origin-ip 1.2.3.4
# 2. Deep-scan a WordPress folder for the 38 malware families
python3 scripts/scan_patterns.py /path/to/wordpress --since 2026-06-14 --json findings.json
# 3. Check installed plugins/themes against known vulnerabilities (free Wordfence feed)
python3 scripts/wordfence_client.py --installed installed.json
| Script | Mode | What it does |
|---|---|---|
scripts/cloaking_diff.py |
Clean | Detects cloaking (bot vs browser, origin vs CDN, JS-redirect) |
scripts/scan_patterns.py |
Clean | Pattern-scans a WordPress tree for malware candidates |
scripts/safety_gate.py |
Remove/Harden | Refuses to act until you register a fresh backup → quarantine (never deletes) → auto-rollback |
scripts/reinstall_clean.py |
Remove | Verifies core/plugins against official checksums; reinstalls from clean source |
scripts/harden_actions.py |
Harden | 20 idempotent, reversible hardening actions (SAFE/RISKY/MANUAL); sentinel-wrapped, per-action rollback |
scripts/hardening_audit.py |
Audit | Read-only config/exposure check (REST user-enum, XML-RPC, debug.log, headers…) |
scripts/code_auditor.py |
Audit | Audits plugin/theme/custom code for vulnerabilities (SQLi, XSS, CSRF, access control…) |
scripts/wordfence_client.py |
Audit | Matches installed versions against known CVEs |
scripts/posture_score.py |
Audit | Aggregates findings into an A–F security score + ranked fixes |
scripts/signatures.json / audit_rules.json |
— | The malware + code-audit pattern databases |
How it cleans safely
- Requires a fresh backup before it will touch anything — you (or your host) take the backup; the tool does not create it for you. It then refuses to delete anything until that backup is registered and is under 24h old (enforced in code by
safety_gate.py, not just a guideline). Read-only Audit / Review never touch the site, so they need no backup — the reminder is only for a destructive clean. - For malware injected into real WordPress/plugin files, it replaces them from the official clean source (
reinstall_clean.py) instead of risky hand-editing. - Moves standalone bad files to a quarantine folder — it doesn't delete them.
- Checks the site still loads after every change; if a change breaks something, it restores the file automatically.
- Asks you before anything permanent.
- Re-checks as Googlebot to confirm the spam is actually gone.
It aims to remove every infection it finds and leave the site working. No scanner can promise a site is permanently clean against future or unknown attacks, so it's honest about that: it lists anything it couldn't fully check and suggests a follow-up scan a day or two later to catch anything that tries to come back. Full protocol: references/remediation-playbook.md.
Documentation
| Document | What's inside |
|---|---|
| SKILL.md | Suite router — points to the three skills |
| skills/wp-security-audit/SKILL.md | The read-only audit methodology (A–F posture) |
| skills/wp-malware-removal/SKILL.md | The 12-layer clean methodology |
| skills/wp-hardening/SKILL.md | The safe/reversible hardening methodology |
| ROADMAP.md | What's shipped and what's next |
| SPEC.md | Product & security specification |
| docs/research-2026-07-wp-security.md | Sourced research behind detection, hardening & audit |
| references/gateway.md | Reaching the site over SproutOS / any WP MCP / SSH+WP-CLI |
| references/detection-playbook.md | Every layer's commands, per gateway |
| references/remediation-playbook.md | Safe removal: backup → quarantine → verify → rollback |
| references/hardening.md | The SAFE/RISKY/MANUAL hardening control reference |
| references/cloaking-detection.md | The bot-vs-browser method in depth |
| references/malware-families.md | The malware families + 2026 threat landscape |
| references/signature-library.md | Human-readable signature list |
| references/edge-cases.md | Multisite, custom prefixes, reinfection, safeguards |
| references/mcp-gateways.md | Connecting via SproutOS / other MCP / SSH |
| references/wordfence-integration.md | Free Wordfence feed setup |
| references/growing-the-database.md | How to grow the vulnerability + attack-pattern coverage |
| references/incident-case-study.md | A real hack, start to finish |
FAQ
Connect the tool to your site and say "remove the Japanese keyword hack." It looks for the spam pages that appear only to search engines, rogue sitemaps, .htaccess tricks, and database injections, cleans them safely, and re-checks as Googlebot to confirm they're gone.
Yes — it looks for redirect code in .htaccess, the database, theme files, and injected JavaScript, including redirects that only trigger on mobile or for search engines.
Some infections (called cloaking) show spam only to search engines and clean content to everyone else — including scanners. This tool checks your pages as Googlebot, which is how it can spot that kind of infection.
Yes. Connect SproutOS (over an Application Password) and it runs without shell access.
It's designed not to: it backs up first, quarantines instead of deleting, and checks the site after every step, restoring anything that causes a problem.
A real example
A live WordPress site was infected with gambling spam that only appeared in Google search results — the site looked completely normal to visitors and to the security scanner that was active on it. The malware was hiding in folders outside wp-content, plus a tiny backdoor file that kept letting the attacker back in.
This tool is built to find exactly that kind of hidden infection. The full, step-by-step write-up is included as a worked example and regression test: references/incident-case-study.md.
Contributing
Malware changes constantly. The pattern list (scripts/signatures.json) is easy to extend — add a family, add a safeguard against false alarms, and open a PR. Found something it missed? Open an issue with a sanitized sample.
If this helped you, a star helps others find it.
Works well alongside
Wordfence, MalCare, and Sucuri are well-known WordPress security tools; running an independent second scan is always sensible. This project uses SproutOS as its recommended gateway and the free Wordfence Intelligence vulnerability feed.
License
AGPL-3.0-or-later. Strong copyleft: you're free to use, modify, and self-host it, but if you run a modified version as a network service, you must share your source. This keeps hosted derivatives open.
No comments yet
Be the first to share your take.