vuln-nist-mcp-server
A Model Context Protocol (MCP) server for querying NIST National Vulnerability Database (NVD) API endpoints.
Purpose
This MCP server exposes tools to query the NVD/CVE REST API and return formatted text results suitable for LLM consumption via the MCP protocol. It includes automatic query chunking for large date ranges and parallel processing for improved performance.
Base API docs: https://nvd.nist.gov/developers/vulnerabilities
Features
Available Tools
get_temporal_context- Get current date and temporal context for time-relative queries- Essential for queries like "this year", "last year", "6 months ago"
- Provides current date mappings and examples for date parameter construction
-
USAGE: Call this tool FIRST when user asks time-relative questions
-
search_cves- Search CVE descriptions by keyword with flexible date filtering - Parameters:
keyword,resultsPerPage(default: 20),startIndex(default: 0),last_days(recent_dayshas been deprecated),start_date,end_date - New in v1.1.0: Support for absolute date ranges with
start_dateandend_dateparameters - Date filtering priority:
start_date/end_dateβlast_daysβ default 30 days - Auto-chunks queries > 120 days into parallel requests
-
Results sorted by publication date (newest first)
-
get_cve_by_id- Retrieve detailed information for a specific CVE - Parameters:
cve_id -
Returns: CVE details, references, tags, and publication dates
-
cves_by_cpe- List CVEs associated with a Common Platform Enumeration (CPE) - Parameters:
cpe_name(full CPE 2.3 format required),is_vulnerable(optional) -
Validates CPE format before querying
-
kevs_between- Find CVEs added to CISA KEV catalog within a date range - Parameters:
kevStartDate,kevEndDate,resultsPerPage(default: 20),startIndex(default: 0) - Auto-chunks queries > 90 days into parallel requests
-
Results sorted by publication date (newest first)
-
cve_change_history- Retrieve change history for CVEs - Parameters:
cve_idOR (changeStartDate+changeEndDate),resultsPerPage(default: 20),startIndex(default: 0) - Auto-chunks date range queries > 120 days into parallel requests
- Results sorted by change creation date (newest first)
Key Features
- Temporal Awareness: New
get_temporal_contexttool for accurate time-relative queries - Flexible Date Filtering: Support for both relative (
last_days) and absolute (start_date/end_date) date ranges - Improved Result Ordering: All results sorted chronologically (newest first) for better relevance
- Parallel Processing: Large date ranges are automatically split into chunks and processed concurrently
- Input Validation: CPE format validation, date parsing, parameter sanitization
- Emoji Indicators: Clear visual feedback (β success, β error, β οΈ warning, π search, π₯ KEV, π CPE, π history, π temporal)
- Comprehensive Logging: Detailed stderr logging for debugging
- Error Handling: Graceful handling of API errors, timeouts, and malformed responses
Prerequisites
- Docker (recommended) or Python 3.11+
- Network access to NVD endpoints (
services.nvd.nist.gov) - MCP-compatible client (e.g., Claude Desktop)
Quick Start
Using Docker (Recommended)
# Clone and build
git clone https://github.com/HaroldFinchIFT/vuln-nist-mcp-server
cd vuln-nist-mcp-server
docker build -t vuln-nist-mcp-server .
# Run
docker run --rm -it vuln-nist-mcp-server
Configuration
Environment variables:
NVD_BASE_URL: Base URL for NVD API (default:https://services.nvd.nist.gov/rest/json)NVD_VERSION: API version (default:/2.0)NVD_API_TIMEOUT: Request timeout in seconds (default:10)
Usage Examples
With Claude Desktop or MCP Client
Get temporal context for time-relative queries:
Tool: get_temporal_context
Params: {}
Search recent CVEs (relative time):
Tool: search_cves
Params: {
"keyword": "Microsoft Exchange",
"resultsPerPage": 10,
"last_days": 7
}
Search CVEs with absolute date range:
Tool: search_cves
Params: {
"keyword": "buffer overflow",
"start_date": "2024-01-01T00:00:00",
"end_date": "2024-03-31T23:59:59"
}
Search CVEs for "this year" (use get_temporal_context first):
# First, get temporal context
Tool: get_temporal_context
# Then use the provided date mappings
Tool: search_cves
Params: {
"keyword": "remote code execution",
"start_date": "2025-01-01T00:00:00",
"end_date": "2025-09-17T12:00:00"
}
Get CVE details:
Tool: get_cve_by_id
Params: {"cve_id": "CVE-2024-21413"}
Check CPE vulnerabilities:
Tool: cves_by_cpe
Params: {
"cpe_name": "cpe:2.3:a:microsoft:exchange_server:2019:*:*:*:*:*:*:*",
"is_vulnerable": "true"
}
Find recent KEV additions:
Tool: kevs_between
Params: {
"kevStartDate": "2024-01-01T00:00:00.000Z",
"kevEndDate": "2024-03-31T23:59:59.000Z"
}
Performance Notes
- Queries with date ranges > 90-120 days are automatically chunked for better performance
- Parallel processing reduces total query time for large date ranges
- Results are automatically sorted by publication date (newest first) across all chunks
Development
File Structure
vuln-nist-mcp-server/
βββ Dockerfile
βββ glama.json
βββ LICENSE
βββ nvd_logo.png
βββ README.md
βββ requirements.txt
βββ SECURITY.md
βββ vuln_nist_mcp_server.py
Security Considerations
- No API key required (public NVD endpoints)
- Container runs as non-root user (
mcpuser) - Input validation prevents injection attacks
- No persistent storage of sensitive data
- Network capabilities added only when required via Docker flags
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Test locally
- Submit a pull request
License
MIT - see LICENSE file for details
Changelog
v1.1.0
- NEW: Added
get_temporal_contexttool for temporal awareness and time-relative queries - ENHANCED:
search_cvesnow supports absolute date ranges withstart_dateandend_dateparameters - ENHANCED: Improved date filtering logic with priority: absolute dates β relative days β default 30 days
- ENHANCED: All tools now return results sorted chronologically (newest first) for better relevance
- IMPROVED: Better error handling for ISO-8601 date parsing
- DEPRECATED:
recent_daysparameter insearch_cves(uselast_daysinstead) - UPDATED: Logo and visual improvements
v1.0.0
- Initial release
- Support for all major NVD API endpoints
- Automatic query chunking and parallel processing
- CPE format validation
- Comprehensive error handling
Parameters
keyword
resultsPerPage
startIndex
recent_days
last_days
start_date
end_date
Parameters
cve_id
Parameters
cpe_name
is_vulnerable
Parameters
kevStartDate
kevEndDate
resultsPerPage
startIndex
Parameters
cve_id
changeStartDate
changeEndDate
resultsPerPage
startIndex
out of 100
Security Review
Integration: Vuln NIST
Repository: https://github.com/HaroldFinchIFT/vuln-nist-mcp-server
Commit: latest
Scan Date: 2026-03-14 12:14 UTC
Security Score
79 / 100
Tier Classification
Silver
OWASP Alignment
OWASP Rubric
- Standard: OWASP Top 10 (2021) aligned review
- Core methodology: architecture context, trust boundaries, data-flow tracing, threat modeling, control verification, and evidence-backed validation
- Key characteristics considered: exploitability, impact, likelihood, attacker preconditions, and business context
OWASP Security Category Mapping
- A01 Broken Access Control: none
- A02 Cryptographic Failures: none
- A03 Injection: none
- A04 Insecure Design: none
- A05 Security Misconfiguration: none
- A06 Vulnerable and Outdated Components: none
- A07 Identification and Authentication Failures: none
- A08 Software and Data Integrity Failures: none
- A09 Security Logging and Monitoring Failures: none
- A10 Server-Side Request Forgery: none
Static Analysis Findings (Bandit)
High Severity
None
Medium Severity
None
Low Severity
- Try, Except, Pass detected. in vuln_nist_mcp_server.py:58 (confidence: HIGH)
Build Status
SKIPPED
Build step was skipped to avoid running untrusted build commands by default.
Tests
Not detected
Documentation
README: Present
Dependency file: Present
AI Security Review
OWASP Review Methodology Applied
I performed a focused, OWASP-aligned security review of the repository using the following approach:
- Orientation / Architecture: inspected the repository layout and main entrypoint (vuln_nist_mcp_server.py) and the Dockerfile and requirements.txt to understand runtime environment and exposed surfaces.
- Entry points: read the MCP server startup (main()) and all functions decorated with @mcp.tool() to identify what external inputs are accepted and what actions are performed.
- Data flow & trust boundaries: traced how user-supplied inputs (tool parameters) flow into outbound HTTP requests, logging, and formatting functions; identified where environment variables (NVD_BASE_URL, NVD_VERSION, NVD_API_TIMEOUT) influence behavior and create trust boundaries.
- Threat modeling: considered attacker preconditions (remote attacker interacting with MCP tools vs. attacker controlling environment/runtime), likely impact, and exploitability for each finding.
- Verification: mapped findings to concrete lines and code snippets, and aligned each finding to OWASP Top 10 2021 categories and remediation guidance.
Summary of project behavior (high level)
- The binary entrypoint is vuln_nist_mcp_server.py (run by Docker CMD). It registers multiple MCP tools (functions decorated with @mcp.tool()). The MCP server is started with mcp.run(transport="stdio") and therefore exposes these tools to any entity that can speak the MCP protocol over stdin/stdout.
- Tools accept user-supplied parameters (keyword, cve_id, cpe_name, date ranges, resultsPerPage, startIndex, etc.) and then perform HTTP requests to the NVD API using httpx. The NVD base URL and API version are environment-configurable via NVD_BASE_URL and NVD_VERSION.
- The tool implementations generally validate formats (e.g., ISO-8601 parsing, CPE regex for cpe_name) but use broad exception handling and in one helper function swallow exceptions silently (Bandit flagged try/except/pass).
- Dockerfile runs the process as a non-root user (mcpuser) and installs dependencies from requirements.txt.
Findings mapped to OWASP Top 10 2021
- A01 Broken Access Control: Exposed MCP tools without authentication or authorization (any MCP client can call these tools).
- A03 Injection: Partial β uncontrolled string concatenation into an outbound URL in search_cves allows HTTP parameter injection (user-supplied keyword injected without encoding), and logged values include user input (log injection).
- A05 Security Misconfiguration: No runtime/transport authentication; NVD_BASE_URL is freely configurable by environment; no caps/limits on user-controlled numeric parameters (resultsPerPage / startIndex). Healthcheck is a no-op.
- A06 Vulnerable and Outdated Components: requirements use open lower bounds (>=) which may allow unexpected versions; no pinned exact versions. (Note: no known CVEs in listed minimal dependencies are asserted here because that requires external CVE DB lookup.)
- A07 Identification and Authentication Failures: No authentication / caller verification protecting tool invocation.
- A08 Software and Data Integrity Failures: Broad exception swallowing may hide integrity issues and complicate monitoring.
- A09 Security Logging and Monitoring Failures: Logging of raw user input without sanitization and silent exception swallowing reduce auditability and may allow log injection.
- A10 Server-Side Request Forgery (SSRF): Outbound HTTP calls are made to an environment-configurable base URL (NVD_BASE_URL). If deployment environment misconfiguration allows NVD_BASE_URL to point to internal services (or if an attacker can influence that env), the tool can be used to access internal endpoints. Additionally search_cves constructs full URLs by string concatenation with unescaped user input which makes it easier to manipulate outbound requests.
Critical Vulnerabilities
- No critical issues found (no RCE, no arbitrary code execution, no unsafe deserialization, no direct shell/OS command execution in repository code).
High Severity Issues
1) Unauthenticated tool exposure (Broken Access Control / A01 / A07) β vuln_nist_mcp_server.py
- Files: vuln_nist_mcp_server.py
- Location: server start / tool registration and run β mcp.run(transport="stdio") (around line ~562 in file)
- Severity: HIGH
- Description & risk: All @mcp.tool() functions are registered and the MCP server is started with stdio transport. There is no authentication, authorization, or caller validation implemented. Any process or actor with access to the server's stdio (or to whatever transport MCP is attached to in a larger system) can invoke the tools. Depending on deployment this can allow unauthorized enumeration of vulnerabilities, create large outbound request loads, or (with a misconfigured environment) be misused to scan internal resources.
- Exploitability: High if an attacker can connect to the MCP transport (for example an LLM runtime or container that exposes stdin/stdout to external processes or when MCP is embedded in a system that forwards requests from remote callers). Preconditions: the attacker must be able to interact with the running MCP process or the host environment exposing the transport.
- Impact: unauthorized access to functions that make network calls; information disclosure; ability to force outbound requests (SSRF-like actions) and DoS (resource exhaustion).
- Remediation: Add authentication/authorization around tool invocation. Options:
- Restrict transport to local-only/private IPC or only start the MCP service on a well-known, authenticated transport.
- Implement an authentication layer in mcp.run or in the tool wrappers (token-based verification, mutual TLS between callers and the server, or integration with the host orchestration authorization).
- At minimum document that the server must only be run in a trusted execution environment and harden deployments to ensure only trusted callers can reach stdio.
- Concrete locations to change:
- vuln_nist_mcp_server.py main(): mcp.run(transport="stdio") β ensure caller authentication or require an authenticated transport or wrapper that enforces identity (file: vuln_nist_mcp_server.py around line ~562).
High severity note: Server-Side Request Forgery (A10) risk from configurable NVD_BASE_URL and unencoded parameter injection
2) SSRF / arbitrary outbound request amplification via configurable NVD_BASE_URL and uncontrolled parameters (A10) β vuln_nist_mcp_server.py
- Files: vuln_nist_mcp_server.py
- Locations:
- NVD_BASE retrieval (line ~27): NVD_BASE = os.environ.get("NVD_BASE_URL", "https://services.nvd.nist.gov/rest/json")
- search_cves builds a URL string and interpolates user-controlled keyword without URL encoding (query built at ~179-186 and full_url built at ~187-189). That code uses client.get(full_url) instead of using params with automatic encoding.
- Severity: HIGH
- Description & risk: Because NVD_BASE is environment-configurable, a misconfigured deployment may set it to an internal host (for example http://169.254.169.254, internal management APIs, or other private resources). The tool will then perform GET requests to whatever host NVD_BASE points to. Additionally the search_cves implementation embeds user input into the raw query string without URL-encoding which allows an attacker to inject additional query-parameters or manipulate the constructed URL more easily. This increases SSRF attack surface and also can be used to craft requests that may trick intermediary proxies or the target. While the code uses an explicit host (NVD_BASE), an attacker might exploit a mistakenly configured NVD_BASE to pivot into internal networks.
- Exploitability: Medium β requires either misconfiguration or the ability to set NVD_BASE in the runtime environment. However, search_cvesβ raw concatenation of keyword increases the chance of unexpected behavior even when NVD_BASE is correct.
- Impact: reading internal endpoints, exfiltrating data, or causing requests to internal-only hosts.
- Remediation:
- Do not allow arbitrary NVD_BASE on production; restrict to an allowlist of known NVD endpoints or validate that NVD_BASE is an https:// URL and host is expected (e.g., services.nvd.nist.gov) before making requests (file: vuln_nist_mcp_server.py near NVD_BASE assignment and early in request functions).
- For search_cves specifically, stop concatenating query strings by hand: pass params to client.get(url, params=params) so httpx will safely encode parameters. Replace the query assembly at ~lines 179-186 with a params dict and call client.get(url, params=params).
- URL-encode or quote user-supplied strings when interpolation is necessary: use urllib.parse.quote_plus(keyword) if you must build the URL string manually.
Medium Severity Issues
3) Lack of input validation and request/response limits β vuln_nist_mcp_server.py
- Files: vuln_nist_mcp_server.py
- Locations: resultsPerPage and startIndex usage (parameters accepted in multiple functions, e.g., search_cves signature lines at top ~122, kevs_between/others) and _int_or_default helper around line ~41.
- Severity: MEDIUM
- Description & risk: Numeric parameters (resultsPerPage and startIndex) are converted to ints, but there is no upper bound validation or rate limiting. An attacker could request extremely large resultsPerPage values or construct date ranges that generate many chunks, causing heavy outbound request load, high memory usage, long running tasks, or even trigger remote API rate limits and affect service availability.
- Exploitability: Medium β attacker only needs to call the exposed tools with crafted parameters.
- Impact: Denial of Service (resource exhaustion), billing or rate-limit issues with external APIs.
- Remediation:
- Enforce sane upper/lower bounds for resultsPerPage and startIndex (e.g., resultsPerPage <= 200 by default or lower depending on NVD limits).
- Limit the maximum number of chunks that can be created for date ranges; return an error asking the caller to narrow the window if over a threshold (e.g., > 12 chunks).
- Add per-client rate-limiting at the transport or tool layer (if applicable) and circuit breakers for external API failures.
- Concrete files/lines: validate values at parsing points (e.g., inside _int_or_default (vuln_nist_mcp_server.py around line ~37) or right after parsing resultsPerPage/startIndex in each tool).
4) Broad exception handling and silent swallowing (A08 / A09)
- Files: vuln_nist_mcp_server.py
- Locations: multiple functions use broad except Exception: where they log and return generic errors; one helper _short_desc_from_vuln swallows exceptions silently with except Exception: pass (bandit flagged) (around line ~58).
- Severity: MEDIUM
- Description & risk: Broad catches obscure root causes and make debugging and monitoring harder. In _short_desc_from_vuln an exception is ignored silently which could hide data issues. Overly broad exception handlers can mask upstream failures and make it harder to detect abuse or attacks.
- Exploitability: low/medium β attacker could attempt to trigger a variety of errors to cover their tracks or to force code into fallback branches.
- Impact: reduced observability and possible unexpected behavior.
- Remediation:
- Replace generic 'except Exception:' with more specific exceptions where possible (ValueError, KeyError, TypeError). Where broad catching is used for top-level tool functions, preserve stack traces in logs at debug level and return a sanitized error message.
- In _short_desc_from_vuln, at minimum log the exception at debug level instead of silent pass, or micro-harden the parsing logic to avoid exceptions.
- Files/lines to change: the helper _short_desc_from_vuln (approx. lines 30-60) and the broad excepts in each tool (search_cves except at ~243, get_cve_by_id except at ~292, cves_by_cpe except at ~348, kevs_between except at ~440, cve_change_history excepts at ~539 and ~568).
Low Severity Issues
5) Log injection and leakage of user input in logs (A09)
- Files: vuln_nist_mcp_server.py
- Locations: logger.info statements that include user input without sanitization (e.g., search_cves chunk logging full_url at ~189, get_cve_by_id logging cveId ~256, cves_by_cpe logging cpeName ~328 etc.)
- Severity: LOW
- Description & risk: Untrusted input is interpolated into log lines. Attackers could insert control characters that may confuse log parsers or inject false log lines. Logs might also contain sensitive information (if the tool were extended to handle secrets in the future).
- Remediation: sanitize or escape user-supplied values before logging (e.g., remove newlines, limit length) and avoid logging entire URLs or user inputs at info level; use debug level for detailed logging.
6) Dependency versioning + minimal requirements (A06)
- Files: requirements.txt
- Location: requirements.txt lists mcp[cli]>=1.2.0 and httpx>=0.24.0 (file: requirements.txt)
- Severity: LOW
- Description & risk: Using open-ended >= version bounds may pull in newer versions with breaking changes or security regressions. Not pinning direct dependency versions for production images increases the risk of unexpected vulnerability exposure.
- Remediation: pin to specific vetted versions (>= sometimes acceptable for library authors, but for deployed containers prefer exact pins or use a lock file). Periodically scan dependencies for CVEs.
7) Healthcheck is a no-op (Dockerfile)
- Files: Dockerfile
- Location: HEALTHCHECK command returns exit 0 unconditionally (Dockerfile lines around the HEALTHCHECK). This will always mark the container healthy even if the MCP server is failing.
- Severity: LOW
- Description & risk: A broken healthcheck reduces deploy-time observability and survival under orchestration β not a security vulnerability per se, but operationally important.
- Remediation: make healthcheck verify that the process is responsive (e.g., a small script that checks the process is running and optionally performs a trivial tool invocation or a socket check).
Key risk characteristics (exploitability / impact / likelihood / preconditions)
- Most likely and impactful issues are: (1) unauthenticated tool exposure allowing arbitrary callers to invoke tools (exploitability depends on the deployment transport exposure β likely moderate in many runtimes); (2) SSRF and outbound request misuse if NVD_BASE is misconfigured (exploitability depends on ability to control environment or misconfiguration β lower probability but high impact).
- Likelihood of exploitation depends on deployment: If the MCP server runs inside a controlled environment with no external access to stdin/stdout, the risk can be low. If embedded into an LLM service or run in a multi-tenant environment where other processes can access MCP transport, risk is high.
- Attacker preconditions: to exploit unauthenticated calls, the attacker needs transport access. To exploit SSRF via NVD_BASE, the attacker or operator must set environment variables or misconfigure the runtime. To abuse search_cves parameter concatenation, the attacker needs to be able to call the tools (same precondition as first issue).
Positive Security Practices observed
- Dockerfile creates a non-root user (RUN useradd ...; USER mcpuser) and runs the process as a non-root UID (good principle of least privilege).
- TLS is used by default because NVD_BASE default is https and httpx verification defaults are preserved.
- The code validates certain inputs strictly (CPE_REGEX enforces a full CPE 2.3 format; ISO-8601 parsing for date inputs is validated and returns helpful messages when invalid).
- The code uses reasonable timeouts for external requests (API_TIMEOUT environment variable used), avoiding infinite hang by default.
- Functions try to sanitize string inputs with _safe_str and convert numeric strings via _int_or_default.
Detailed, actionable recommendations (file:line suggestions)
- Enforce caller authentication and authorization
- File: vuln_nist_mcp_server.py β around main() where mcp.run(transport="stdio") is invoked (approx. line ~562).
- Replace or wrap mcp.run call with an authentication-enforcing transport or require an API token/credentials for each tool call. If FastMCP supports middleware or a pre-call hook, implement a pre-call authorization check in that hook. If the environment does not support auth, document and enforce secure deployment guidelines (run in isolated VMs, restrict stdin/stdout exposure).
- Map to OWASP: A01 Broken Access Control, A07 Identification and Authentication Failures.
- Prevent SSRF and unsafe URL assembly
- File: vuln_nist_mcp_server.py β lines around:
- NVD_BASE definition (approx. line 27). Add validation that NVD_BASE is an https:// URL and, if possible, the host is in an allowlist (e.g., services.nvd.nist.gov). If NVD_BASE is set to anything other than the production NVD host, require an explicit admin flag or disallow in production.
- search_cves: replace the manual query string concatenation (lines ~179-189) with using the params argument: e.g., params = {"keywordSearch": keyword, "resultsPerPage": resultsPerPage, "startIndex": startIndex, "pubStartDate": pubStartDate, "pubEndDate": pubEndDate} and call client.get(url, params=params). This ensures proper parameter encoding and avoids injection.
- Additionally restrict NVD_BASE to https and disallow user-supplied hostnames or IPs (resolve and check against expected hostnames if needed).
-
Map to OWASP: A10 SSRF, A03 Injection.
-
Add input bounds and rate/cap limits
- File: vuln_nist_mcp_server.py β in _int_or_default (approx. line ~37) and directly in each tool after parsing resultsPerPage/startIndex: enforce maximums like resultsPerPage <= 200, startIndex >= 0 and <= some large cap, and maximum allowed number of chunks when splitting long date ranges (e.g., max_chunks = 12). Return a helpful error if caller requests more than allowed.
- Add per-call rate limiting / concurrency caps for the number of parallel HTTP requests created by chunk splitting (limit tasks length and/or run chunks sequentially when above a threshold).
-
Map to OWASP: A05 Security Misconfiguration / DoS prevention.
-
Improve exception handling and logging
- File: vuln_nist_mcp_server.py β helper _short_desc_from_vuln: replace bare 'except Exception: pass' (approx. line ~58) with specific except clauses or log debugging information: at minimum logger.debug(traceback.format_exc()) when exceptions occur. Do not swallow errors silently.
- Replace broad catches where possible with specific exceptions, and define a top-level exception wrapper that returns a sanitized message but logs full details at debug level (many except blocks exist at lines ~243, ~292, ~348, ~440, ~539, ~553, ~568).
- Sanitize logged user inputs before including in logs; strip newlines and non-printable chars and truncate to reasonable length.
-
Map to OWASP: A08, A09.
-
Sanitize logs to avoid log injection
- File: vuln_nist_mcp_server.py β all logger.info lines that include user input (examples at ~189, ~256, ~328). Implement a helper that escapes or removes newlines and suspicious characters before logging.
-
Map to OWASP: A09 Security Logging and Monitoring Failures.
-
Pin / manage dependency versions and scanning
- File: requirements.txt β replace open lower bounds with pinned versions or add a lock file to the build pipeline (e.g., pip freeze or poetry lock). Monitor dependencies for CVEs.
-
Map to OWASP: A06 Vulnerable and Outdated Components.
-
Make Docker healthcheck meaningful
- File: Dockerfile β replace the HEALTHCHECK that always exits 0 with a script that verifies the process is running and optionally performs a safe check (e.g., checks logs or uses a small internal query) so orchestration will detect failure.
- Map to OWASP: A05 Security Misconfiguration / operational hygiene.
Concrete code changes (examples)
- Fix search_cves URL building (replace manual concatenation with params):
- File: vuln_nist_mcp_server.py around lines ~179-189
- Replace:
query = (f"?keywordSearch={keyword}" f"&resultsPerPage={resultsPerPage}" ...)
full_url = url + query
resp = await client.get(full_url)
With:
params = {"keywordSearch": keyword, "resultsPerPage": resultsPerPage, "startIndex": startIndex, "pubStartDate": pubStartDate, "pubEndDate": pubEndDate}
resp = await client.get(url, params=params)
- Validate NVD_BASE at startup:
- File: vuln_nist_mcp_server.py around line ~27
-
Example: if not NVD_BASE.lower().startswith("https://") or "services.nvd.nist.gov" not in urllib.parse.urlparse(NVD_BASE).hostname: log warning and refuse to start (or require explicit ADMIN_ALLOW_INTERNAL_NVD=true).
-
Add caps for resultsPerPage and chunk count:
- File: vuln_nist_mcp_server.py β after _int_or_default usage in each tool (e.g., search_cves, kevs_between, cve_change_history). If resultsPerPage > 500: resultsPerPage = 500 or return error.
Next Tier Upgrade Plan
- Current tier assessment: Bronze (Minimal safe-by-default measures present, but key controls missing). Rationale: code follows secure patterns in parts (non-root user, input parsing/validation for many fields, TLS by default) but lacks critical runtime access controls and SSRF mitigations. The MCP tools are exposed without authentication which is the primary risk preventing higher trust tiers.
-
Next target tier: Silver β require authentication and stricter runtime validation.
-
Prioritized actions to reach Silver (ordered by priority):
- Add authentication/authorization on MCP transport or tool invocation (HIGH priority) β prevent unauthenticated use of tools.
- Fix search_cves URL construction to use httpx params and validate/allowlist NVD_BASE (HIGH priority) β eliminate easy injection and SSRF vectors.
- Add input caps and chunk limits for date ranges and resultsPerPage (MEDIUM priority) β mitigate DoS/resource exhaustion.
- Replace silent exception swallowing and add structured logging with sanitized inputs (MEDIUM priority) β improve observability and reduce information leakage.
- Pin dependencies or add a lock file + add periodic dependency scanning (LOW/MEDIUM priority) β reduce risk from third-party libraries.
- Improve Docker healthcheck to be meaningful (LOW priority).
Verdict / overall risk summary
- No immediate, trivial RCE or SQL-injection-style bugs were found.
- The largest operational/security risk is that the MCP tools are accessible without authentication and perform outbound HTTP requests to an environment-configurable base URL. This combination enables misuse (information disclosure, large outbound requests, SSRF-like abuse) depending on deployment conditions. Treat this as a high priority to remediate before deploying into multi-tenant or untrusted environments.
Appendix: key code-location references (approximate line numbers)
- NVD_BASE env: vuln_nist_mcp_server.py line ~27
- _safe_str helper: vuln_nist_mcp_server.py lines ~32-36
- _int_or_default helper: vuln_nist_mcp_server.py lines ~37-45
- _short_desc_from_vuln swallowing except: vuln_nist_mcp_server.py line ~58
- search_cves query concatenation & full_url: vuln_nist_mcp_server.py lines ~179-189
- search_cves top-level exception handler: vuln_nist_mcp_server.py line ~243
- get_cve_by_id httpx usage and exception handlers: vuln_nist_mcp_server.py around lines ~252-296
- cves_by_cpe httpx usage & exception handler: vuln_nist_mcp_server.py around lines ~320-352
- kevs_between chunking and httpx usage: vuln_nist_mcp_server.py around lines ~380-444
- cve_change_history chunking and httpx usage: vuln_nist_mcp_server.py around lines ~468-568
- Server startup: mcp.run(transport="stdio") at vuln_nist_mcp_server.py line ~562
- Docker: non-root user and healthcheck: Dockerfile (USER mcpuser, HEALTHCHECK - lines ~13-23)
- requirements: requirements.txt (mcp[cli]>=1.2.0, httpx>=0.24.0)
If you want, I can prepare specific code diffs / patches for the recommended changes (e.g., replace search_cves concatenation with params usage, add parameter validation helpers, and add a simple auth token header check wrapper around mcp.tool calls) to expedite remediation.
Summary
Security Score: 79/100 (Silver)
Static analysis found 0 high, 0 medium, and 1 low severity issues.
Build step skipped for safety.
No automated tests detected.
Sign in to leave a review
No reviews yet β be the first!
Configuration
Docker Image
Docker HubPublished by github.com/HaroldFinchIFT