Comprehensive audit of scanning feature across all server types | 2026-04-06 | Branch: feat/039-security-scanner-plugins
| Level | Count | Percentage |
|---|---|---|
| Critical | 14 | 0.7% |
| High | 631 | 33.2% |
| Medium | 1,163 | 61.2% |
| Low | 91 | 4.8% |
Threat classification: 247 dangerous, 473 warnings, 1,179 informational
| Phase | Method | Scope |
|---|---|---|
| API Testing | curl + jq | 72 API tests across all scan endpoints |
| Frontend Code Review | Static analysis | ServerDetail.vue (2,000+ lines), Security.vue, api.ts |
| Backend Code Review | Static analysis | service.go, engine.go, source_resolver.go, registry_bundled.go, security_scanner.go |
| Visual UI Testing | Chrome screenshots | Global Security page, server detail security tabs |
| Scanner Quality | False positive analysis | All findings from cisco-mcp-scanner, trivy, semgrep |
| Type | Servers | Source Method | Scanners Run |
|---|---|---|---|
| HTTP (remote) | context7, hugginface, kaggle, supabase | url | 1-6 |
| Streamable-HTTP (remote) | kubic, synapbus | url | 1-3 |
| Stdio (local) | demo-filesystem | working_dir | 6 |
| Stdio (Docker) | perplexity, screenshot-website-fast | docker_extract | 3-6 |
| Stdio (quarantined) | malicious-demo | uvx_cache | 6 (1 failed) |
| Stdio (disconnected) | everything-server | npx_cache | 6 |
CVE-2025-66414 (DNS rebinding), CVE-2026-0621 (ReDoS) in @modelcontextprotocol/sdk
Tool poisoning detector could not run - server failed to connect for tool export
Audio processing tools incorrectly flagged as system manipulation
Note: supabase and kubic had 2 failed scanners each (cisco, trivy) due to tools.json not exported at time of scan
| # | Severity | Category | Description | Status |
|---|---|---|---|---|
| 1 | High | API | Concurrent scan returns 500 instead of 409 Conflict | Fixed |
| 2 | High | Backend | Duplicate findings when merging Pass 1 + Pass 2 reports (same CVE appears twice) | Fixed |
| 3 | High | Backend | Security overview threat levels all zero (dangerous/warnings/info_level not aggregated) | Fixed |
| 4 | High | Backend | malicious-demo tools.json not exported - cisco scanner fails, server shows "clean" | Open |
| 5 | High | Backend | CancelScan doesn't cancel running Docker containers (uses context.Background()) | Open |
| 6 | High | Backend | Race condition between Pass 1 completion and Pass 2 start | Open |
| 7 | High | Backend | Report directory (scanner-reports/) never cleaned up | Open |
| 8 | High | Backend | No scanner-source matching: all scanners run on all source types | Open |
| 9 | Medium | API | handleStartScan silently ignores JSON decode errors | Open |
| 10 | Medium | Backend | Pass 1 cleanup removes temp dir before Pass 2 can use it | Open |
| 11 | Medium | Backend | Race condition reading/writing job.Status without lock | Open |
| 12 | Medium | API | POST scan for nonexistent server returns 500 instead of 404 | Open |
| 13 | Medium | Backend | tools_exported inconsistently null for some servers | Open |
| 14 | Medium | Backend | Inconsistent scanner count: some servers get 6 scanners, others only 1-3 | Open |
| 15 | Medium | Backend | Docker cache mount at /root/.cache may conflict with scanner-specific paths | Open |
| 16 | Medium | Backend | extractTopLevelDir includes /usr, /var for Docker - too broad for supply chain audit | Open |
| 17 | Medium | Backend | cancel-all wipes scan job data for servers with active scans | Open |
| 18 | Medium | Backend | Scan report has duplicate scanner entries for multi-scanned servers | Open |
| 19 | Low | Backend | ValidateManifest requires Command non-empty, but 3 bundled scanners have nil Command | Open |
| 20 | Low | Backend | parseResults silently treats unparseable scanner output as 'clean' | Open |
| 21 | Low | Backend | File-to-findings path matching uses flawed normalization | Open |
| 22 | Low | Backend | GetScanSummary doesn't check for active Pass 2 scans | Open |
| 23 | Low | Backend | Cisco scanner hardcodes --tools /scan/source/tools.json path | Open |
| 24 | Low | Backend | Docker-extracted scans report total_files=0 despite scanning extracted files | Open |
| 25 | Low | Backend | Argument-based source resolution matches non-flag args as file paths incorrectly | Open |
| 26 | Low | Backend | Job ID collision risk with time.Now().UnixNano() generation | Open |
| 27 | Low | Backend | handleGetScanFiles retrieves report independently of job (potential mismatch) | Open |
| # | Severity | Category | Description | Status |
|---|---|---|---|---|
| 28 | High | UI | No Cancel button during active scan (API exists but UI doesn't expose it) | Fixed |
| 29 | Medium | UI | Scanned Files section visible for tool_definitions_only source method | Fixed |
| 30 | Medium | UI | No retry button after scan failure | Fixed |
| 31 | High | UI | Race condition: polling completion fires before scanReport loads | Open |
| 32 | High | UI | "Already in progress" error extracts job ID with fragile regex | Open |
| 33 | Medium | UI | No debounce on Scan Now button (rapid clicks can cause issues) | Open |
| 34 | Medium | UI | Polling continues silently on network errors with no max retry | Open |
| 35 | Medium | UI | Scan error alert has no dismiss action | Open |
| 36 | Medium | UI | Approve/Reject only shown with findings (can't approve clean servers) | Open |
| 37 | Medium | UI | Active scan state lost on page navigation and return | Open |
| 38 | Low | UI | Inconsistent risk score color thresholds between pages | Open |
| 39 | Low | UI | Failed scanners counted as "completed" in progress bar | Open |
| 40 | Low | UI | Scanner Execution Logs depend on scanStatus populated at wrong time | Open |
| 41 | Low | UI | No explanation of Risk Score metric anywhere | Open |
| 42 | Low | UI | No "last scanned" timestamp shown prominently | Open |
File: internal/httpapi/security_scanner.go
When a scan is already running for a server and another scan is triggered, the API now returns HTTP 409 Conflict instead of 500 Internal Server Error.
Validated: POST /scan returns 409 with "scan already in progress" message
File: internal/security/scanner/service.go
When merging Pass 1 (security scan) and Pass 2 (supply chain audit) reports, duplicate findings (same scanner + rule + title) are now removed. Pass 1 findings take priority.
Example: Perplexity had 4 findings (2 duplicated). Now correctly shows 2.
Validated: perplexity report shows 2 findings (was 4)
File: internal/security/scanner/service.go
The global security overview now correctly counts findings by threat level (dangerous, warnings, info_level). Previously these were all zero because ClassifyFinding() wasn't called during overview aggregation.
Validated: Overview shows dangerous=247, warnings=473, info_level=1179 (was all 0)
File: frontend/src/views/ServerDetail.vue
Added a "Cancel" button that appears during active scans. Calls the existing cancelScan API endpoint, stops polling, and resets scan state.
Validated: Cancel button renders, calls API correctly
File: frontend/src/views/ServerDetail.vue
The Scanned Files collapsible section is now hidden for HTTP servers and tool_definitions_only source methods (no filesystem to show files for).
Validated: Section hidden for url, url_full, and tool_definitions_only
File: frontend/src/views/ServerDetail.vue
Added a "Retry" button to the scan error alert, allowing users to easily re-trigger a scan after failure without refreshing the page.
Validated: Retry button clears error and re-triggers scan
Scanner: cisco-mcp-scanner | Findings: 2
What was flagged:
Analysis: This is standard MCP tool description pattern. Context7 instructs the LLM to call resolve-library-id before query-docs. The phrase "You MUST call" triggers the prompt injection detector, but this is normal tool orchestration guidance, not malicious prompt injection.
Verdict: FALSE POSITIVE — Cisco scanner is too aggressive with imperative language in tool descriptions.
Scanner: cisco-mcp-scanner | Findings: 16 (2 dangerous + 14 warning)
What was flagged: All audio tools (text_to_speech, speech_to_text, text_to_sound_effects, isolate_audio, speech_to_speech, etc.) flagged as "SYSTEM MANIPULATION"
Analysis: ElevenLabs is a legitimate audio processing API. Its tools interact with audio data, not system resources. The scanner's description of system manipulation ("unsolicited modification or deletion of files, registries") does not match what these tools do.
Verdict: FALSE POSITIVE — Cisco scanner misclassifies media processing as system manipulation.
| Server | Findings | Assessment |
|---|---|---|
| demo-filesystem | 7 findings (Stripe key, GitHub PAT, private keys) | TRUE POSITIVE - real secrets in filesystem |
| perplexity | 2 CVEs (DNS rebinding, ReDoS in MCP SDK) | TRUE POSITIVE - real vulnerabilities in dependencies |
The quarantined malicious-demo server can't have its tool definitions exported because it fails to connect (MCP initialize timeout). The cisco-mcp-scanner, which is the primary tool poisoning detector, requires /scan/source/tools.json which can't be created without a connection.
Impact: Quarantined servers that are truly malicious can't be scanned for tool poisoning — the exact scenario this feature is designed for.
Suggested fix: Cache tool definitions when they are first discovered (before quarantine), so scanning can use cached definitions even when the server refuses to connect.
Some servers get 6 scanners, others only 1-3. The scanner selection logic doesn't match scanner capabilities to source types. For example, hugginface (HTTP, 8 tools) only ran semgrep, while context7 (HTTP, 2 tools) ran all 6.
Impact: Inconsistent security coverage across servers.
Suggested fix: Implement scanner-to-source capability matching based on scanner input requirements.
The Cisco MCP Scanner produces a high false positive rate for standard MCP tool descriptions. Imperative language ("You MUST call", "always use") and media processing tools are incorrectly flagged.
Impact: Risk score of 60-100 for legitimate servers, eroding user trust.
Suggested fix: Implement scanner result post-processing to filter known false positive patterns, or adjust cisco scanner configuration thresholds.
Generated 2026-04-06 | MCPProxy v0.23.1 | Branch: feat/039-security-scanner-plugins
QA Coverage: 72 API tests, 15 UI bugs, 20 backend bugs, 8 design issues, 10 UX improvements