# Docker Compose Security Audit **Date:** 2026-02-20 **Auditor:** External Security Review **Scope:** `docker-compose.yml` and container orchestration ## Executive Summary | Metric | Value | |--------|-------| | Total Services | 40+ | | High Severity Issues | 3 | | Medium Severity Issues | 1 | | Low Severity Issues | 1 | ## Detailed Findings ### 1. Docker Socket Mount (HIGH) **Severity:** HIGH **Affected Services:** `docker-mcp`, `mcp-ansible` **CWE:** CWE-250 (Execution with Unnecessary Privileges) #### Description Two services mount the Docker socket, granting full Docker daemon access: ```yaml # docker-mcp volumes: - /var/run/docker.sock:/var/run/docker.sock # mcp-ansible volumes: - /var/run/docker.sock:/var/run/docker.sock ``` This provides equivalent access to root on the host system. #### Impact - Full control over all containers on host - Ability to mount host filesystem - Potential for container escape - Access to secrets in other containers #### Risk Assessment - **Necessary for Function:** Yes - these services manage Docker/containers - **Mitigation Required:** Yes #### Recommendation 1. Run these services with explicit user constraints where possible 2. Document the privilege requirement clearly 3. Consider socket proxy (docker-socket-proxy) for least privilege 4. Isolate on dedicated management nodes in production ```yaml # Alternative with socket proxy services: docker-mcp: environment: - DOCKER_HOST=tcp://docker-proxy:2375 depends_on: - docker-proxy docker-proxy: image: tecnativa/docker-socket-proxy volumes: - /var/run/docker.sock:/var/run/docker.sock environment: - CONTAINERS=1 - IMAGES=1 # Only allow specific operations ``` --- ### 2. Kubernetes Config Mount (HIGH) **Severity:** HIGH **Affected Service:** `kubernetes-mcp` **CWE:** CWE-250 (Execution with Unnecessary Privileges) #### Description The kubernetes-mcp service mounts kubeconfig: ```yaml volumes: - ~/.kube/config:/home/appuser/.kube/config:ro ``` This grants Kubernetes cluster admin access to the container. #### Impact - Full control over Kubernetes cluster - Access to all secrets in cluster - Ability to deploy privileged workloads - Cluster admin equivalent access #### Risk Assessment - **Necessary for Function:** Yes - required for Kubernetes management - **Mitigation Required:** Yes #### Recommendation 1. Use read-only mount (`:ro` flag) - already implemented 2. Consider ServiceAccount tokens instead of kubeconfig 3. Implement RBAC with minimal required permissions 4. Document required permissions clearly --- ### 3. Privileged Access Pattern (MEDIUM) **Severity:** MEDIUM **Affected:** Multiple services requiring system access **CWE:** CWE-269 (Improper Privilege Management) #### Description Several services require elevated privileges for their function: | Service | Privilege Type | Justification | |---------|---------------|---------------| | docker-mcp | Docker socket | Container management | | mcp-ansible | Docker socket | Container orchestration | | kubernetes-mcp | kubeconfig | Cluster management | | ssh-mcp | SSH keys | Remote server access | #### Recommendation Document each privileged service with: - Required access level - Business justification - Mitigating controls - Audit logging requirements --- ### 4. Default Credential Pattern (LOW) **Severity:** LOW **Affected Service:** `ghost-mcp` **CWE:** CWE-1188 (Initialization with Hard-Coded Network Resource Configuration) #### Description Ghost MCP service shows a placeholder credential pattern: ```yaml # Line 224 environment: - GHOST_API_KEY=${GHOST_API_KEY:-your-api-key-here} ``` While this is a placeholder (not a real credential), it establishes a pattern that could lead to: - Developers committing real credentials - Default credentials being used in development #### Recommendation - Remove default values entirely - Fail fast if required variables not set - Use `${VAR:?VAR must be set}` pattern ```yaml environment: - GHOST_API_KEY=${GHOST_API_KEY:?GHOST_API_KEY must be set} ``` --- ## Network Security Analysis ### Network Configuration All services use default Docker networking (bridge). No custom networks defined. #### Recommendations 1. Create isolated networks for service groups: ```yaml networks: mcp-servers: driver: bridge lsp-servers: driver: bridge ``` 2. Limit inter-service communication where not required --- ## Resource Limits ### Current State No resource limits defined for any service. #### Risk - Resource exhaustion (memory/CPU) - Noisy neighbor problems - Potential denial of service #### Recommendation Add resource constraints: ```yaml deploy: resources: limits: cpus: '0.5' memory: 512M reservations: memory: 256M ``` --- ## Health Checks ### Current State No health checks defined. #### Recommendation Add health checks for monitoring: ```yaml healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s ``` --- ## Positive Findings 1. **No host network mode** - Services use bridge networking 2. **No privileged mode** - No containers run with `privileged: true` 3. **Environment variables externalized** - Using `.env` file pattern 4. **Read-only mounts where appropriate** - kubeconfig mounted read-only 5. **Consistent container naming** - `kneldevstack-aimiddleware-` prefix --- ## Remediation Priority | Priority | Finding | Effort | Impact | |----------|---------|--------|--------| | 1 | Document privileged services | Low | High | | 2 | Add resource limits | Low | Medium | | 3 | Implement socket proxy for Docker access | Medium | High | | 4 | Remove default credential patterns | Low | Low | | 5 | Add health checks | Medium | Medium | | 6 | Create network segmentation | Medium | Medium |