Skip to content

Security: initMAX/zabbix-mcp-server

Security

SECURITY.md

Security Policy

Reporting a Vulnerability

If you discover a security vulnerability in Zabbix MCP Server, please report it responsibly.

Do not open a public GitHub issue for security vulnerabilities.

Instead, contact us directly:

  • Email: info@initmax.com
  • Subject: [SECURITY] Zabbix MCP Server — <brief description>

We will acknowledge your report within 48 hours and work with you on a fix.

Security Considerations

MCP Token Authentication

  • Multi-token support via [tokens.*] sections in config.toml — each token is a named entry with independent permissions
  • Tokens stored as SHA-256 hashes — raw tokens shown only once at creation, never stored
  • Scopes — restrict which tool groups a token can access (e.g. monitoring, alerts)
  • Server binding — restrict which Zabbix servers a token can reach (allowed_servers)
  • IP allowlist — restrict token usage to specific IPs or CIDR ranges (allowed_ips)
  • Expiry — set expires_at (ISO 8601) for automatic token expiration
  • Read-only flag — per-token write protection independent of server-level read_only
  • Revocation — tokens can be revoked instantly via the admin portal; revoked tokens are rejected immediately
  • Legacy auth_token automatically migrated to [tokens.legacy] on first v1.16 start

Zabbix API Tokens

  • Zabbix API tokens stored in config.toml should be protected with file permissions (chmod 600)
  • The install script sets these permissions automatically — config directory is chmod 750
  • Use environment variable references (${ENV_VAR}) to avoid storing tokens in plain text
  • Tokens inherit the permissions of the Zabbix user they belong to — use the principle of least privilege

Admin Portal Security

  • Session-based authentication with scrypt password hashing (n=16384, r=8, p=1)
  • Session cookies: HttpOnly, SameSite=Strict, Secure (on HTTPS) - prevents XSS and CSRF
  • Login rate limiting: 5 attempts per 5 minutes per IP, 30-second lockout
  • POST rate limiting: 30 requests per minute per session
  • Password policy: minimum 10 characters, at least one uppercase letter and one digit
  • Role-based access control: admin (full), operator (tokens/templates), viewer (read-only)
  • Jinja2 autoescape enabled on all templates - prevents XSS
  • Config write-back uses atomic file operations with threading.RLock

OAuth 2.1 Authorization Server (v1.28+)

  • Authorization Code grant + PKCE S256 (mandatory; non-PKCE clients refused at startup)
  • RFC 8707 audience binding: every issued access token's aud is bound to [server].public_url; tokens issued for one MCP deployment cannot be replayed against another
  • Dynamic client registration (RFC 7591) - off via [oauth].dynamic_registration_enabled = false if you do not want untrusted callers registering clients
  • Login rate limit on /oauth/login: 5 failed attempts per IP per 5-minute rolling window (parity with admin portal /login)
  • Login uses the existing [admin.users.*] table (scrypt-hashed) - no second identity store
  • Authorization codes are one-shot, 10-minute TTL, in-memory
  • Refresh tokens rotated on each use (OAuth 2.1 §4.3.1)
  • Issuer URL must be HTTPS for non-localhost bindings (RFC 8414); the framework refuses to start otherwise
  • Full setup walkthrough including reverse-proxy patterns (Apache, Nginx, Caddy) in docs/OAUTH.md

Network Security

  • The server binds to 127.0.0.1 (localhost) by default — not accessible from the network
  • If you bind to 0.0.0.0, always configure MCP token authentication to protect the endpoint
  • Native TLS support — set tls_cert_file and tls_key_file in config, or use a reverse proxy (nginx, Caddy)
  • IP allowlist — set allowed_hosts to restrict access to specific IPs or CIDR ranges
  • CORS control — set cors_origins to restrict which web origins may access the server; omit to disable CORS entirely
  • The rate_limit config option protects the Zabbix API from being overwhelmed (default: 300 calls/minute per client)
  • SSRF prevention — server test endpoint validates URL scheme and resolves DNS to block private/loopback/reserved IPs

Origin / Host validation (DNS rebinding protection)

Per the MCP 2025-11-25 spec, the server can reject requests whose Origin or Host header does not match the operator-declared allowlist (returns HTTP 403 / 421 respectively). This blocks DNS rebinding attacks against an MCP endpoint reachable from a browser context.

Recommended minimum configuration for production: set [server].public_url to the externally-reachable URL of the server, e.g.

[server]
public_url = "https://mcp.example.com"

The host (mcp.example.com) is auto-added to the Host allowlist, the origin (https://mcp.example.com) to the Origin allowlist, and DNS-rebinding protection flips on. No further config needed for the typical reverse-proxy deployment.

For additional origins (e.g. an internal admin dashboard at a different URL), populate [server].allowed_origins:

allowed_origins = ["https://app.example.com", "https://office.example.com:*"]

When public_url, allowed_origins, and allowed_hosts are all unset on a non-localhost bind, protection stays off (backwards compat) and the server logs a startup warning pointing here.

Read-Only Mode

  • Servers are configured as read_only = true by default
  • This blocks all write operations (create, update, delete, execute) at the MCP server level, including via the zabbix_raw_api_call tool
  • Per-token read_only flag provides additional write protection
  • Two-step action approval (action_prepare + action_confirm) for write operations — 5-minute confirmation window
  • Set read_only = false only on servers where you explicitly need write access

File Access and Uploads

  • The source_file feature (for configuration.import) is disabled by default
  • To enable it, configure allowed_import_dirs with specific directories from which files may be read
  • Path traversal is blocked — only files within configured directories are accessible, validated with Path.is_relative_to()
  • SVG uploads sanitized: script tags, event handlers, javascript: URLs, and dangerous data URIs stripped
  • TLS private keys saved with 0600 permissions; TLS directory 0750
  • Report template preview uses SandboxedEnvironment — prevents server-side template injection (SSTI)

Audit Logging

  • All admin portal actions logged to /var/log/zabbix-mcp/audit.log (JSON lines)
  • Tracked actions: login, logout, token CRUD, user CRUD, server CRUD, settings changes, uploads
  • Log rotation at 50 MB with backup scheme
  • Audit log viewable and exportable (CSV) via admin portal

Supported Versions

Version Supported
1.31 (latest) Yes
1.30 Yes
1.29 Yes
1.28 Yes
1.27 Yes
1.26 Yes
1.25 Yes
1.24 Yes
< 1.24 No

There aren't any published security advisories