Skip to content

Security: enuno/unifi-mcp-server

SECURITY.md

Security Policy

Supported Versions

We release patches for security vulnerabilities in the following versions:

Version Supported
0.1.x
< 0.1

Note: As this project is in early development (pre-1.0), we recommend always using the latest version.

Reporting a Vulnerability

We take the security of the UniFi MCP Server seriously. If you believe you have found a security vulnerability, please report it to us as described below.

Please DO NOT

  • Open a public GitHub issue for security vulnerabilities
  • Disclose the vulnerability publicly before it has been addressed
  • Exploit the vulnerability beyond the minimum necessary to demonstrate the issue

Please DO

Report security vulnerabilities via GitHub Security Advisories:

  1. Go to the repository's Security tab
  2. Click "Report a vulnerability"
  3. Fill out the vulnerability report form with as much detail as possible

Alternatively, you can email the maintainers directly at:

What to Include in Your Report

Please include the following information in your report:

  • Description: A clear description of the vulnerability
  • Impact: What an attacker could achieve by exploiting this vulnerability
  • Reproduction Steps: Step-by-step instructions to reproduce the vulnerability
  • Affected Versions: Which versions of the project are affected
  • Suggested Fix: If you have suggestions for how to fix the vulnerability, please include them
  • Your Contact Information: So we can follow up with questions if needed

Example Report

**Vulnerability Type:** API Key Exposure

**Description:**
The application logs UniFi API keys in plain text when debug
logging is enabled, potentially exposing sensitive authentication information.

**Impact:**
An attacker with access to log files could retrieve the UniFi API key
and gain unauthorized access to the UniFi Cloud API and network infrastructure.

**Reproduction Steps:**
1. Enable debug logging in the configuration
2. Start the MCP server
3. Examine the log output - API key appears in plain text

**Affected Versions:** 0.1.0 - 0.1.3

**Suggested Fix:**
Implement API key masking in the logging module to redact sensitive
information before writing to logs. Show only first 8 characters or use
placeholder text like "API key: ********".

Response Timeline

We aim to respond to security vulnerability reports according to the following timeline:

  • Initial Response: Within 48 hours of receiving the report
  • Vulnerability Assessment: Within 7 days, we will provide an assessment of the vulnerability
  • Fix Development: Critical vulnerabilities will be addressed within 30 days
  • Public Disclosure: After a fix is released and users have had time to update (typically 7-14 days)

Security Best Practices for Contributors

Credential Management

NEVER commit credentials or secrets to the repository:

  • UniFi API keys (primary authentication method)
  • Passwords
  • Private keys
  • Certificates
  • OAuth tokens
  • Session tokens
  • Encryption keys
  • Database connection strings
  • Any .env files containing secrets

DO use environment variables or secure secret management:

from pydantic_settings import BaseSettings
from pydantic import Field, SecretStr

class Settings(BaseSettings):
    """Application settings loaded from environment."""

    unifi_api_key: SecretStr = Field(..., description="UniFi API Key from unifi.ui.com")
    unifi_api_type: str = Field(default="cloud", description="API type: cloud or local")
    unifi_host: str = Field(default="api.ui.com", description="API host")
    unifi_port: int = Field(default=443, description="API port")

    class Config:
        env_file = ".env"
        env_file_encoding = "utf-8"

# Usage with automatic masking
settings = Settings()
# API key is automatically masked when printed
print(f"Using host: {settings.unifi_host}")  # Safe
print(f"API key: {settings.unifi_api_key}")  # Outputs: **********

UniFi API Key Security

Obtaining API Keys Securely:

  1. Log in to UniFi Site Manager
  2. Navigate to Settings → Control Plane → Integrations
  3. Create API Key with a descriptive name
  4. Copy the key immediately - it's only shown once
  5. Store in a password manager or secure secret management system

API Key Best Practices:

# ❌ NEVER hardcode API keys
api_key = "abc123def456..."

# ❌ NEVER log full API keys
logging.debug(f"Using API key: {api_key}")

# ✅ DO load from environment
api_key = os.getenv("UNIFI_API_KEY")

# ✅ DO mask in logs (show first 8 chars only)
logging.debug(f"Using API key: {api_key[:8]}..." if api_key else "not set")

# ✅ DO use SecretStr for automatic masking
from pydantic import SecretStr
api_key = SecretStr(os.getenv("UNIFI_API_KEY"))

API Key Rotation:

  • Rotate API keys every 90 days or sooner
  • Immediately rotate if a key is exposed or compromised
  • Use separate keys for development, staging, and production
  • Revoke old keys after rotation
  • Document key rotation procedures in your runbooks

Secure Storage Options:

  • Environment variables (.env file, never committed)
  • AWS Secrets Manager
  • HashiCorp Vault
  • Azure Key Vault
  • Google Cloud Secret Manager
  • Password managers (1Password, LastPass, etc.)

Input Validation

Always validate and sanitize user inputs:

from pydantic import BaseModel, validator, Field

class DeviceConfig(BaseModel):
    name: str = Field(..., min_length=1, max_length=100)
    mac_address: str

    @validator('mac_address')
    def validate_mac(cls, v):
        # Validate MAC address format
        import re
        if not re.match(r'^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$', v):
            raise ValueError('Invalid MAC address format')
        return v.lower()

API Security

Authentication:

  • Always use HTTPS for API communications (required for UniFi Cloud API)
  • Use API key authentication via X-API-Key header
  • No session management needed (stateless authentication)
  • Store API keys securely using environment variables or secret management

API Key Headers:

import httpx
from pydantic import SecretStr

async def make_api_request(api_key: SecretStr, endpoint: str):
    """Make authenticated request to UniFi API."""
    headers = {
        "X-API-Key": api_key.get_secret_value(),  # Only expose when needed
        "Accept": "application/json"
    }

    async with httpx.AsyncClient() as client:
        response = await client.get(
            f"https://api.ui.com/v1/{endpoint}",
            headers=headers,
            timeout=30.0
        )
        response.raise_for_status()
        return response.json()

Rate Limiting:

  • Respect UniFi API rate limits (100 req/min EA, 10k req/min v1)
  • Implement client-side rate limiting
  • Add exponential backoff for 429 (rate limit) errors
  • Cache frequently accessed data to reduce API calls

Rate Limit Implementation Example:

import asyncio
from datetime import datetime, timedelta

class APIRateLimiter:
    """Enforce rate limits for UniFi API."""

    def __init__(self, max_requests: int = 100, window_seconds: int = 60):
        self.max_requests = max_requests
        self.window = timedelta(seconds=window_seconds)
        self.requests = []

    async def acquire(self):
        """Wait if necessary to respect rate limits."""
        now = datetime.now()

        # Remove old requests
        self.requests = [req for req in self.requests if req > now - self.window]

        # Wait if at limit
        if len(self.requests) >= self.max_requests:
            sleep_time = (self.requests[0] + self.window - now).total_seconds()
            if sleep_time > 0:
                await asyncio.sleep(sleep_time)

        self.requests.append(now)

Error Handling:

  • Never expose API keys in error messages
  • Log errors securely without exposing secrets
  • Provide user-friendly error messages
import logging

# ❌ BAD - Exposes API key
logging.error(f"Failed to connect with API key: {api_key}")

# ❌ BAD - Shows partial key (still risky)
logging.error(f"Auth failed with key: {api_key[:16]}...")

# ✅ GOOD - No key exposure
logging.error(f"Authentication failed for host '{host}'. Check your UNIFI_API_KEY.")

# ✅ GOOD - Redacted for debugging
logging.debug(f"API key configured: {'yes' if api_key else 'no'}")

Dependency Security

Regular Updates:

  • Keep all dependencies up to date
  • Review security advisories for dependencies
  • Use automated dependency scanning tools

Vulnerability Scanning:

Our CI/CD pipeline includes automated security scanning:

# Check for known vulnerabilities in dependencies
safety check

# Security linting with Bandit
bandit -r src/

# Docker image scanning
trivy image unifi-mcp-server:latest

Manual Security Checks:

# Install development dependencies
pip install -e ".[dev]"

# Run security checks
safety check
bandit -r src/ -f json -o bandit-report.json

# Check for outdated packages with vulnerabilities
pip list --outdated

AI-Specific Security Considerations

When using AI coding assistants:

  1. Review All AI-Generated Code: Never merge AI-generated code without human review
  2. Validate Security-Critical Code: Extra scrutiny for authentication, authorization, and data handling
  3. Test Generated Code: Ensure comprehensive test coverage for AI contributions
  4. Audit AI Permissions: Limit AI assistant access to only necessary resources
  5. Monitor AI Changes: Track and review all AI-contributed changes in version control

See AI_GIT_PRACTICES.md and AGENTS.md for additional AI security guidelines.

Docker Security

Image Security:

  • Use official base images from trusted sources
  • Keep base images updated
  • Run containers as non-root users
  • Scan images for vulnerabilities

Example Secure Dockerfile:

FROM python:3.10-slim

# Create non-root user
RUN useradd -m -u 1000 mcpuser

# Set working directory
WORKDIR /app

# Copy and install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code
COPY --chown=mcpuser:mcpuser . .

# Switch to non-root user
USER mcpuser

# Run application
CMD ["python", "src/main.py"]

Security Features

Current Security Features

  • API Key Authentication: Stateless authentication via official UniFi Cloud API
  • Environment-based Configuration: API keys stored in environment variables, not in code
  • Secret Masking: Pydantic SecretStr automatically masks sensitive values
  • Type Safety: Pydantic models enforce data validation
  • Async Security: Non-blocking I/O prevents certain timing attacks
  • HTTPS-Only: Secure communication with UniFi Cloud API (TLS 1.2+)
  • Pre-commit Hooks: Automated secret detection before commits using detect-secrets
  • Dependency Scanning: Automated vulnerability scanning with Safety and Bandit
  • Container Security: Docker images scanned with Trivy
  • Input Validation: All user inputs validated with Pydantic models

Phase 4 Mutating Tools Safety Mechanisms

All mutating tools (Phase 4) implement comprehensive safety features:

  1. Confirmation Requirement:

    # ❌ WILL FAIL - Missing confirmation
    await create_firewall_rule(site_id="default", name="test", action="drop")
    
    # ✅ WORKS - With confirmation
    await create_firewall_rule(site_id="default", name="test", action="drop", confirm=True)
  2. Dry Run Mode:

    # Preview changes without executing
    result = await create_network(
        site_id="default",
        name="Guest",
        vlan_id=100,
        subnet="192.168.100.0/24",
        dry_run=True  # No actual changes made
    )
    # Returns: {"dry_run": True, "would_create": {...}}
  3. Audit Logging:

    • All mutating operations logged to audit.log
    • Includes timestamp, operation, parameters, result, user (if available)
    • Separate log for security audit trail
    • Format: JSON lines for easy parsing
  4. Input Validation:

    • All parameters validated before execution
    • Type checking via Pydantic models
    • Custom validators for MAC addresses, IPs, VLANs, etc.
    • Raises ValidationError for invalid inputs

Mutating Tool Categories:

  • Firewall Management: create_firewall_rule, update_firewall_rule, delete_firewall_rule
  • Network Configuration: create_network, update_network, delete_network
  • Device Control: restart_device, locate_device, upgrade_device
  • Client Management: block_client, unblock_client, reconnect_client

Audit Log Example:

{
  "timestamp": "2025-10-18T10:30:00Z",
  "operation": "create_firewall_rule",
  "parameters": {"site_id": "default", "name": "Block SSH", "action": "drop"},
  "result": "success",
  "dry_run": false,
  "site_id": "default"
}

Planned Security Enhancements

  • Audit logging for all mutating operations (✅ Phase 4)
  • Confirmation requirements for dangerous operations (✅ Phase 4)
  • Dry-run mode for safe testing (✅ Phase 4)
  • Role-based access control (RBAC) for MCP tools
  • API key rotation automation
  • Request signing for additional security
  • IP allowlist/denylist support
  • Webhook signature verification
  • Enhanced monitoring and alerting for suspicious activity
  • Security headers for HTTP responses
  • Support for multiple API keys with different scopes

Security Audit History

Date Type Findings Status
2025-10-17 Initial Setup N/A Baseline

Compliance and Standards

This project strives to follow:

  • OWASP Top 10: Web application security best practices
  • CWE Top 25: Common weakness enumeration
  • NIST Guidelines: Cybersecurity framework recommendations
  • Secure Coding Standards: For Python development

Security Contacts

For security-related questions or concerns:

Acknowledgments

We appreciate the security research community and recognize contributors who responsibly disclose vulnerabilities:

Additional Resources


Last Updated: 2025-10-17

Thank you for helping keep UniFi MCP Server and its users safe!

There aren’t any published security advisories