描述
WordPress Malware Scanner & Malware Removal
DevDome Malware Scanner checks WordPress files and database content for malware, backdoor code and suspicious changes. It provides file integrity checks, reversible quarantine and malware removal tools in your WordPress dashboard.
It works without an account. An optional DevDome account adds a known-malware hash check against 90,000+ signatures, signature updates and cloud reports.
Review what was found, see the evidence and choose a cleanup action. Areas the scanner could not verify are listed as coverage gaps.
What the Scanner Checks
- WordPress core, plugins and themes for changed, missing or unexpected files.
- PHP code for suspicious execution, hidden code and remote downloads.
- Uploads for executable files and PHP disguised as images or documents.
- Database content for injected scripts, hidden iframes, spam and hidden links.
- Administrator accounts for new users and unexpected administrative permissions.
- WordPress scheduled tasks for suspicious arguments and other warning signs.
- Must-use plugins and drop-ins that may help malware return.
- wp-config.php, .htaccess and .user.ini for suspicious code or settings.
The database scan covers options, posts, revisions, post metadata and user metadata. PHP analysis checks code behavior, including request input reaching execution and downloaded content being written to disk.
An optional vulnerability check compares installed WordPress, plugin and theme versions with WPVulnerability records. It is off by default.
Findings You Can Review
Severity and confidence are separate:
- Severity describes the potential impact: Critical, High, Medium, Low or Info.
- Confidence describes how strongly the evidence suggests malicious activity.
A changed file or newly added administrator is a reason to investigate, not proof of an infection. Low and Info findings are review notes.
Finding details show the affected item, why it was flagged and supporting evidence. For modified core and WordPress.org plugin files, “View what changed” compares the file with the official copy.
Coverage gaps name checks that were skipped, failed or only partly completed. These can include excluded paths, unreadable files, size limits and unavailable official checksums. An unchecked area is not treated as verified clean.
File Integrity and Official Repair
WordPress core and WordPress.org plugin files are verified against official WordPress.org checksums. WordPress.org themes are compared with the official package for the installed version.
Premium and custom plugins and themes are tracked against a file baseline. The first scan records the starting state. Later scans show changes. This baseline records what was present, not whether it was safe.
For eligible core and plugin findings, repair uses the WordPress updater to reinstall the same installed version from the official WordPress.org package. This replaces the whole package, not just the flagged file.
Repair stores backup copies in quarantine before the reinstall and checks the resulting package against official checksums. If a reinstall fails, it attempts to restore those backups and reports any remaining recovery work. Repair backups can also be restored from the Quarantine tab.
Malware Removal and Reversible Quarantine
“One click fix” handles eligible file findings through quarantine or official package repair. These can include known malware, suspicious executable files in uploads and modified core or plugin files.
Findings that need review stay under “Needs your decision”. Examples include suspicious database content, configuration changes, administrator accounts and scheduled tasks. Available actions depend on the finding and the current file.
Quarantine removes a file from disk and keeps a compressed copy in the plugin’s database table. If compression is unavailable, the copy is stored uncompressed. The record includes its original path, hash, size and permissions.
- Restore puts the file back at its original path and verifies its hash.
- Permanent deletion is a separate action.
- Official core files and protected startup files cannot be quarantined.
- Restoring a suspicious file puts its original contents back on the site.
Review the cleanup results and scan again to check what remains.
Check Why Malware May Return
The Reinfection risks tab brings together administrator, scheduled-task, must-use plugin and drop-in findings. These can reveal access or files left behind after malware removal.
Where available, “Neutralize” lets you:
- Remove an account’s administrator rights while keeping the account.
- Remove scheduled events for a suspicious task.
- Quarantine a suspicious must-use plugin or drop-in.
Account roles can be restored under Users. Quarantined files can be restored from Quarantine. Removed scheduled tasks are not restorable through the plugin.
New administrators and other unexpected additions need your review. Legitimate plugins can also create scheduled tasks, must-use plugins and drop-ins.
Scheduled Scans and Scan Controls
Choose daily or weekly scheduled scans, or start a scan manually. Automatic scans are scheduled around 02:00 site time and depend on WordPress cron running.
Scans work in short batches. The open admin page drives progress, with a WP-Cron fallback after you close the tab. You can pause, resume or cancel a scan.
Settings let you adjust batch duration, deep-scan file size limits and excluded paths. Reduced coverage is reported with the results.
Works Without an Account
Without a DevDome account, you can run file integrity, PHP, uploads, configuration, database, user and scheduled-task checks. Quarantine, eligible official repairs and local scan history are available too.
Official verification still contacts WordPress.org. DevDome’s known-malware hash lookup requires a connected account.
Anonymous detection telemetry is optional and off by default. Reports sent through the reporting buttons are separate actions. The External services section explains what each service receives.
Optional DevDome Account
Connecting an account adds:
- Known-malware hash checks against DevDome’s database of 90,000+ signatures. This check sends file hashes, not file contents.
- Downloaded byte-pattern signatures for matching on your site.
- Cloud reports for viewing site security status in your DevDome dashboard.
Enhanced analysis is a separate opt-in. It sends short suspicious code fragments and a file-path hint for a second opinion. The plugin attempts to redact secrets before sending them, but redaction cannot cover every secret format.
Disconnecting stops hash lookups and signature updates. Previously downloaded byte-pattern signatures can still match locally.
Dashboard and Multisite
Simple view shows the verdict, cleanup options and settings. Advanced view adds finding filters, bulk actions, file changes, reinfection risks, quarantine and scan history.
On multisite, the scanner requires network administrator access because file checks and cleanup can affect shared core and plugin files. Each site keeps its own scan data.
WordPress Abilities and MCP
On WordPress 6.9 and newer, WordPress Abilities let compatible AI agents read WordPress security findings, control scans, manage settings and use cleanup actions.
MCP clients can access these abilities when the site exposes them through an adapter such as the WordPress MCP Adapter.
Abilities use the same permission checks and action rules as the dashboard. Actions such as quarantine, repair, neutralization, restore and permanent deletion require an explicit confirmation flag from the agent.
External services
The plugin talks to the following services:
-
WordPress.org APIs (api.wordpress.org, downloads.wordpress.org, core.svn.wordpress.org, plugins.svn.wordpress.org): used to fetch official core and plugin checksums, plugin directory status (whether an installed plugin was closed for a security issue), the official zip of each installed WordPress.org theme (downloaded during a scan to verify the theme’s files) and, on explicit repair or comparison actions, official file copies. Only your WordPress version, locale, plugin and theme slugs and their versions are sent. Terms: https://wordpress.org/about/privacy/ Privacy: https://wordpress.org/about/privacy/
-
DevDome Security API (analytics.devdome.com), only on a site connected to a DevDome account: (a) during each scan, the SHA-256 and MD5 hashes of every scanned file are checked against the DevDome database of 90,000+ known-malware signatures (hashes only, never file contents); (b) after every scan a summary (severity counts, the type, title, path and status of the top findings, the site’s wp-admin URL for the email button, the signature-set version and the plugin version) is sent so your DevDome dashboard shows the site’s security status and your account address gets an email when critical or high threats are found; (c) the byte-pattern signature set is delivered and updated through the account and stored on this site; the hash signatures stay on DevDome’s servers and are only ever queried by hash; (d) with the separate “Enhanced analysis” opt-in, short suspicious code fragments and a file-path hint are sent for a second opinion; the plugin attempts to redact common credential and secret patterns before transmission, but no redactor can guarantee that every secret format is removed. Authentication is the site token the DevDome Dashboard provisioned on connect. Nothing is sent before you connect. Terms: https://devdome.com/terms-of-service Privacy: https://devdome.com/privacy-policy
-
WPVulnerability API (www.wpvulnerability.net), only when you switch on the vulnerability check in Settings (off by default): during a scan, the slugs and versions of your installed plugins, themes and WordPress core are checked against this free public vulnerability database (EUPL v1.2). Only slugs and version numbers are sent. Terms: https://www.robotstxt.es/legal/ Privacy: https://www.wpvulnerability.com/privacy/
Signature data source (not a service the plugin contacts): the signature set is the Linux Malware Detect database (GPLv2, rfxn.com project), imported and served by DevDome; the plugin never contacts rfxn.com. Project page: https://www.rfxn.com/projects/linux-malware-detect/ License (GPLv2): https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-
Plugin catalog (devdome.com): the DevDome Dashboard inside wp-admin fetches the list of DevDome plugins (names, descriptions, logos, links, WordPress.org slugs) from
https://devdome.com/wp-plugins/catalog.jsonat most once every 12 hours, and only after you have connected the site to a DevDome account; a site that is not connected never contacts devdome.com for it. Only the bundled core version is sent in the request; no site or visitor data. Terms: https://devdome.com/terms-of-service Privacy: https://devdome.com/privacy-policy -
Connecting a DevDome account (optional): the DevDome Dashboard offers connecting a free DevDome account. Nothing is sent until you press the Connect button. If you do connect, the shared library sends your site address, a generated site ID and a generated secret site token to
analytics.devdome.com/api/plugin/connect/startand/api/plugin/connect/claimto link this site to your account; afterwards it confirms the connection withapi.devdome.com/plugin/accountat most once every fifteen minutes while you use the dashboard (once an hour after a refusal), and tellsapi.devdome.com/plugin/disconnectwhen you disconnect. Terms: https://devdome.com/terms-of-service Privacy: https://devdome.com/privacy-policy -
Detection telemetry (analytics.devdome.com), only when you tick “Help improve detection” in Settings (off by default) and only on a site that is NOT connected to a DevDome account (a connected site’s scan report, item 2, already carries the same list): after each completed scan the plugin sends the severity, type, title and site-relative path of each open finding of medium severity or higher, the scan number, and the plugin and signature versions, under an anonymous site id (a hash; your site address is never sent). Never file contents, e-mail addresses or absolute server paths. DevDome keeps these lists to tell files flagged on many unrelated sites (allowlist rules) from the same unknown file spreading across sites (new signatures), both delivered through the daily signature update. Terms: https://devdome.com/terms-of-service Privacy: https://devdome.com/privacy-policy
-
Scanner reports (devdome.com), only when you click “Report false alarm to DevDome” in the Actions menu of a finding list or “Send scan report to DevDome” on the Overview. The dialog shows the exact text before you send it: your site address, the plugin, WordPress and PHP versions, the signature version, and for each finding its severity, type, title, site-relative path, status, file hash, the plugin it belongs to and the stored evidence lines (secrets redacted, absolute paths removed), plus the note and reply e-mail you type (both optional). Never file contents. The report goes to DevDome support, who use it to fix false alarms and improve detection in the daily signature update. Terms: https://devdome.com/terms-of-service Privacy: https://devdome.com/privacy-policy
-
Error reports (devdome.com), only when you press “Report this error” on an error message: the plugin sends the error text, the plugin, WordPress and PHP versions, the screen you were on, the last 20 scanner log lines with secrets removed, your site address and your admin e-mail (so support can reply) to
https://devdome.com/api/plugin/error-report. Nothing is sent unless you press the button. Terms: https://devdome.com/terms-of-service Privacy: https://devdome.com/privacy-policy
The scanner does not require a DevDome account. WordPress.org verification services may still be contacted as described above.
Build
The admin stylesheet assets/devdome-tools-tw.css is compiled with Tailwind CSS 3.4.19 from the shipped source src/tw.css. No package.json or build tooling is included in the distribution (WordPress.org review, September 2026). To reproduce the file with the standalone Tailwind CLI (https://github.com/tailwindlabs/tailwindcss/releases/tag/v3.4.19), run from the plugin folder:
tailwindcss -i ./src/tw.css -o ./assets/devdome-tools-tw.css --minify --content "./admin/**/*.php,./assets/admin.js"
The content globs above are the plugin’s complete Tailwind configuration (no theme extensions, no plugins). assets/admin.js is plain, unminified JavaScript and is edited directly; there is no build step for it. The two inline header icons (bug report, save) are from Lucide (ISC licence).
螢幕截圖







安裝
- Upload the plugin and activate it.
- Open Malware Scanner in the admin menu and press Scan Now.
- The first scan verifies integrity and seeds the file baseline; later scans add the change timeline.
- Uninstalling removes the plugin’s tables, settings and scheduled tasks, including the quarantine table. Restore or delete quarantined files before uninstalling if you still need them.
常見問題
-
Does the plugin delete files?
-
No. Threats are moved to quarantine (a compressed, non-executable copy in the plugin’s database table; the file itself is removed from disk) and can be restored from the Quarantine tab at any time. The only deletion is the explicit Delete permanently button on a quarantined file. Uninstalling the plugin removes its tables, settings and scheduled tasks, including the quarantine table, so restore or delete quarantined files first if you still need them.
-
Do I need a DevDome account?
-
No. Every scanning engine runs on your own server: core, plugin and theme integrity, code analysis, uploads, configuration files, users, cron, database and persistence. Connecting a free account adds the 90,000+ known-malware signatures, the security dashboard and the alert email. Without an account the signature set is never downloaded, so there is no known-malware signature matching; the scanner relies on its heuristics and reports that in the coverage notes. If you connect and later disconnect, the byte-pattern signatures already on this site keep matching, but updates and the file hash check stop.
-
Can a cleanup break my site?
-
It is built not to. Files WordPress cannot boot without are never quarantined. A repair reinstalls the whole package (all of WordPress core, or the whole plugin) through the WordPress updater, verified against the official checksum afterwards; the flagged file and every other file the reinstall would change are copied to quarantine first, and if the reinstall fails the original is put back. Theme files, database content, user accounts, cron tasks and configuration files are never changed automatically, with one exception: a theme file that matches a known-malware signature is quarantined (restorable from the Quarantine tab). Anything quarantined can be restored with one click.
-
Why does the scan list coverage gaps?
-
Because unscanned is not the same as clean. Excluded paths, files above the deep scan size limit, an unreachable checksum source, a file the previous scan could not finish and a stage that failed are all listed on the Overview, and findings on files that could not be rechecked are kept, not resolved.
-
Does a scan slow down my site?
-
Scans run in short batches (8 seconds per request by default, 3 to 25 in Settings) while the admin page is open, and continue through WP-Cron when it is closed. You can pause or cancel at any time. The scan does use PHP time on your server, so lower the batch budget on very constrained shared hosting.
-
What is the difference between severity and confidence?
-
Severity is the potential impact (Critical, High, Medium, Low, Info). Confidence is how likely the finding is malicious. A known-signature match has 100% confidence; a high-entropy blob on its own is only a contributing signal and never called malware by itself. Low and Info rows are notes, not threats, and never trigger an alert.
評價
There are no reviews for this plugin.
貢獻者及開發者
修改日誌
1.3.4
- Detection rework, measured on 1,155 public PHP malware samples and 17,261 official WordPress, plugin and theme files: 89 percent to 93 percent of the samples are now caught at some level, with no new alarms on the official files.
- Files that hide PHP under an image, icon, text or translation extension are now looked at outside the uploads folder too, and a script that includes such a file is reported.
- Files over 2 MB are pattern-checked from start to end in windows instead of a 64 KB head, so a payload at the end of a large file is seen.
- A file that is byte-identical to an official WordPress core or plugin file (a backup folder such as updraft/plugins-old, a second WordPress install inside the site folder) is no longer reported as suspicious code; only its bytes are compared, a changed copy is still scanned.
- Payloads assembled from hundreds of short string pieces, the shape of the 2026 bypass shells, are recognised, also in files too large for full code analysis.
- Request input read from headers, from the raw request body, from $GLOBALS or from a superglobal spelled as a string is followed to the same sinks as $_POST and $_GET.
- More callback sinks are judged (array_udiff and friends, forward_static_call, ob_start, the error and exception handlers, register_tick_function), a function name assembled from string pieces is resolved before the call is scored, and the multibyte e-modifier replace is treated like preg_replace /e.
- A login or user elevation only counts as a backdoor when the request input is read in the same function, which removes false alarms on large official files.
- Script tags carried inside PHP strings and JavaScript uploads are judged by the JavaScript detector.
- Page cache folders are scanned for executable content instead of being skipped entirely.
- Signature hits carry the feed’s severity: only critical signatures are a known malware verdict, lower ones are evidence.
- wp-includes/version.php is never repaired automatically (it names the WordPress version every repair would download): reinstall WordPress from a fresh wordpress.org package, then rescan; package reinstalls need the matching update capability and respect DISALLOW_FILE_MODS; removing administrator rights needs the promote_users capability.
- A displaced plugin folder left behind by a permission repair is denied web access where the server honours .htaccess.
- Plugin integrity: an official file that a plugin moved to a renamed folder is matched by its content instead of its path, and a folder full of files the official package does not ship (a library the plugin installed itself) is one review item, not one alarm per file. A customer site with WP phpMyAdmin received 2,386 alarms for one renamed folder.
1.3.3
- Updates now work when a DevDome plugin folder belongs to another system user, for example after an install from a root shell or by an AI agent. Before, the update failed with Retry update or an uploaded zip kept the old version (shared DevDome core 1.7.2).
- The old copy such an update leaves behind, a hidden folder the web server cannot delete, is recognised by the content fingerprint recorded when it was created, so it is no longer reported as a plugin folder without a plugin header. Its files are still scanned, and a copy whose files changed is reported as before.
1.3.2
- Scan Coverage lists only what was not scanned (excluded folders, symlinks, oversized trees), once per path. Plugins without WordPress.org checksums are scanned file by file and are no longer listed there as if they were a gap.
- The scanner now verifies its own files against the WordPress.org checksums like every other plugin. It used to skip its own folder, so its files went through the full code analysis and one shared-library file was reported as a threat on every site.
- New: a visible “Think one of these is a false alarm?” line with a “Report false alarms” button under the findings on the Overview and under the Threats list, plus “Report false alarm to DevDome” in the Actions menu of the Threats and Reinfection risks lists for selected rows. No account needed: the dialog shows the exact text before it is sent (never file contents), you can add a note and a reply address, and DevDome support uses the report to fix false alarms and improve detection.
- Overview laid out like Link Monitor: the protection ring with the Scan button under it on the left; the verdict, the One click fix button, the severity tiles (Medium is now counted in the simple view too) and the progress bar on the right; the findings in their own card below. The fix button and the false-alarm line disappear the moment a scan starts. The ring stays amber for High findings; Mediums next to a High no longer paint it red.
- Fixed two false alarms seen on real sites: a plugin’s own shared-library file was reported as “request input reaches code execution” because a closure that captured a sanitised request value was treated as request-controlled code (a variable holding a closure is a function written in the file, never a name from the request), and a plugin file that is plain text without any PHP open tag (All-in-One WP Migration’s “Kangaroos cannot jump here” storage/index.php) was reported as an unknown PHP file after every quarantine. An inline closure passed as a callback is now judged like a quoted function name, so values read from the database as its data no longer raise a “value read from the database is executed” note. A callback that is a plain variable or a fixed method on an object (call_user_func($renderer, $data), array_map(array($this->handler, ‘run’), $rows)) is now judged by the callback itself, not by the data next to it; a callback taken from the request or the database is still reported. A PHP file inside uploads that only answers 403/404 and stops (the index.php WPForms writes into its cache folder) is no longer reported as an executable file inside uploads.
1.3.1
- New optional “Help improve detection” switch in Settings (off by default): after each scan a site without a DevDome account can send an anonymous finding list (severity, type, title, site-relative path, scan number, plugin and signature versions under an anonymous site id; never your site address, file contents or server paths). Connected sites already report through the account. DevDome turns files flagged on many unrelated sites into allowlist rules and shared unknown files into new signatures, delivered through the daily signature update.
- The update-settings ability accepts the new “telemetry” key; turning it on needs confirm: true like every other data-sharing switch.
- Fixed: a false “crash marker could not be saved (database error)” note at the end of every filesystem pass (an empty value read as a missing row).
- Fixed: a database write that did not land could still pass its verification when the stored value was empty.
- Secrets written with HTML entities (password="…") in database records are now redacted in stored evidence too.
- Shared library 1.7.1: a connection is never reported as “not connected” after a failed database read, the connect return leg keeps its retry handle until the connection is stored, and plugins get a devdcorev1_connected hook.
1.3.0
- Fewer false alarms, seen on real sites: a plugin’s own empty “Silence is golden” index.php inside its storage or cache folder is no longer reported as an unknown PHP file (it came back after every quarantine); code patterns inside a Composer library a plugin ships (listed in its vendor/composer/installed.json) are LOW notes instead of MEDIUM alarms; the options of head/footer-code plugins (Head, Footer and Post Injections, Insert Headers and Footers, WPCode and similar) are LOW “review what you put there” notes, not HIGH injection alarms.
- Repair: a core file repair refuses while wp-includes/version.php itself has an open finding, so the WordPress version that chooses the package can never come from an attacker; repairs run one at a time (also across the sites of a multisite network).
- Shared core 1.7.0: Disconnect proves the connection was cleared on this site and says so when it was not; a site token removed elsewhere reads as disconnected at once; plugins without health checks show “Not monitored” on the DevDome dashboard instead of “No Issues”; overlapping bot IP ranges are merged.
- Report this error: every error banner and failed-action dialog has a button that sends the error text, the plugin and WordPress versions and the last scanner log lines (secrets redacted) to DevDome support with one click, no form. Nothing is sent unless you click it.
- Database guard: every failed database query during a scan tick, a screen action, an AI agent ability or the scanner page is now recorded as it happens. A failed read can no longer pass as an empty answer: the plugin refuses to write findings, statuses or baselines after one, actions and abilities answer a database error instead of “done”, a scan stage with a failed query is marked failed (nothing auto-resolved) and the scanner page shows a warning when it was built over one.
- Shared core 1.7.0: new read-only ability devdome-tools/get-connection for AI agents (connected, account ID, plan, installed DevDome plugins); a site that moved to another domain resets its connection instead of showing the old domain’s; on a subdirectory multisite every site shares the network’s connection.
- Shared core 1.7.0 (account connection): a proxy error page or a short outage of the account server no longer clears a live connection (only the server’s own “not linked” answer does); Disconnect reports “still listed” unless the server confirmed the unlink; the final connect confirmation requires a real success response; clearer connect error texts.
- Database scan: an oEmbed cache row (oembed postmeta) holding a visible embed from an unlisted provider is now a LOW embed note, not a critical injection. WordPress rebuilds those rows from the post on every view, so the old CRITICAL finding came back after each quarantine. Hidden iframes stay flagged. The finding text now says to remove the embed from the post instead of the row.
- Quarantine: a record whose last database write failed after the file was already removed is finished by Restore or Delete instead of staying stuck, and unfinished records are always listed (screen and agents). Secret redaction also covers heredoc and nowdoc values assigned to bracketed keys, unquoted .env / INI / YAML values, wrapped literals (base64_decode, hex2bin) and concatenated putenv() values. Hidden-frame checks decode numeric entities written without a semicolon. A record still being stored is never restored, and the backups a running repair made stay locked until it finishes. Read-only agent abilities report the account connection from the cached state without re-verifying it.
- Code analysis follows request input through one assignment (a variable that took a superglobal counts like the superglobal in include, exec and callback checks); short-echo tags followed by a quote, digit or parenthesis are recognised in uploads; an official plugin holding a file the package does not ship (a stray .htaccess, .js or .svg) is no longer skipped by the file scan. Demoted or unscheduled findings read as handled; a demote retried after a lost status write closes the finding; the Overview says when the reinfection risks could not be read; dashboard tiles use the last completed scan, not a failed later attempt; agents get a database error, not “not found”, when a finding read fails.
- A restore interrupted after the file was written finishes reopening its finding on the next try. Backups made by a running repair stay locked per repair (two repairs at once never unlock each other), through the rollback. Code analysis follows request input through appended strings and through functions that return it, and judges the callback argument of array_filter, usort, array_walk, array_reduce and preg_replace_callback. Secret redaction also covers commented or parenthesised values, nested wrappers, YAML block values, hyphenated JSON keys, XML elements, HTTP Basic headers, passwords inside connection URLs and sprintf-built putenv() calls. Read-only agent abilities no longer trigger a signature or catalog download; scan history is not pruned when the keep-newest lookup fails.
- The only network super admin is never demoted; the file-changes list shows the whole 90-day window; the deep-scan size setting has an upper bound (64 MB); bulk Ignore, Mark as false positive and Remove from list ask first; an unlistable must-use plugins folder reads “unavailable”; agents get an error, not “not running”, when the scan table cannot be read; a cloud switch can always be turned off without an account; signature downloads stop retrying after repeated API failures and keep the feed’s own severity levels; a missing core file fails core verification; a plugin folder that is a symbolic link is never treated as verified; an empty checksum answer from WordPress.org is retried within the hour instead of being remembered for a week; short-echo PHP tags before a minus sign and PHP code inside .svg or .html uploads are recognised; $pass, $pwd and XML credential values are redacted.
- An account that still holds administrator-level capabilities through a role is never reported as demoted; a repair backup put back over the official copy reopens its finding even when the earlier attempt was interrupted; a repair refuses to start when it cannot lock its backups; credential values concatenated behind comments, parentheses or wrapper calls are redacted.
- A signature download that finishes while a scan is reading the signature table no longer leaves that scan matching against a mix of the old and the new set, and the download reads its final writes back. A scan whose saved progress record is damaged ends as failed instead of completing with nothing verified. The screens say when the scan history could not be read. Theme vulnerability findings are typed as themes. Agent output keeps file names for paths that contain spaces. A PHP short tag glued to a dangerous call (system, eval, include) counts as PHP code when short tags are on. A script tag hidden in the middle of a large image or SVG upload is found. A failed site list during network activation or deactivation is recorded.
- A findings read that fails after the counts were taken never shows the green pill or verdict; the progress poller and the finding buttons report a database error instead of “no scan” or “not found”; One click fix and the run-scan ability read the scan state back before acting. A hash lookup that answers without results keeps the known-malware findings open. A failed reinstall can always roll back its own backups, even while another repair runs, and two repairs starting at once keep both their locks. An unreadable scheduled-task list fails the cron check instead of clearing it; unreadable configuration files keep their earlier findings; a revision holding PHP is judged like its parent post; a symbolic link to an absolute path outside the site is flagged; PHP hidden in the middle of a large HTML upload is found; accounts with raw administrator capabilities join the administrator roster; a linked official plugin file or theme folder is never read through. Signature download failures are abandoned cleanly and every progress write is read back. A scan finishing in the same instant a new one starts no longer clears the new scan’s pointer. A dismissed bulk confirmation re-enables Apply.
- Restoring a repair backup of a file whose threat had since been marked resolved reopens that threat; a repair whose lock could not be taken never touches the other repairs’ locks.
- Every “is a scan running” check (Scan button, scheduled start, One click fix, Cancel) reports a database error instead of assuming no scan; a scan that ends never clears the pointer of a scan that started right after it; the progress poller and the background worker report an unreadable scan row; the DevDome dashboard says “unavailable” instead of “never scanned” on a failed read. A file whose current hash could not be read fails the scan stage instead of keeping a false-positive decision; configuration files larger than the read cap are recorded as partly checked; a lost core file list degrades the core check instead of skipping it; a database value used as an include path is a finding; array_filter on request data without a callback is no longer flagged; a linked folder on the way to an official plugin or theme file is never read through. Signature downloads swap the set under a marker the scan matcher honours, and a restarted download reads its state back. A cloud code-analysis answer without results is a coverage note.
- A new administrator, a new must-use plugin or drop-in, or a changed critical setting stays listed until you decide about it; earlier scans closed those findings on the next scan because the item had become part of the stored snapshot. Saving settings while the current settings cannot be read no longer replaces the schedule and the account switches with defaults. The automatic-scan schedule is only reported as applied when the scheduled-task list could be read.
- Every action that acts on a finding or a quarantine record by id (quarantine, repair, compare, restore, delete, remove from list) reports a database error instead of “not found” when the record could not be read, and the stored lists of administrators, must-use plugins and drop-ins are never rebuilt from a failed read.
- Every “is a scan running” check reports a database error when the scan pointer itself could not be read; demoting an administrator and One click fix run one at a time; a scan whose progress could not be saved ends as failed instead of restarting on stale state; no file hash or report is sent to DevDome when the settings could not be read (the defaults are never used for sharing); the repair backup lock fails closed when it cannot be read; a signature set is never matched while its version marker is unreadable; option names containing “secret” or “key” without an underscore are scanned again (an escaping mistake excluded them); an unquoted password with spaces is redacted whole; accounts that can activate plugins count as administrators; a database value used as a callback is flagged; official file lists can never point outside the plugin or theme folder; every site of a network gets its own uploads folder for quarantine; the schema version is recorded only when the tables exist.
- Reopening a trusted finding refuses when the trusted list could not be read instead of leaving the file silenced; trusting a file never rebuilds the trusted list from a failed read; a scan whose saved progress went missing after the first stage ends as failed instead of completing clean.
1.2.2
- Screens never show a clean or empty list when the database read failed: the Threats, Reinfection risks, File changes, Quarantine and History tabs say “unavailable” instead.
- Counts on the screens and in the agent summary are no longer taken from a capped window (header threat split, severity pills, reinfection risks, quarantine history).
- Agents: the security summary, fix plan and quarantine list refuse with an error when the findings table could not be read; the scan status names an uncounted findings table; turning any cloud switch on (hash lookup, code analysis, report) needs confirm: true; a neutralize whose demotion or unscheduling succeeded but whose status write failed says exactly that; sync-signatures reports the real start result.
- Scanners: an unreadable file in uploads, wp-config.php or a .htaccess / .user.ini is recorded as not checked instead of being scanned as an empty file; an unreadable must-use plugins folder or wp-content no longer wipes the stored snapshot; privileged config files beyond the checked set are named.
- Fix plan: a changed plugin file outside the writable roots is a decision, not a repair that would be refused.
- One-click fix: rows with a backslash in the path no longer freeze the progress loop, and a batch with failed rows is never announced as closed.
- Secret redaction also covers plain token, access_token, refresh_token, secret_key and application password assignments.
- A false-positive decision whose trust undo failed reports that the content is still trusted.
1.2.1
- Neutralize on a scheduled task now removes every event of the hook, including events scheduled with arguments, and verifies none remain before the finding is marked handled.
- Repair backs up everything the package reinstall may overwrite or delete (files differing from the official copy, extra files in the plugin folder) as copies in quarantine, restorable over the official copy; the scope of a repair is stated in the fix plan, the confirmation and the ability descriptions.
- A failed reinstall now puts every backed-up package file back, and restoring a backup over the reinstalled file keeps the displaced file safe if the write fails.
- Scheduled-task details show the next run for any event of the hook; agent output carries no absolute server paths; settings updates are read back before they report success and changes that lower protection need an explicit confirm.
- Abilities hardening: finding-action only accepts actions the screen offers for that finding (the screens enforce the same list); One click fix, quarantine, repair, neutralize, restore and permanent quarantine deletion require confirm: true; per-ability idempotency annotations; user email no longer included in finding details.
- The official-copy comparison now compares lines in order: a file whose code was only moved around is reported as modified, not as whitespace drift. Package repair refuses a plugin folder that contains a symbolic link (no backup is possible for it). A restore whose recorded permissions cannot be applied is rolled back and reported instead of counted as success.
- A restore whose rollback fails keeps the file it displaced as its own quarantine record (restorable over the path) and says so. Core repair backs up the files inside obsolete folders the reinstall removes. A permanent delete that lost its final database write shows as Deleting and is finished by pressing Delete again. The finding-action ability is annotated destructive (neutralize removes scheduled events for good).
- Evidence snippets are redacted before they are shortened, so a credential on a very long line never reaches stored evidence or agent output.
- Core repair refuses to run when a core file or its folder is a symbolic link (the reinstall would write outside the site with no backup) and also backs up the Genericons example.html files WordPress removes from plugins and themes. A quarantine copy from a pre-1.0.2 store is only touched inside a link-free quarantine folder, and a copy that cannot be removed stays tracked instead of being forgotten.
- Core repair also refuses when a missing core file would be created below a symbolic link, and the Genericons check reads whole files and follows links the way WordPress does, refusing any match it could not back up. Turning cloud code analysis on through the update-settings ability now needs confirm: true (it sends suspicious code fragments to DevDome).
- Core repair also backs up the legacy Requests library files WordPress removes, and its Genericons search walks every folder without a depth limit (looping links end safely). A multi-line private key in a modified file is redacted as a whole in the official-copy comparison. The account Disconnect says so when the DevDome account server could not be told.
- Every file that ships with WordPress core is now repair-only: quarantine is refused for all of them (the official checksum map decides), not just for the handful of bootstrap files. A credential whose value sits on its own line is redacted in the official-copy comparison. Pausing a scan reads the saved state back and reports when the pause did not stick.
- The secret redactor never swallows a line break, so the official-copy comparison keeps its line numbers while redacting; if a line count ever moves, every line that is part of a recognised secret is replaced whole. Resuming a scan reads the saved state back too.
- Secret values that span several lines (a define, an environment value, an assignment, a key block) are redacted whole with their line count kept. One click fix reads every active finding, not the first 500, and both it and the findings list report a failed database read instead of an empty result.
- The theme integrity check extracts the official theme copy through the plugin’s own direct file access, so a host whose WordPress file method is FTP no longer ends the scan with a failed theme stage.
1.2.0
- WordPress Abilities API: 20 abilities covering every feature (verdict and fix plan, findings, evidence and diff, scan control, One click fix, every finding action incl. neutralize, quarantine restore and delete, logs, settings, view mode, signatures). Empty-input abilities refuse unexpected arguments cleanly.
1.1.0
- WordPress Abilities API support (WordPress 6.9+): seven read and scan abilities for AI agents and MCP clients: get-security-summary, get-findings, get-finding-details, get-scan-progress, run-malware-scan, get-scan-history, get-quarantine. Cleanup actions are not exposed.
1.0.3
- New plugin icon (shield with magnifier) in the admin header, matching the WordPress.org listing.
1.0.2
- Quarantine no longer keeps files on disk: the file’s contents are stored compressed in the plugin’s own database table and the file is removed; restore verifies the hash. Copies made by 1.0.1 are moved into the database on upgrade.
- Local file reads go through the WordPress filesystem layer; temporary files and folders are removed through it too.
- The database scanner never reads options that hold credentials (WordPress Connectors and any API key, token, secret or application password option).
- Build tooling is no longer shipped in the distribution zip.
1.0.1
- Quarantine store moved to uploads/devdome-malware-scanner/quarantine (resolved through wp_upload_dir(), protected by deny rules and non-executable names).
- Trusted repair now hands the write to the WordPress updater: core files are restored by reinstalling the running WordPress version, plugin files by reinstalling the same plugin version from WordPress.org. The plugin no longer writes into core or plugin folders.
- Suite dashboard: installing a sibling plugin no longer activates it; activation is a separate click.
1.0.0
- First public release.
- Scans WordPress core, WordPress.org plugins and themes against their official copies, and premium or custom code against a baseline with a file change timeline.
- Token-based PHP analysis for behavior chains (request input to execution, decode to execution, remote download to disk write), obfuscation detection, uploads inspection, configuration files, must-use plugins and drop-ins, administrator accounts, WP-Cron events and database injections.
- Known-malware signatures through an optional DevDome account: byte patterns matched on the site, file hashes checked on the DevDome servers, only hashes ever sent.
- One-click cleanup: quarantine (renamed, non-executable, restorable) and trusted repair through the WordPress updater (reinstall of the same version from WordPress.org), every action bound to the exact file contents the finding was made on.
- Honest verdicts: unscanned, unreadable or partially scanned areas are never assumed clean, a failed or cancelled scan never replaces the last completed result, and coverage gaps are listed.
- Reinfection risks tab: unknown administrators, must-use plugins, drop-ins and scheduled tasks that would let an attacker back in, with a Neutralize action; every finding expands to a detail panel with the facts and links that lead to the fix.
- Time-boxed batches with pause, resume and cancel, a WP-Cron fallback, scheduled daily or weekly scans, Simple and Advanced views, and multisite support.
