# Changelog - Vulnity Security

## [1.3.5] - 2026-06-04

### Added
- Added WP-Cron diagnostics in the WordPress admin for missing, stale, disabled, or fallback-only heartbeat scheduling.
- Added a throttled runtime heartbeat fallback from admin/site traffic for hosts where WP-Cron is disabled or unreliable.
- Added WP-Cron setup documentation guidance for stable external cron configuration.

## [1.3.4] - 2026-06-01

### Fixed
- Hardened the hidden login URL feature so direct unauthenticated access to wp-login.php and wp-admin returns 404 while the configured custom login slug remains usable on Apache and nginx/PHP-FPM setups.
- Fixed custom login URL generation so WordPress login links point to the Vulnity login entrypoint instead of returning an empty login URL.
- Reduced malicious upload false positives so the PHP upload alert only fires for PHP-like uploads with suspicious PHP indicators, not normal media such as PNG files.

## [1.3.0] - 2026-05-10

### Changed
- Bumped plugin version from 1.2.3 to 1.3.0.
- Updated `readme.txt` Stable tag from 1.2.3 to 1.3.0.
- WordPress Multisite activation is blocked explicitly in 1.3.0 to avoid unsafe cross-blog configuration, storage, cron, or uninstall behavior.
- Minimum supported WordPress version is now 6.2; older versions are blocked fail-safe during activation/runtime.

## [1.2.3] - 2026-03-31

### Stability & Compatibility — Critical Fixes from Production Audit

#### Fixed
- **Firewall bootstrap blocks admin recovery paths:** Blocked IPs could not access `wp-login.php`, `wp-cron.php`, `admin-ajax.php`, or `xmlrpc.php`, making it impossible for admins to recover access. Added path-based exemptions before the block page renders.
- **Firewall bootstrap returns HTML for REST API:** Blocked IPs hitting `/wp-json/` received an HTML 403 page instead of JSON, crashing mobile apps and API integrations. Now returns `{"code":"ip_blocked","message":"Access denied by Vulnity Firewall","data":{"status":403}}`.
- **Uninstall leaves broken `.htaccess` on read-only filesystems:** If `.htaccess` was not writable during uninstall, the `auto_prepend_file` directive pointed to a deleted `bootstrap.php`, causing HTTP 500 on all requests. Now detects failed cleanup and creates a safe no-op stub.
- **Early IP blocking intercepts AJAX and REST requests:** `early_blocking_check()` at `plugins_loaded` priority 0 had no exemptions for `DOING_AJAX` or `REST_REQUEST`, returning HTML block pages instead of JSON and breaking the admin panel for blocked IPs.
- **`request_targets_file()` false positives:** The file detection method used a simple dot-presence check, incorrectly treating directories with dots in their names as files. Now strips query strings, checks trailing slashes, and validates against a proper file extension regex.

#### Changed
- **SIEM alert timeout reduced from 10s to 3s:** Prevents page hangs when the SIEM endpoint is slow or unreachable during attacks. Retry mechanism handles any resulting timeouts.
- **Inventory sync timeout reduced from 30s to 8s:** Prevents random 30-second page loads for visitors who trigger WordPress pseudo-cron.
- **SIEM alert redirections reduced from 5 to 2:** Limits redirect chains to reduce total blocking time.
- **Nginx config snippet now blocks PHP execution in uploads:** Added `location ~* ^/wp-content/uploads/.*\.php$ { return 403; }` to prevent uploaded webshell execution.
- **`.htaccess` common paths rules now include `Options -Indexes`:** Added as defense-in-depth alongside the existing `RewriteRule`.

#### Added
- **Expanded REST API public route whitelist:** Added WooCommerce REST v3, UpdraftPlus, BackWPup, Elementor, Forminator, FluentForms, SureCart, MailPoet, and WordPress block editor endpoints. All prefixes made more specific (e.g. `/contact-form-7/v1/` instead of `/contact-form-7/`).

#### Coding Standards
- Updated `readme.txt` Stable tag from 1.2.2 to 1.2.3.

---

## [1.2.2] - 2026-03-19

### Auto-Update System — Bug Fixes & SIEM Bidirectionality

#### Fixed
- **Anti-collapse dedup blocking second toggle:** `generate_hash()` produced the same hash for all `auto_update_state_changed` events because those events carry no `ip`, `user_id` or `action` fields. Hash now includes plugin/theme toggle state (`:p=0/1:t=0/1`), making each combination distinct.
- **`/real-time-alerts` auth failure:** Endpoint requires HMAC-SHA256 (`x-signature` + `x-site-id` + `x-plugin-version`) but plugin was sending `x-vulnity-token`. `send_alert()` now selects headers based on target endpoint.
- **Missing `remediation` field:** SIEM canonical schema requires `remediation.summary` and `remediation.steps`. Added to `send_auto_update_state_event()`.
- **`version_old` missing from auto-update events:** By `upgrader_process_complete` files are already replaced, making the old version unrecoverable. Fixed by hooking `upgrader_pre_install` to capture the version before WP overwrites plugin/theme files.
- **Updates re-triggered when disabling auto-update:** `ajax_save_auto_update()` was running `apply_push_trigger_update()` whenever at least one type was ON, including when disabling. Now reads previous state first and only triggers for types that are *newly* being enabled.
- **`wp_doing_cron()` too restrictive:** Check prevented auto-update alerts when `wp_maybe_auto_update()` was invoked outside a standard cron context (e.g. via `wp eval`). Replaced with `$upgrader instanceof WP_Automatic_Updater`, which correctly identifies WP's native updater in all contexts.
- **Single-file plugin slug resolving to `.`:** `dirname('hello-dolly.php')` returns `'.'`, breaking slug-based lookups. Fixed with `basename($file, '.php')` fallback in both `apply_push_trigger_update()` and `on_auto_update_complete()`.

#### Added
- **`triggered_by` field:** Distinguishes `siem_manual` (SIEM explicit request), `siem_auto_update` (triggered by enabling auto-update), and `wp_auto_updater` (WordPress native cron updater) in manual-update and auto-update events.

#### Changed
- **Auto-update toggles are now read-only in the admin panel.** An info banner redirects administrators to the SIEM (Sistema section) to enable or disable auto-updates, preventing state divergence between WP admin and the SIEM.

#### Coding Standards
- Replaced `parse_url()` with `wp_parse_url()` across `class-core.php` and `class-auto-update-alert.php`.
- Added `phpcs:disable/enable` comment for nonce verification in `ajax_save_auto_update()` (nonce already verified via `verify_admin_ajax_request()`).
- Updated `readme.txt` Stable tag from 1.2.1 to 1.2.2.

---

## [1.2.1] - 2026-03-09

### Maintenance Release
- **Changed:** Version bump to 1.2.1.
- **Improved:** Plugin Check compatibility for filesystem and nonce-related warnings.
- **Improved:** Runtime validation of scanner detection, file editor monitoring, and firewall state serialization.

## [1.2.0] - 2026-03-06

### Improvements & Fixes
- **Fixed:** Login URL rename now validates the chosen slug against existing WordPress pages/posts before saving, preventing rewrite rule conflicts.
- **Fixed:** Login URL rename now blocks reserved WordPress routes (`wp-admin`, `wp-json`, `wp-login`, `admin`, `login`, etc.) as login slug candidates.
- **Fixed:** `vulnity_suppress_blocked_alerts` option added to the explicit uninstall cleanup list.
- **Fixed:** Uninstall now uses `wp_unschedule_hook()` instead of `wp_clear_scheduled_hook()` for consistent and complete cron cleanup, matching the deactivation behavior.
- **Fixed:** Heartbeat, mitigation sync, retry queue and alert buffer crons are now cancelled on disconnect (both manual unpair and remote disconnect), preventing unnecessary scheduled tasks while the plugin is unpaired.

## [1.1.8] - 2026-02-12

### Fix Wrning error
- **Fixed:** Warning message was displayed on every load; now it is shown only once.

## [1.1.7] - 2026-02-12

### Deactivation & Cleanup Fixes
- **Fixed:** 4 missing cron hooks not cleared on deactivation (`vulnity_sync_mitigation_config`, `vulnity_cleanup_flood_data`, `vulnity_process_brute_force_windows`, `vulnity_triggered_inventory_sync`)
- **Fixed:** Cron events re-scheduled by late-firing alert hooks (e.g. plugin-change alerts triggering inventory sync) now cleared via `final_deactivation_cleanup` at priority 9999
- **Fixed:** Replaced `wp_clear_scheduled_hook` with `wp_unschedule_hook` to properly clear single events with arguments
- **Fixed:** `.htaccess` marker removal now has native PHP fallback when WP_Filesystem is unavailable during deactivation
- **Fixed:** Plugin Check error — replaced direct `is_writable()` call with `vulnity_path_is_writable()` and `WP_Filesystem_Direct`

## [1.1.6] - 2026-02-11

### 🔴 Critical Bug Fixes

#### Race Conditions & Concurrency
- **Fixed:** Race condition in log rotation that could cause data loss when multiple processes rotate logs simultaneously
  - Added atomic file locking with `flock(LOCK_EX | LOCK_NB)`
  - Implemented double-check pattern after lock acquisition
  - Files: `vulnity.php:471-518`

- **Fixed:** Race condition in `save_local_alert()` that could lose critical alerts
  - Implemented transient-based locking with 10s timeout
  - Added try-finally block to ensure lock release
  - Files: `includes/alerts/class-alert-base.php:138-177`

#### Memory Exhaustion
- **Fixed:** Memory exhaustion when counting lines in large log files (100MB+)
  - Replaced full file loading with streaming using `fgets()`
  - Now processes files line-by-line without loading into RAM
  - Files: `vulnity.php:425-448`

#### Stack Overflow & Performance
- **Fixed:** Recursive retry logic with blocking `sleep()` causing stack overflow and timeouts (up to 75s)
  - Converted recursive function to iterative loop
  - Removed blocking `sleep()` calls
  - Delegated retries to asynchronous cron jobs
  - Files: `includes/alerts/class-alert-base.php:153-186`

- **Fixed:** Fatal error when calling `wp_get_theme()->get('Name')` on missing theme
  - Created safe helper method `get_safe_theme_name()` with validation
  - Returns 'Unknown' instead of crashing
  - Files: `includes/class-security-monitor.php:510-521`

### 🟠 Security Improvements

#### Input Sanitization (Plugin Check Compliance)
- **Added:** Global helper function `vulnity_get_server_var()` using `filter_input(INPUT_SERVER)`
  - Complies with WordPress Plugin Check standards
  - Includes fallback for CLI/test environments
  - Files: `vulnity.php:533-579`

- **Improved:** Replaced 15+ direct `$_SERVER` accesses with sanitized helper
  - `includes/alerts/class-alert-base.php` - 6 locations
  - `includes/class-static-security.php` - 5 locations
  - `includes/alerts/class-file-editor-alert.php` - 2 locations
  - `includes/alerts/class-suspicious-query-alert.php` - 2 locations

#### Code Quality
- **Fixed:** Weak comparison (`==`) changed to strict comparison (`===`)
  - Files: `includes/class-anti-collapse.php:114`

### 🔵 Apache/Nginx Compatibility

#### Server Detection & Configuration
- **Added:** Server type detection (`detect_server_type()`)
  - Detects Apache, Nginx, LiteSpeed, or Unknown
  - Files: `includes/class-static-security.php`

- **Added:** Nginx configuration snippet generator (`get_nginx_config_snippet()`)
  - Dynamically generates Nginx config based on active features
  - Includes login URL rewriting, path protection, firewall bootstrap, and log protection
  - Files: `includes/class-static-security.php`

- **Added:** New admin view for server configuration
  - Auto-detects server type and shows appropriate instructions
  - Copy-to-clipboard functionality for Nginx config
  - Step-by-step installation guide
  - Files: `views/admin-server-config.php` (NEW)

#### PHP-Only Protection Fallback
- **Improved:** Enhanced `protect_common_paths()` with universal PHP fallback
  - Always protects Vulnity logs directory (`/wp-content/uploads/vulnity-logs/`)
  - Always protects firewall data directory (`/wp-content/vulnity-firewall/`)
  - Works on all servers (Apache, Nginx, LiteSpeed, etc.)
  - Files: `includes/class-static-security.php:777-821`

### 🟡 Internationalization (i18n)

- **Added:** Translation support for admin dashboard
  - 20+ strings wrapped in `__()`, `esc_html__()` functions
  - Files: `views/admin-dashboard.php`

- **Added:** Complete i18n support for server configuration view
  - 100% translatable with proper text domain
  - Files: `views/admin-server-config.php`

### ⚡ Performance Optimizations

- **Added:** Performance limit in alert processing
  - Limited to last 200 alerts to prevent timeouts
  - Prevents memory exhaustion with large alert history
  - Files: `includes/class-mitigation-manager.php:735-738`

---

## Technical Details

### Files Modified (10)
1. `vulnity.php` - Core functions and helpers
2. `includes/alerts/class-alert-base.php` - Alert system improvements
3. `includes/class-security-monitor.php` - Safe theme detection
4. `includes/class-anti-collapse.php` - Strict comparisons
5. `includes/class-static-security.php` - Nginx support + hardening
6. `includes/class-mitigation-manager.php` - Performance limits
7. `includes/alerts/class-file-editor-alert.php` - Input sanitization
8. `includes/alerts/class-suspicious-query-alert.php` - Input sanitization
9. `views/admin-dashboard.php` - Internationalization
10. `views/admin-server-config.php` - **NEW FILE**

### New Functions & Methods
- `vulnity_get_server_var()` - Global helper for sanitized `$_SERVER` access
- `Vulnity_Static_Security::detect_server_type()` - Server detection
- `Vulnity_Static_Security::get_nginx_config_snippet()` - Nginx config generator
- `Vulnity_Static_Security::get_apache_config_info()` - Apache info
- `Vulnity_Security_Monitor::get_safe_theme_name()` - Safe theme name retrieval

### Statistics
- **Lines Modified:** ~500
- **Lines Added:** ~350
- **Bugs Fixed:** 8 critical + 7 high priority
- **Security Issues:** 15+ locations sanitized
- **New Features:** 4 (server detection, config generator, PHP fallback, new admin view)

---

## Upgrade Notes

### Breaking Changes
None. This is a backward-compatible release.

### Action Required for Nginx Users
If you're running Nginx, visit **Settings > Vulnity > Server Configuration** to get your custom configuration snippet and installation instructions.

### Recommendations
1. If using Nginx, configure server-level rules for optimal security
2. Review new server configuration page at **Settings > Vulnity > Server Configuration**
3. Test alert generation to verify lock improvements work correctly

---

## Previous Releases

### [1.1.5] - Previous version
- Initial SIEM integration features
- Basic alert system
- Login URL renaming
- Common paths protection

---

**Full Changelog:** https://github.com/vulnity/vulnity-wp-plugin/compare/1.1.5...1.1.6
