MCPProxy Security Scanner QA Report

Comprehensive audit of scanning feature across all server types | 2026-04-06 | Branch: feat/039-security-scanner-plugins

Table of Contents 1. Executive Overview 2. Testing Coverage 3. Server-by-Server Scan Results 4. Bugs Found (42 total) 5. Bugs Fixed (6 implemented) 6. False Positive Analysis 7. Remaining Issues 8. Recommendations

1. Executive Overview

11
Servers Tested
6
Scanners Installed
214
Total Scans Run
42
Total Bugs Found
6
Bugs Fixed
1,899
Total Findings
Findings by Severity (Global Overview)
LevelCountPercentage
Critical140.7%
High63133.2%
Medium1,16361.2%
Low914.8%

Threat classification: 247 dangerous, 473 warnings, 1,179 informational

2. Testing Coverage

QA Methodology
PhaseMethodScope
API Testingcurl + jq72 API tests across all scan endpoints
Frontend Code ReviewStatic analysisServerDetail.vue (2,000+ lines), Security.vue, api.ts
Backend Code ReviewStatic analysisservice.go, engine.go, source_resolver.go, registry_bundled.go, security_scanner.go
Visual UI TestingChrome screenshotsGlobal Security page, server detail security tabs
Scanner QualityFalse positive analysisAll findings from cisco-mcp-scanner, trivy, semgrep
Server Types Tested
TypeServersSource MethodScanners Run
HTTP (remote)context7, hugginface, kaggle, supabaseurl1-6
Streamable-HTTP (remote)kubic, synapbusurl1-3
Stdio (local)demo-filesystemworking_dir6
Stdio (Docker)perplexity, screenshot-website-fastdocker_extract3-6
Stdio (quarantined)malicious-demouvx_cache6 (1 failed)
Stdio (disconnected)everything-servernpx_cache6

3. Server-by-Server Scan Results

context7
HTTP | https://mcp.context7.com/mcp | 2 tools
Risk: 60 2 False Positives
cisco-mcp-scanner: 2 findings (PROMPT INJECTION)
semgrep-mcp: 0 findings
trivy-mcp: 0 findings
ramparts: 0 findings
nova-proximity: 0 findings
mcp-scan: 0 findings
demo-filesystem
Stdio (local) | working_dir | 14 tools
Risk: 31 7 Findings
trivy-mcp: 5 findings (secrets)
semgrep-mcp: 2 findings (secrets)
cisco-mcp-scanner: 0 findings
ramparts/nova/mcp-scan: 0 findings
perplexity
Stdio (Docker) | docker_extract | 3 tools
Risk: 20 2 CVEs
trivy-mcp: 2 findings (MCP SDK CVEs)
All other scanners: 0 findings

CVE-2025-66414 (DNS rebinding), CVE-2026-0621 (ReDoS) in @modelcontextprotocol/sdk

malicious-demo
Stdio (quarantined) | uvx_cache | 0 tools (disconnected)
Risk: 0 Scan Incomplete
cisco-mcp-scanner: FAILED (tools.json not found)
All other scanners: 0 findings

Tool poisoning detector could not run - server failed to connect for tool export

ElevenLabs
Stdio | Error state | 0 tools
Risk: 100 16 False Positives
cisco-mcp-scanner: 16 findings (SYSTEM MANIPULATION)

Audio processing tools incorrectly flagged as system manipulation

hugginface / kaggle / supabase / kubic / synapbus
HTTP/Streamable-HTTP | url | 5-58 tools
Risk: 0 Clean

Note: supabase and kubic had 2 failed scanners each (cisco, trivy) due to tools.json not exported at time of scan

4. All Bugs Found (42 total)

API / Backend Bugs (27)

#SeverityCategoryDescriptionStatus
1HighAPIConcurrent scan returns 500 instead of 409 ConflictFixed
2HighBackendDuplicate findings when merging Pass 1 + Pass 2 reports (same CVE appears twice)Fixed
3HighBackendSecurity overview threat levels all zero (dangerous/warnings/info_level not aggregated)Fixed
4HighBackendmalicious-demo tools.json not exported - cisco scanner fails, server shows "clean"Open
5HighBackendCancelScan doesn't cancel running Docker containers (uses context.Background())Open
6HighBackendRace condition between Pass 1 completion and Pass 2 startOpen
7HighBackendReport directory (scanner-reports/) never cleaned upOpen
8HighBackendNo scanner-source matching: all scanners run on all source typesOpen
9MediumAPIhandleStartScan silently ignores JSON decode errorsOpen
10MediumBackendPass 1 cleanup removes temp dir before Pass 2 can use itOpen
11MediumBackendRace condition reading/writing job.Status without lockOpen
12MediumAPIPOST scan for nonexistent server returns 500 instead of 404Open
13MediumBackendtools_exported inconsistently null for some serversOpen
14MediumBackendInconsistent scanner count: some servers get 6 scanners, others only 1-3Open
15MediumBackendDocker cache mount at /root/.cache may conflict with scanner-specific pathsOpen
16MediumBackendextractTopLevelDir includes /usr, /var for Docker - too broad for supply chain auditOpen
17MediumBackendcancel-all wipes scan job data for servers with active scansOpen
18MediumBackendScan report has duplicate scanner entries for multi-scanned serversOpen
19LowBackendValidateManifest requires Command non-empty, but 3 bundled scanners have nil CommandOpen
20LowBackendparseResults silently treats unparseable scanner output as 'clean'Open
21LowBackendFile-to-findings path matching uses flawed normalizationOpen
22LowBackendGetScanSummary doesn't check for active Pass 2 scansOpen
23LowBackendCisco scanner hardcodes --tools /scan/source/tools.json pathOpen
24LowBackendDocker-extracted scans report total_files=0 despite scanning extracted filesOpen
25LowBackendArgument-based source resolution matches non-flag args as file paths incorrectlyOpen
26LowBackendJob ID collision risk with time.Now().UnixNano() generationOpen
27LowBackendhandleGetScanFiles retrieves report independently of job (potential mismatch)Open

Frontend / UI Bugs (15)

#SeverityCategoryDescriptionStatus
28HighUINo Cancel button during active scan (API exists but UI doesn't expose it)Fixed
29MediumUIScanned Files section visible for tool_definitions_only source methodFixed
30MediumUINo retry button after scan failureFixed
31HighUIRace condition: polling completion fires before scanReport loadsOpen
32HighUI"Already in progress" error extracts job ID with fragile regexOpen
33MediumUINo debounce on Scan Now button (rapid clicks can cause issues)Open
34MediumUIPolling continues silently on network errors with no max retryOpen
35MediumUIScan error alert has no dismiss actionOpen
36MediumUIApprove/Reject only shown with findings (can't approve clean servers)Open
37MediumUIActive scan state lost on page navigation and returnOpen
38LowUIInconsistent risk score color thresholds between pagesOpen
39LowUIFailed scanners counted as "completed" in progress barOpen
40LowUIScanner Execution Logs depend on scanStatus populated at wrong timeOpen
41LowUINo explanation of Risk Score metric anywhereOpen
42LowUINo "last scanned" timestamp shown prominentlyOpen

5. Bugs Fixed (6 implemented)

Fix 1: Concurrent scan returns 409 Conflict Verified

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.

- s.writeError(w, r, http.StatusInternalServerError, err.Error())
+ if strings.Contains(err.Error(), "already in progress") {
+ s.writeError(w, r, http.StatusConflict, err.Error())
+ } else {
+ s.writeError(w, r, http.StatusInternalServerError, err.Error())
+ }

Validated: POST /scan returns 409 with "scan already in progress" message

Fix 2: Deduplicate Pass 1/Pass 2 findings Verified

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)

Fix 3: Security overview threat level aggregation Verified

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)

Fix 4: Cancel button in security tab Verified

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

Fix 5: Scanned Files section visibility Verified

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

Fix 6: Retry button after scan error Verified

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

6. False Positive Analysis

False Positive: context7 "PROMPT INJECTION" (Risk: 60)

Scanner: cisco-mcp-scanner | Findings: 2

What was flagged:

Tool: resolve-library-id Evidence: "You MUST call this function before 'Query Documentation' tool to obtain a valid Context7-compatible library ID UNLESS the user explicitly provides a library ID..."

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.

False Positive: ElevenLabs "SYSTEM MANIPULATION" (Risk: 100)

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.

True Positives (Confirmed Real Issues)
ServerFindingsAssessment
demo-filesystem7 findings (Stripe key, GitHub PAT, private keys)TRUE POSITIVE - real secrets in filesystem
perplexity2 CVEs (DNS rebinding, ReDoS in MCP SDK)TRUE POSITIVE - real vulnerabilities in dependencies

7. Remaining Issues (Not Fixed)

Critical: malicious-demo tool poisoning not detected

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.

High: Inconsistent scanner count across servers

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.

High: False positive rate from cisco-mcp-scanner

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.

8. Recommendations

Priority 1 (Next Sprint)

Priority 2 (Future)

Priority 3 (Polish)


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