A read-only WordPress malware scanner your AI assistant can drive over the Model Context Protocol.
Turns WordPress into an MCP server so an assistant like Claude can scan the site on request, read the files it flags, and explain what it found — instead of handing you a list of rule names to decode yourself.
It cannot delete, modify, quarantine or move anything. That is the point. A plugin that deletes files on command from a remote endpoint is itself a backdoor; the only thing separating it from the malware it hunts is who holds the token.
Signature scanners produce noise. On a real infection this plugin was tested against, the signature scan returned 76 high-severity hits and 23 were real — the rest were a sentiment-analysis library and a bundled SSH client sitting inside reputable SEO plugins.
The integrity checker found the same 23 with zero false positives, because it compares every core file against the official wordpress.org checksum manifest. A checksum mismatch is a fact. A pattern match is a guess.
Both are included. Judgement about which to trust is the part an AI assistant is actually good at.
File signatures — webshells, obfuscated payloads (eval on decoded strings, layered base64 + gzinflate, chr() assembly), request-driven code execution, command execution, PHP in the uploads directory, double extensions, unexpected PHP in the document root, must-use plugins, drop-ins, search-engine verification files.
Core & plugin integrity — every core file against api.wordpress.org checksums for your exact version, and every wordpress.org plugin against its published manifest. Reports modified, missing, and unexpected files. Catches injected backdoors that signature scanning misses entirely, because attackers usually add files rather than edit them.
Database & users — administrator accounts, passwordless temporary logins, roles granted admin capabilities, active sessions with IPs and user agents, orphaned cron events, options containing PHP, snippet-plugin code stored in the database, external scripts injected into content. Cleaning files without this leaves the attacker a way back in.
Crawler cloaking — fetches your own site as Googlebot, AdsBot, Mediapartners and bingbot, then diffs each response against a normal browser. Cloaking is invisible to the site owner by design.
| Tool | Purpose |
|---|---|
sentinel_site_info |
Versions, plugins, mu-plugins, drop-ins, hardening constants |
sentinel_scan_files |
Signature + heuristic scan (resumable) |
sentinel_check_integrity |
Core + plugin checksums vs wordpress.org (resumable) |
sentinel_scan_database |
Users, sessions, cron, options, snippets, content |
sentinel_check_cloaking |
Googlebot / AdsBot / bingbot response diffing |
sentinel_read_file |
Read a flagged file (root-confined, secrets redacted) |
sentinel_recent_files |
Files modified since a date, newest first |
scan_files and check_integrity are resumable: each pass takes a wall-clock budget, stops before the host kills it, and returns a cursor. The assistant keeps calling until complete is true, so a large site finishes instead of dying against max_execution_time.
From a release
Download the latest zip from Releases, then WordPress → Plugins → Add New → Upload Plugin.
From source
git clone https://github.com/sameeullah/ai-malware-scanner.git
cd ai-malware-scannerCopy or symlink into wp-content/plugins/. There is no build step — no Composer, no npm, no compiled assets. What you read is what runs.
Connect an MCP client
- Activate, then go to Tools → AI Malware Scanner
- Connection & token tab → Generate token (shown once; only a SHA-256 hash is stored)
- Add the MCP URL as a custom connector:
https://example.com/wp-json/ai-malware-scanner/v1/mcp - Set the authorization header to
Bearer <your token> - Ask: "Run a full security scan"
If your client can't send custom headers, append the token to the path instead — /mcp/<token>. Works everywhere, but the token lands in your access logs, so rotate it.
Verify reachability:
curl https://example.com/wp-json/ai-malware-scanner/v1/ping
# {"service":"ai-malware-scanner","version":"1.0.0","ready":true}| Read files inside the WordPress root | yes |
| Verify checksums against wordpress.org | yes |
| Read users, options, cron, posts | yes |
| Fetch its own site as a crawler | yes |
| Write, delete or move any file | no |
| Modify or delete database rows | no |
| Execute shell commands or arbitrary PHP | no |
| Read outside the WordPress root | no |
| Return DB passwords or auth salts | no — redacted |
- 64-character bearer token, stored only as a SHA-256 hash, compared with
hash_equals() - Endpoint closed until a token is explicitly generated; deactivation revokes it
- Optional IP allowlist (IPv4 + IPv6 CIDR)
- Rate limited per IP
- Every authentication attempt logged, allowed or denied
Found a vulnerability? Please report it privately via GitHub Security Advisories rather than a public issue.
Nothing, until you connect a client.
Once connected, scan results — file paths, contents you ask the assistant to read, usernames, email addresses, session IPs — go to whichever AI provider you chose, under their privacy policy.
The integrity checker calls api.wordpress.org for checksum manifests. That request carries your WordPress version and plugin slugs, nothing site-identifying.
ai-malware-scanner.php Bootstrap, constants, class map
includes/
class-sentinel-auth.php Tokens, rate limiting, IP allowlist, access log
class-sentinel-mcp-server.php JSON-RPC 2.0 over Streamable HTTP
class-sentinel-tools.php Tool schemas and dispatch
class-sentinel-report.php Finding collection and severity
class-sentinel-results.php Persists findings for the admin dashboard
class-sentinel-budget.php Wall-clock budget for resumable passes
class-sentinel-admin.php Tabbed admin UI
class-sentinel-plugin-info.php Native "View details" modal
scanners/
class-sentinel-scanner-files.php
class-sentinel-scanner-integrity.php
class-sentinel-scanner-database.php
class-sentinel-scanner-cloaking.php
uninstall.php Removes every option and transient
readme.txt WordPress.org directory metadata
An explicit class map is used instead of a filesystem-scanning autoloader — that construct is exactly what a security plugin should not ship.
Tool descriptions in class-sentinel-tools.php are load-bearing. They are the only instructions the model receives about when a tool applies and how to drive a resumable scan, and are written for that reader rather than as API docs.
No dependencies to install. To check it before a PR:
# WordPress coding standards
composer global require wp-coding-standards/wpcs
phpcs --standard=WordPress .
# The same checks wordpress.org runs
# (install "Plugin Check" from the plugin directory, then)
wp plugin check ai-malware-scannerDirect $wpdb calls in the database scanner carry phpcs:disable blocks with justification inline. They are deliberate: no Core API can search option_value or do post_content LIKE, and caching would be a defect — a scanner reporting stale state actively lies.
Stated plainly, because a security tool that oversells itself is worse than none.
- Loopback fetches. The cloaking check requests your site from your own server. Many hosts block this. The tool reports the failure rather than a false all-clear — verify manually with
curl -A "Googlebot/2.1 (+http://www.google.com/bot.html)". - Premium plugins are unverifiable, not verified. No published manifest means nothing to compare against.
- Cloaking tests one URL at a time, the homepage by default.
- Signature scanning produces false positives. Read what it flags; that's why
sentinel_read_fileexists. - Multisite is lightly tested.
- It finds; it does not fix. By design.
- Skip signature analysis on plugins that verify clean against wordpress.org (would have removed nearly every false positive in testing)
- Scheduled scans with email alerts on critical findings
- Multi-URL cloaking checks
- Exportable incident report
Issues and pull requests welcome. For code changes, please run PHPCS against the WordPress standard and Plugin Check before opening a PR, and keep the read-only guarantee intact — any patch introducing a write path to site files or rows will be declined regardless of how useful it is.
GPL-2.0-or-later. See LICENSE.
Samee Ullah — Full Stack Web Developer & AI Automation Specialist LinkedIn