| Version | Supported |
|---|---|
| 0.6.x | ✅ (current) |
| 0.5.x | ✅ |
| 0.4.x | ✅ |
| < 0.4 | ❌ |
Security is a top priority for Ops Health Dashboard. If you discover a vulnerability, please report it responsibly.
Do not open a public GitHub issue for security vulnerabilities.
- GitHub Security Advisory (preferred): https://github.com/mab056/ops-health-dashboard/security/advisories/new
- Email:
info@mattiabondrano.dev
- Vulnerability type (e.g. XSS, SQL injection, SSRF, information disclosure)
- Full source file paths involved
- Reproduction steps
- Proof of concept/exploit (if available)
- Potential impact
- Acknowledgement: within 48 hours
- Initial assessment: within 7 days
- Fix and release: within 30 days after confirmation
- Capability checks: all admin pages require
manage_options - CSRF protection: nonce checks on all forms/POST actions (
ops_health_admin_action,ops_health_alert_settings) - PRG pattern (Post-Redirect-Get) to prevent duplicate submissions (HealthScreen + AlertSettings)
- Input sanitization:
sanitize_text_field(),sanitize_email(),esc_url_raw(),absint() - Output escaping:
esc_html(),esc_attr(),esc_url() - Parameterized DB queries via
$wpdb->prepare()where applicable
- Central redaction service with 11 automatic sanitization patterns applied to all diagnostic outputs
- Database credentials (DB_PASSWORD, DB_USER, DB_NAME, DB_HOST)
- WordPress salts and security keys
- API keys, secrets, tokens, bearer
- Passwords in URLs and generic fields
- Email addresses, IPv4, IPv6
- Filesystem paths (ABSPATH, WP_CONTENT_DIR, home directory)
DatabaseCheck: no host/database name exposure in resultsErrorLogCheck: log samples redacted before inclusion; raw paths not exposedRedisCheck: host and error messages redacted via RedactionInterface
- Symlink rejection for log files (directory traversal mitigation)
- Read-size limit (512KB max) to avoid excessive memory usage
- Shared lock with
flock(LOCK_SH)for safe concurrent log access
All outbound alerting HTTP requests (Webhook, Slack, Telegram, WhatsApp) go through HttpClient with:
- Strict scheme allowlist (
http/httpsonly) - Private/reserved IP blocking (RFC 1918: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16; loopback 127.0.0.0/8; link-local 169.254.0.0/16; unspecified 0.0.0.0)
- IPv6 safe-fail rejection (because
gethostbyname()returns IPv4 only) - DNS validation: hostname resolution and verification that the resolved IP is not private (DNS rebinding prevention)
- DNS pinning via
CURLOPT_RESOLVEthroughhttp_api_curlaction, forcing cURL to use the already-validated IP (prevents TOCTOU/DNS rebinding between validation and actual request) - Port restrictions (80/443 only)
- Redirect disabled (
redirection => 0onwp_remote_post()) - 2xx-only success validation
- Timeout set to 5 seconds
- Protected
resolve_host(): wrapsgethostbyname()for testability via partial mock
Implemented in src/Services/HttpClient.php via HttpClientInterface.
TelegramChannel:htmlspecialchars()on interpolated valuesSlackChannel: mrkdwn escaping for user-controlled valuesEmailChannel: recipient validation withis_email()WhatsAppChannel: E.164 phone validation (/^\+[1-9]\d{6,14}$/)WebhookChannel: optional HMAC SHA-256 signature viaX-OpsHealth-Signatureheader (body pre-serialized to avoid signature discrepancies)AlertSettings: tokens and secrets usetype="password"+autocomplete="off",value=""+placeholder="********"(credentials never present in the DOM source)AlertManager: cooldown set before dispatch, per-channel isolation viatry/catch \ThrowableScheduler: wrapsalert_manager->process()incatch (\Throwable)for cron resilience
- Single-site: removes plugin options, cron hooks, fixed transients, and dynamic cooldown transients
- Multisite: iterates every site with
switch_to_blog()/restore_current_blog()and applies full cleanup - Dynamic cooldown transient cleanup via
$wpdbLIKE query (ops_health_alert_cooldown_*) WP_UNINSTALL_PLUGINguard inuninstall.php- Multisite fallback path in
uninstall.phpwithout autoloader
- No singleton pattern
- No static methods in business logic
- Constructor dependency injection for explicit, auditable dependencies
- Source code in
src/ - Configuration in
config/bootstrap.php - Uninstall logic in
uninstall.php - Build/distribution scripts in
bin/ - Main plugin bootstrap file
ops-health-dashboard.php
- WordPress core vulnerabilities
- Third-party themes/plugins
- Web server configuration (Apache/Nginx)
- PHP/MySQL runtime configuration
- Dev dependencies in
vendor/
Each release must pass:
- PHPCS (WordPress Coding Standards): clean
- PHPStan level 6: zero errors
- Pattern-enforcement tests (no singleton/static/final violations)
- Test matrix across supported PHP versions
- Code review before merge
Thank you to everyone who reports vulnerabilities responsibly. Security researchers who help improve Ops Health Dashboard may be acknowledged here (with consent).