-
v5.1.6 Stable
released this
2026-08-23 07:10:06 +00:00 | 0 commits to main since this release5.1.6 - 2026-08-22
Fixed
- Saving the "Delete all plugin data on uninstall" preference no longer triggers a fatal error (
add_settings_error()was called before the WordPress admin API was loaded). - Notification channels can now be disabled entirely: unchecking every channel and saving previously kept the old channels active, because unchecked checkboxes are never submitted.
- "Reset Plugin" and "Delete all logs" now purge both log stores (API request logs and shell execution audit logs). Previously the shell audit store was never cleaned, and both deletions silently did nothing because the log post types were not registered yet when the actions ran.
- The Debug tab API connectivity tests now use the real API routes: WordPress core collapses pre-release versions (e.g. 7.1-alpha) to their stable milestone, and plugins/themes are tested against their actual slug routes instead of nonexistent plural ones (HTTP 404).
- Component icons now carry explicit width/height attributes and a meaningful alt text. The same icons are embedded in notification emails and Site Health, where the plugin CSS is not loaded and unsized SVGs rendered at their intrinsic 800x800 size.
Changed
languages/wpvulnerability.potregenerated with the new strings.
Compatibility
- WordPress: 4.7 - 7.1
- PHP: 7.0 - 8.5
- WP-CLI: 2.3.0 - 2.12.0
Tests
- PHP Coding Standards: 3.13.6 (0 errors)
- WordPress Coding Standards: 3.4.1
- PHPStan: 2.2.9 (level 9, 0 errors)
- PHPUnit: 9.6.36 (54 tests)
5.1.5 - 2026-08-22
Changed
- The contributor list now leads with the ROBOTSTXT organization account, followed by Javier Casares; the remaining contributors are unchanged.
- Regenerated
languages/wpvulnerability.potso its source references match the current code. The string set is unchanged (450 strings); all shipped translations were verified against it and remain fully up to date.
Compatibility
- WordPress: 4.7 - 7.1
- PHP: 7.0 - 8.5
- WP-CLI: 2.3.0 - 2.12.0
Tests
- PHP Coding Standards: 3.13.6
- WordPress Coding Standards: 3.4.1
- PHPStan: 2.2.9 (level 9, 0 errors)
- PHPUnit: 9.6.36 (45 tests)
= [5.1.4] - 2026-08-22 =
Highlights
- The Site Health vulnerability tests work again on every WordPress version: they were silently disabled everywhere by an availability gate that could never pass. Secrets are now masked in the admin forms, and compatibility was verified against real PHP interpreters from 5.6 to 8.5.
Fixed
- The Site Health integration registered its tests behind
class_exists( 'WP_Site_Health' ), but core loads that class lazily, afterinit, where the plugin loads its modules — so the guard always evaluated to false and none of the 13 vulnerability tests ever appeared in Site Health. The filter is now registered unconditionally; below WordPress 5.2 it simply never fires. - "Clear all caches" in the debug tools now also deletes the
wpvulnerability-plugins-cache-datatimestamp option, so the plugins dataset is fully refreshed afterwards. - The notification email "From:" address is now sanitized with
sanitize_email()on all code paths. - The plugins list table "Last updated" column decoded the whole plugins dataset for every table row; it is now decoded once per request.
- Removed a duplicated
json_decode()call when reading the vulnerable-themes count. - The
wp_date()compatibility polyfill no longer fatals on WordPress 4.7–5.3: core callswp_maybe_decline_date()unconditionally, but that function only exists since 5.4; the call is now availability-guarded. - The core and software JSON getters return
'[]'instead of an empty string when encoding fails, matching the plugins and themes getters.
Security
- Webhook URLs (Slack, Teams, Discord) and the Telegram bot token are masked in the admin settings forms (single-site and network), showing only their last 4 characters — previously they were rendered in full into the page HTML. The inputs are plain text fields, so masked values never trigger browser URL validation. Saving a form with unchanged masked values keeps the stored secret; clearing a field still removes it.
- Removed the dead
register_uninstall_hook()registration:uninstall.phpsupersedes it and the registration added a stray autoloaded option row. - Single-site settings registrations now explicitly set
show_in_rest => false, matching the multisite configuration.
Changed
- Admin CSS/JS assets load only on the WPVulnerability settings pages, the dashboard and the plugins/themes list tables instead of on every wp-admin screen.
- The shell availability probe (
wpvulnerability_can_shell_exec()) result is cached per request instead of spawning a process on every call.
Compatibility
- WordPress: 4.7 - 7.1
- PHP: 7.0 - 8.5
- WP-CLI: 2.3.0 - 2.12.0
- Verified against real PHP interpreters 5.6.40, 7.0.33, 7.1.33, 7.2.34, 7.3.33, 7.4.33, 8.0.30, 8.1.34, 8.2.33, 8.3.33, 8.4.24 and 8.5.9: every plugin file lints clean from 7.0 up and fails on 5.6, confirming the declared floor. PHPCompatibility gate 7.0-8.5 clean; wp-compat WordPress floor 4.7 clean.
Tests
- PHP Coding Standards: 3.13.6
- WordPress Coding Standards: 3.4.1
- PHPStan: 2.2.9 (level 9, 0 errors)
- PHPUnit: 9.6.36 (45 tests)
5.1.3 - 2026-08-22
Added
wpvulnerability-compat.php: verbatim WordPress core function polyfills (wp_doing_cron,get_main_site_id,wp_is_json_request,sanitize_locale_name,determine_locale,wp_timezone_string,wp_timezone,wp_date,get_post_datetime,get_post_timestamp), each guarded byfunction_exists(). The plugin no longer fatals on WordPress versions that lack these functions.
Security
- The API connectivity test results (message, HTTP code, response time and the raw response preview) are now escaped client-side before being inserted into the page, in both single-site and network admin. Remote API responses could previously inject arbitrary HTML.
- The debug export and the Database Options Viewer now mask webhook URLs, Telegram bot tokens/chat IDs and notification email addresses, so shared debug files never contain usable secrets.
- The multisite "components to hide" save now routes through the strict sanitizer, so a crafted request can no longer re-enable analysis of components force-hidden with
WPVULNERABILITY_HIDE_*constants. - API responses are only cached when the HTTP status is 200 and the body is valid JSON. Error responses (4xx/5xx, HTML error pages) were previously cached for the full TTL and blocked retries.
- API request URLs are now built from whitelisted types and sanitized slugs/versions (
wpvulnerability_get(),wpvulnerability_get_vulnerabilities()).
Fixed
- Cron scheduling ran
wp_get_schedules()(and other plugins'cron_schedulescallbacks, including their translation calls) beforeiniton every request. Core and notification event scheduling moved toinit, matching the WordPress 6.7+ translation-loading requirements. - Deactivation now removes the
wpvulnerability-plugins-dataandwpvulnerability-plugins-data-cacheoptions created at activation. - The notification cron period is validated against
daily/weeklybeforewp_schedule_event(), so a corrupted configuration value can no longer silently unschedule notifications. - The admin menu vulnerability counters escape the badge title attribute, and the plugin row "Settings" link escapes its URL and label.
- Application Passwords REST authentication is gated on
function_exists( 'wp_is_application_passwords_available' )so WordPress < 5.6 no longer fatals on unauthenticated REST requests; cookie-authenticated admin sessions keep working and the Application Passwords functionality itself is simply unavailable on old versions. - The Site Health integration registers its tests only when
WP_Site_Healthexists (WordPress 5.2+); on older versions the plugin runs without the Site Health section.
Changed
- Minimum WordPress version lowered from 5.6 to 4.7. Whole functionalities degrade gracefully on old versions: Application Passwords REST authentication (WordPress 5.6+) and the Site Health integration (WordPress 5.2+) are only registered when available; everything else works through the polyfills.
Compatibility
- WordPress: 4.7 - 7.1
- PHP: 7.0 - 8.5
- WP-CLI: 2.3.0 - 2.12.0
Tests
- PHP Coding Standards: 3.13.6
- WordPress Coding Standards: 3.4.1
- PHPStan: 2.2.9 (level 9, 0 errors)
- PHPUnit: 9.6.36 (37 tests)
Downloads
- Saving the "Delete all plugin data on uninstall" preference no longer triggers a fatal error (
-
v5.1.2 Stable
released this
2026-08-07 10:46:22 +00:00 | 1 commits to main since this release[5.1.2] - 2026-08-07
Fixed
- Missing
load_plugin_textdomain()call caused a "Translation loading for thewpvulnerabilitydomain was triggered too early"_doing_it_wrong()notice on WordPress 6.7+. The textdomain is now explicitly loaded on theinithook.
Added
- WordPress Playground blueprint (
blueprint.json) with pre-installed vulnerable plugins and a theme for quick testing.
Changed
- Security vulnerability reporting link updated to ROBOTSTXT.
- Contributor repository link updated to git.robotstxt.es/ROBOTSTXT/wpvulnerability.
- The
readme.txtChangelog section now shows only the latest 3 versions; the full history remains inchangelog.txt.
Compatibility
- WordPress: 5.6 - 7.1
- PHP: 7.0 - 8.5
- WP-CLI: 2.3.0 - 2.12.0
Tests
- PHP Coding Standards: 3.13.5
- WordPress Coding Standards: 3.3.0
- PHPStan: 2.1.55 (level 9, 0 errors)
- PHPUnit: 9.6.34 (25 tests)
Downloads
- Missing
-
v5.1.1 Stable
released this
2026-07-09 06:29:00 +00:00 | 2 commits to main since this release[5.1.1] - 2026-07-09
Fixed
- Site Health: the memcached, Redis, and SQLite vulnerability tests always returned "Invalid software type" because those components were missing from the software list. They now run correctly.
- "Send test email" failed when no email recipients were configured: the forced-test path added the admin email but the send gate used a flag computed before the override. The test email now sends.
- "Run notification now" reported failure when only webhook channels (Slack/Teams/Discord/Telegram) were enabled and email was disabled. The notification result now reflects whether any channel delivered successfully.
- Weekly notification cron events were never auto-scheduled, because the
weeklycron schedule was registered only atinitwhile the on-load scheduling runs earlier. The weekly/daily schedule registration moved to the always-loaded scheduler so weekly notifications schedule correctly. - Deactivation deleted the per-component analysis settings (
wpvulnerability-analyze), so deactivating and reactivating reset which components were hidden. Analysis settings are now preserved on deactivation (only uninstall removes them). - The debug "Cron Status" panel always showed the notification event as "not scheduled" because it checked the wrong hook name (
wpvulnerability_send_notificationinstead ofwpvulnerability_notification). - The debug "last run" timestamp was always empty because it read a
wpvulnerability-logsoption that is never written; it now reads the most recent API log entry. - Redis detection called
close()twice on the success path (once in thetryblock, once infinally); the redundant close was removed. - The single-site vulnerable-themes count was hardcoded to
0instead of reading the stored option.
Changed
- Single-site email recipient sanitization now uses
is_email()for strict validation, matching the multisite behaviour. - Removed a redundant nonce field from the single-site "Reset Plugin" form (the form only submits the full-reset action).
- Removed dead code: the unused
wpvulnerability_sanitize_messagescallback and its setting registration, and an unused$tools_actionvariable in the multisite admin.
Downloads
-
v5.1.0 Stable
released this
2026-07-09 06:21:27 +00:00 | 3 commits to main since this release[5.1.0] - 2026-07-08
Security
wpvulnerability_validate_shell_command()now uses exactin_array()match instead ofstripos()substring matching for the shell-command allowlist (defense-in-depth).wpvulnerability_detect_php(),wpvulnerability_detect_curl(), andwpvulnerability_detect_webserver()now route throughwpvulnerability_safe_shell_exec(), so every software-detection shell call is validated and recorded in the Shell Execution Audit Log. Previously these calledshell_exec()directly, bypassing the wrapper and the audit log. As a side effect this also fixes nginx/angie version detection:escapeshellcmd()was escaping the2>&1redirect, so stderr (where nginx prints its version) was never captured.
Fixed
- Multisite uninstall fatal error:
Uncaught Error: Undefined constant "WPVULNERABILITY_PLUGIN_BASE"when "Delete all plugin data on uninstall" was enabled.uninstall.phpnow defines the constant before loadingwpvulnerability-run.php. WPVULNERABILITY_HIDE_*constants now stopshell_execdetection for hidden components during scheduled scans and in the admin "Software Detection Methods" panel. Previously they only hid the results from the UI, so the audit log kept filling with "command not found" entries for components the administrator had explicitly deactivated.wpvulnerability_detect_webserver()no longer shell-probes a hidden web server via the sibling path:WPVULNERABILITY_HIDE_NGINXandWPVULNERABILITY_HIDE_APACHEnow fully isolate the hidden server.- Multisite cron requests on non-main subsites no longer load all plugin module files. No WPVulnerability cron events are scheduled on subsites, so the extra loading was wasted work.
- LiteSpeed / OpenLiteSpeed / Caddy shell detection in the WP_DEBUG diagnostic panel now works: the commands no longer use
2>/dev/null(which the shell-command validator rejected),caddywas added to the allowlist, andwhichoutput is validated as a real path so "command not found" messages are not mistaken for a detection.
Changed
Network: trueadded to the plugin header to declare network-aware multisite behaviour.- Removed the unused
$plugin_statusparameter fromwpvulnerability_plugin_info_after(); the PHPCS suite now passes with zero warnings. - Multisite network dashboard: the "Site Health" footer link pointed to
wp-admin/network/site-health.php, which does not exist (Site Health is a per-site screen). It now links to the main site'swp-admin/site-health.php.
Downloads
-
v5.0.1 Stable
released this
2026-06-02 13:44:09 +00:00 | 4 commits to main since this release[5.0.1] - 2026-06-02
Fixed
wp_cache_flush()removed fromwpvulnerability_update_database_data()andwpvulnerability_reset_plugin_data(). The function was wiping the entire Object Cache (Redis, Memcached, APCu) on every plugin or theme update, causing CPU spikes and database overload on high-traffic sites. The targetedwpvulnerability_delete_transients()call that already runs before it invalidates all plugin-owned cache entries; a global flush was never necessary.wp_cache_flush()was called twice on plugin reset: once insidewpvulnerability_update_database_data()and once more immediately after inwpvulnerability_reset_plugin_data(). Both calls have been removed.
Downloads
-
v5.0.0 Stable
released this
2026-06-02 13:42:48 +00:00 | 5 commits to main since this release[5.0.0] - 2026-05-26 =
Added
- Vulnerability detail panels fully redesigned across all contexts (plugins, themes, core, server software, Site Health):
- Bootstrap-inspired score/severity badge colour-coded by severity level (Critical/High/Medium/Low/None).
- Source attribution pills: label is the hostname extracted from the source URL (e.g.
wordfence.com,nvd.nist.gov); uniform dark-grey#50575e; hover turns black/white; linked withrel="nofollow noopener noreferrer". - "References:" label and pills displayed on the same flex row.
- CVSS priority order: CVSS 4 → CVSS 3 → CVSS 2 → legacy CVSS. The highest available score and severity are always shown.
ssvc.exploitation:poc→ "⚡ Public exploit" badge;active→ merged into "⚠ Actively exploited".ssvc.automatable: yes→ "⚙ Automatable" badge.ssvc.kev_date→ date appended to "Actively exploited" (e.g. "⚠ Actively exploited · 2024-03-15").epss→ "EPSS X.X%" badge on the same row as the CVSS badge.- CVE description from
source[].descriptionshown for all vulnerability types;[en-US]/ language prefix stripped automatically. - CWE name and description shown in server software vulnerability details (was missing).
- Version range: leading
-/*stripped when there is no lower bound (e.g.- < 1.3.28→< 1.3.28). - Wording change: "affecting this version" → "affecting your installed version" (plugins, themes, core).
- Core vulnerabilities on
update-core.php: display rewritten to use the same two-column table with badges, description, CWE, and reference pills as plugin/theme rows (replaces the old plain table with score-only rows). - Theme details modal (single-site): vulnerability section injected after the Tags field. Uses
wp_prepare_themes_for_jsfilter to embed pre-rendered HTML and a JS template patch (admin_footer) to surface it inside the Underscore.js template. Shows version range, badges, description, and references — identical layout to plugin rows. - Helper functions added to
wpvulnerability-process.php:wpvulnerability_source_css_slug(),wpvulnerability_render_source_pills(),wpvulnerability_render_score_badge(),wpvulnerability_clean_version_range(),wpvulnerability_get_source_description(). - Helper functions added to
wpvulnerability-themes.php:wpvulnerability_theme_modal_html(),wpvulnerability_filter_prepare_themes_for_js(),wpvulnerability_theme_modal_template_patch(). - Vulnerability severity now uses the full-word value from
cvss3.severity("critical","high","medium","low","none") when available, falling back to the legacy single-charactercvss.severitycode.wpvulnerability_severity()accepts both formats. - Known Exploited Vulnerability (KEV) badge: when a vulnerability is listed in the CISA KEV catalog (
impact.ssvc.kev: truefor plugins/themes/core;impact.kev: truefor server software), a prominent warning is shown in the vulnerability detail panel. - Publication date displayed next to each source link in the vulnerability details table (
source[].datefield from the API). - Server software lifecycle status displayed in the vulnerability detail panel: a coloured dot shows whether the detected version is Supported or End of Life, together with the end-of-life date if available (
data.status,data.date_endfields from the API). - EOL badge shown in the dashboard software grid (PHP, Apache, nginx, MariaDB, MySQL, ImageMagick, curl, memcached, Redis, SQLite) when the detected version has reached end-of-life. Lifecycle data is fetched alongside vulnerability data during the scheduled scan and stored with the software option.
- REST API: all vulnerability endpoints now expose
uuid(unique vulnerability identifier),kev(boolean),ssvcblock (exploitation,automatable,technical_impact) for plugins/themes/core, andseverityfromcvss3when available. - About tab: new Intelligence Sources table showing how many vulnerabilities each source (CVE, EUVD, JVN, Patchstack, WPScan, Wordfence) contributes, broken down by Core / Plugins / Themes. Populated from the new
stats.vulnerabilities.{source}field in the API. - REST API: source entries now include a
datefield with the vulnerability publication date.
Security
wpvulnerability-adminms.php:wpvulnerability_process_network_config_forms()now requiresmanage_network_optionscapability (viacurrent_user_can()) in addition to the nonce check already present. Previously, a logged-in user who obtained a valid nonce could update plugin config and analysis options.- WP-CLI: all vulnerability commands (
core,plugins,themes,php,apache, …) now requiremanage_options(ormanage_network_optionson multisite). Commands abort with a clear error and--user=<admin_login>hint if the check fails. Enforces the same access model as the REST API endpoints. - WP-CLI: all config commands (
hide,email,cache,log-retention,period) now requiremanage_options/manage_network_optionsbefore modifying any WordPress option. - REST API permission check now passes strict mode (
true) tobase64_decode()when parsing the HTTP Basic Authorization header. Without this flag, PHP silently ignores illegal base64 characters; with it, a malformed or padding-stripped token is immediately rejected and returns an authentication failure instead of decoding unpredictable bytes. - Debug web server detection (LiteSpeed, OpenLiteSpeed, Caddy) now routes through the
wpvulnerability_safe_shell_exec()wrapper instead of callingshell_exec()directly. This ensures theWPVULNERABILITY_DISABLE_SHELL_EXECconstant, the security mode, the command whitelist, and audit logging are respected even whenWP_DEBUGis enabled.
Fixed
- Forced test email on a fresh install (no email address configured yet) no longer produces an
E_WARNINGon PHP 7.x or aTypeErroron PHP 8.x. The fallback now initialisesemailsas an array instead of appending to a potentially empty string. determine_locale()call in the About tab is now guarded byfunction_exists()instead of aversion_compare()check, which is more forward-compatible and correctly recognised by static analysis tools.preg_replace()return values (which can benullon error) in the HTML-to-plain-text converter are now handled safely, preventing a potentialTypeErroron corrupt input.DOMDocument::$documentElementnull check added in the HTML-to-plain-text converter; avoids a potential fatal error on malformed or empty HTML fragments.- JSON-encoded vulnerability count options are validated as strings before being passed to
json_decode(), preventing potential errors when a WordPress option returns an unexpected type. cron_schedulescallbacks (wpvulnerability_add_every_week,wpvulnerability_add_every_day) now usedid_action('init')guard before calling__(), eliminating the "Translation loading triggered too early" notice introduced in WordPress 6.7.- WP-CLI vulnerability commands (
core,plugins,themes,php, and all software components) now display a clear success message when no vulnerabilities are found, instead of an empty table. - WP-CLI
config period monthlynow returns a proper error message instead of silently treating the value asnever. Valid periods aredaily,weekly, andnever. uninstall.phpcreated. Plugin data is preserved by default on uninstall; a new "Delete all plugin data on uninstall" checkbox in the Tools settings tab allows opting in to full removal.- Large vulnerability data options are now stored with
autoload=false, preventing unnecessary loading of JSON blobs on every WordPress request.
Changed
- Minimum required PHP version updated from 5.6 to 7.0. The null coalescing operator (
??) introduced throughout the codebase for improved type safety requires PHP 7.0 or later. PHP 5.6 reached end-of-life in December 2018 and is no longer supported by any currently maintained WordPress version. - Minimum required WordPress version updated from 4.7 to 5.6. This enables simplification of backward-compatibility code paths and full use of Application Passwords,
wp_timezone(),wp_date(),determine_locale(), and$wpdb->db_server_info()without version guards. - Removed
wp_doing_cron()polyfill — the function has been available since WordPress 4.8 and is guaranteed at the new minimum. - Application Passwords authentication in the REST API no longer requires a
function_exists('wp_is_application_passwords_available')guard — Application Passwords are always available at WordPress 5.6. - Removed fallback code paths for
wp_timezone()(WordPress 5.3),wp_date()(WordPress 5.3), anddetermine_locale()(WordPress 5.0). wpvulnerability_get_vulnerabilities()now stores theimpactfield in each matched vulnerability array entry, enabling KEV and severity display for all component types.wpvulnerability_get_fresh_vulnerabilities()(software.php) now stores lifecycle metadata (name,status,date_start,date_end) in the software option alongsidevulnerabilitiesandvulnerable. The transient is explicitly cleared before the refresh to guarantee a fresh API call.wpvulnerability_get_cron_snapshot()now uses only public WordPress Cron API functions (wp_next_scheduled(),wp_get_schedule()) instead of the private_get_cron_array(). The function iterates over the known plugin hooks (defined inwpvulnerability_get_plugin_cron_hooks()) rather than scanning the full cron array. Duplicate-instance detection is no longer performed.wpvulnerability_get_plugin(),wpvulnerability_get_theme(),wpvulnerability_get_core(), andwpvulnerability_get_vulnerabilities()now store theuuidfield in each vulnerability entry.
Developer
- Full PHPStan level 9 compliance achieved across all 17 PHP files: 1,092 pre-existing type errors resolved; analysis now passes clean with zero errors and an empty baseline.
- Added development tooling:
composer.jsonwith all dev dependencies,phpstan.neon(level 9),phpcs.xml(WordPress standards),phpunit.xml.dist,bin/deploy.sh, anddocs/directory. - Added 18 PHPUnit plugin header tests verifying consistency between
wpvulnerability.phpandreadme.txt. - WordPress API stubs updated to v7.0.0 for PHPStan analysis. Added
johnbillion/wp-compatextension for WordPress version compatibility analysis. - Added internal helpers
wpvulnerability_get_component_count()andwpvulnerability_get_config()to centralise typed access to cached vulnerability counts and plugin configuration. - Fixed 10 WordPress version compatibility findings reported by
wp-compat:wp_date(),determine_locale(),wp_authenticate_application_password(),after_core_auto_updates_settingshook,site_status_testsfilter, and others.
Compatibility
- WordPress: 5.6 - 7.1
- PHP: 7.0 - 8.5
- WP-CLI: 2.3.0 - 2.12.0
Tests
- PHP Coding Standards: 3.13.5
- WordPress Coding Standards: 3.3.0
- PHPStan: 2.1.55 (level 9, 0 errors)
- PHPUnit: 9.6.34 (18 tests)
- Plugin Check (PCP): 1.8.0
Downloads
- Vulnerability detail panels fully redesigned across all contexts (plugins, themes, core, server software, Site Health):