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.
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.
- 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
Report security vulnerabilities via GitHub Security Advisories:
- Go to the repository's Security tab
- Click "Report a vulnerability"
- Fill out the vulnerability report form with as much detail as possible
Alternatively, you can email the maintainers directly at:
- Use GitHub Security Advisories to report vulnerabilities
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
**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: ********".
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)
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
.envfiles 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: **********Obtaining API Keys Securely:
- Log in to UniFi Site Manager
- Navigate to Settings → Control Plane → Integrations
- Create API Key with a descriptive name
- Copy the key immediately - it's only shown once
- 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 (
.envfile, never committed) - AWS Secrets Manager
- HashiCorp Vault
- Azure Key Vault
- Google Cloud Secret Manager
- Password managers (1Password, LastPass, etc.)
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()Authentication:
- Always use HTTPS for API communications (required for UniFi Cloud API)
- Use API key authentication via
X-API-Keyheader - 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'}")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:latestManual 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 --outdatedWhen using AI coding assistants:
- Review All AI-Generated Code: Never merge AI-generated code without human review
- Validate Security-Critical Code: Extra scrutiny for authentication, authorization, and data handling
- Test Generated Code: Ensure comprehensive test coverage for AI contributions
- Audit AI Permissions: Limit AI assistant access to only necessary resources
- 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.
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"]- 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
All mutating tools (Phase 4) implement comprehensive safety features:
-
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)
-
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": {...}}
-
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
- All mutating operations logged to
-
Input Validation:
- All parameters validated before execution
- Type checking via Pydantic models
- Custom validators for MAC addresses, IPs, VLANs, etc.
- Raises
ValidationErrorfor 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"
}- 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
| Date | Type | Findings | Status |
|---|---|---|---|
| 2025-10-17 | Initial Setup | N/A | Baseline |
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
For security-related questions or concerns:
- Security Reports: Use GitHub Security Advisories
- Project Issues: GitHub Issues
We appreciate the security research community and recognize contributors who responsibly disclose vulnerabilities:
- OWASP Python Security
- Python Security Best Practices
- FastAPI Security
- GitHub Security Best Practices
Last Updated: 2026-03-17
Thank you for helping keep UniFi MCP Server and its users safe!
None. As of 2026-03-17, all known vulnerabilities have been resolved by upgrading dependencies (authlib, fastmcp, PyJWT, black, nltk) and diskcache has been removed from the dependency tree entirely (fastmcp 3.x no longer depends on it).