Skip to content

v4.3.0 — Production hardening

Latest

Choose a tag to compare

@alokemajumder alokemajumder released this 06 Aug 19:22
· 39 commits to main since this release

Wazuh MCP Server v4.3.0 is a production-hardening release. It ships the MCP 2026-07-28 dual-era protocol, multi-cluster support, and published container images from the previous development cycle, and resolves every blocker and high-severity finding from a full four-workstream audit (security, Wazuh API correctness, MCP/resilience, testing & production readiness).

The test suite grew from 112 to 197 tests, with a branch-coverage floor now enforced in CI.

Important

Three previously-intended behaviors are now enforced. See UPGRADING.md before upgrading a production deployment: RBAC is fail-closed (write is opt-in), AUTH_SECRET_KEY is required in production, and alert/vulnerability tools require the Wazuh Indexer.

🔒 Security

  • Credential redaction now actually runs. The log sanitizer was attached to the root logger, whose filters are skipped for records propagating up from child loggers — so passwords and tokens from the API clients and auth layer were written to logs in cleartext. It now attaches to the emitting handlers, and additionally redacts URL-embedded credentials and the token after an Authorization: label.
  • OAuth authorization-server hardening. Requested scope is bound to the client's registered scope (a read-only client can no longer self-grant wazuh:write); confidential clients must present their secret at the token endpoint; the issuer URL only trusts x-forwarded-* from TRUSTED_PROXIES (closing discovery poisoning); and authorization responses now carry the RFC 9207 iss parameter.
  • Fail-closed tool scope. A tool that isn't explicitly read-scoped — or whose name matches a destructive verb — now requires wazuh:write, so a future write tool can't silently be invokable by a read-only token.
  • DoS hardening. JSON nesting-depth cap (deeply-nested bodies previously raised an unhandled RecursionError → 500), rate-limiter keyed on the authenticated principal + trusted-proxy IP (a single client behind the reverse proxy could previously lock out everyone), sliding-window backoff, and injection-safe indexer search (simple_query_string replaces the Lucene-injectable query_string).
  • Security boundary is now tested. The recommended OAuth mode (PKCE, single-use codes, refresh rotation, revocation, DCR) has a dedicated suite, and every one of the 14 write tools is verified denied to a read-only token, with the destructive-op audit record asserted.

🛠️ Reliability & correctness

  • Circuit-breaker deadlock fixed. A half-open recovery trial that raised an unmonitored exception (routine on a 4xx / invalid-JSON response) or hit a 429 left the breaker stuck HALF_OPEN with its single-trial gate set — so every later call returned HTTP 503 until the process restarted, bricking all Wazuh tools on that client. The trial now always releases the gate and re-arms.
  • Active-response & ISO 27001 correctness against stock Wazuh. The generic wazuh_active_response tool (validator rejected the ! the allowlist required) now works; wazuh_firewall_allow/wazuh_host_allow no longer silently re-block an address — they require an operator-deployed undo script (WAZUH_AR_FIREWALL_UNDO_COMMAND / WAZUH_AR_HOSTDENY_UNDO_COMMAND) and refuse otherwise; disable_user sets alert.data.dstuser; check_file_quarantine uses GET /syscheck/{agent_id}; search_wazuh_manager_logs uses search=. ISO A.8.15 now reads the correctly-nested analysisd stats (it always scored 0 before), and an Indexer outage no longer scores A.8.8 as perfect compliance.
  • MCP dual-era routing. A legacy client whose _meta carried a legacy protocol version is no longer hijacked onto the modern stateless path (which rejected it with a self-contradictory UnsupportedProtocolVersionError and livelocked the retry).
  • Liveness vs readiness. /health is now a pure liveness probe (200 while the process is up); dependency checks moved to a new /ready, so a Wazuh outage no longer fails the container healthcheck and restart-loops a live server.
  • Agent IDs are normalized to Wazuh's zero-padded form (1001), so an exact-match term no longer silently returns nothing.

📈 Observability

  • Previously-dead Prometheus metrics (auth attempts, rate-limit hits, session lifecycle) are now wired.
  • New JSON log format (LOG_FORMAT=json) renders correlation IDs and structured fields that the default formatter silently dropped.

🚀 Platform (from this development cycle)

  • MCP 2026-07-28 dual-era protocol — modern stateless requests (server/discover, per-request _meta, Mcp-Method/Mcp-Name header validation, resultType, cache hints) alongside the legacy initialize handshake for clients on 2024-11-05 through 2025-11-25.
  • Multi-cluster support (opt-in) with OpenSearch Cross-Cluster Search routing.
  • Published multi-arch container images on GHCR.
  • Wazuh 4.8.0 – 4.14.7 compatibility.

📦 Install

docker pull ghcr.io/gensecaihq/wazuh-mcp-server:4.3.0
# or: docker pull ghcr.io/gensecaihq/wazuh-mcp-server:latest

Full details in CHANGELOG.md · Upgrade notes in UPGRADING.md.