get_vex_status
Retrieve VEX status for a specific CVE ID and optionally a product to assess vulnerability impact and exploitability, providing vendor statements and false positive insights.
Instructions
Check VEX vulnerability status for specific products
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| cve_id | Yes | Check Vulnerability Exploitability eXchange (VEX) status for specific products to determine actual impact and exploitability. Provide a CVE ID in format CVE-YYYY-NNNN and optionally a product name (e.g., 'Windows 11', 'RHEL 8', 'Apache HTTP Server'). Returns vendor-provided exploitability statements, false positive filtering, and product-specific impact assessment. | |
| product | No | Product name or identifier to check VEX status for (optional). Examples: 'Windows 11', 'RHEL 8', 'Ubuntu 22.04', 'Apache HTTP Server' |
Implementation Reference
- The primary handler function implementing the get_vex_status tool. It validates the CVE ID, queries the NVD API for vendor statements, infers VEX statuses, provides product-specific guidance, and returns a formatted markdown report with emojis and links.async def get_vex_status( cve_id: str, product: Optional[str] = None, ) -> List[types.TextContent | types.ImageContent | types.EmbeddedResource]: """ Check VEX (Vulnerability Exploitability eXchange) status for a CVE and product. VEX Status definitions: - not_affected: Product is not affected by the vulnerability - affected: Product is affected and vulnerable - fixed: Vulnerability has been fixed in the product - under_investigation: Vendor is investigating the impact Args: cve_id: CVE identifier in format CVE-YYYY-NNNN product: Product name or identifier (optional) Returns: List of content containing VEX status information or guidance """ # Clean up CVE ID format cve_id = cve_id.upper().strip() if not cve_id.startswith("CVE-"): cve_id = f"CVE-{cve_id}" # Validate CVE ID format (CVE-YYYY-NNNN) if not re.match(r"^CVE-\d{4}-\d{4,}$", cve_id): return [ types.TextContent( type="text", text=f"Error: Invalid CVE ID format. Expected format: CVE-YYYY-NNNN (e.g., CVE-2021-44228). Got: {cve_id}", ) ] headers = { "User-Agent": "MCP VEX Status Checker v1.0", "Accept": "application/json", } vex_data = {} vendor_statements = [] try: timeout = httpx.Timeout(15.0, connect=10.0) async with httpx.AsyncClient( follow_redirects=True, headers=headers, timeout=timeout ) as client: # Check 1: NVD for vendor statements and VEX-like information try: nvd_url = ( f"https://services.nvd.nist.gov/rest/json/cves/2.0?cveId={cve_id}" ) nvd_response = await client.get(nvd_url) if nvd_response.status_code == 200: nvd_data = nvd_response.json() if nvd_data.get("totalResults", 0) > 0: cve_item = nvd_data["vulnerabilities"][0]["cve"] # Analyze references for vendor statements for ref in cve_item.get("references", []): url = ref.get("url", "").lower() tags = ref.get("tags", []) source = ref.get("source", "") # Look for vendor statements if ( "vendor advisory" in tags or "vendor" in url or any( vendor in url for vendor in [ "microsoft", "oracle", "redhat", "ubuntu", "debian", "apache", "cisco", "vmware", ] ) ): # Try to determine VEX-like status from URL/tags status = "under_investigation" # Default confidence = "low" if any( keyword in url for keyword in [ "patch", "fix", "update", "resolved", ] ): status = "fixed" confidence = "medium" elif any( keyword in url for keyword in [ "not-affected", "unaffected", "not_affected", ] ): status = "not_affected" confidence = "high" elif any( keyword in url for keyword in ["affected", "vulnerable"] ): status = "affected" confidence = "medium" vendor_statements.append( { "vendor": source, "url": ref.get("url", ""), "inferred_status": status, "confidence": confidence, "tags": tags, } ) vex_data["nvd_vendor_statements"] = vendor_statements except Exception as e: vex_data["nvd_error"] = str(e) # Check 2: GitHub for VEX documents (CSAF format) # Note: This would require GitHub API for full search vex_data["github_vex_search"] = { "status": "manual_check_recommended", "search_urls": [ f"https://github.com/search?q={cve_id}+VEX&type=code", f"https://github.com/search?q={cve_id}+CSAF&type=code", f"https://github.com/search?q={cve_id}+vulnerability+status&type=code", ], } # Check 3: Known VEX data sources vex_sources = { "CISA": "https://www.cisa.gov/known-exploited-vulnerabilities-catalog", "RedHat": f"https://access.redhat.com/security/cve/{cve_id}", "Microsoft": f"https://msrc.microsoft.com/blog/tag/cve-{cve_id.lower()}/", "Ubuntu": f"https://ubuntu.com/security/{cve_id}", "Debian": f"https://security-tracker.debian.org/tracker/{cve_id}", } vex_data["recommended_vex_sources"] = vex_sources except Exception as e: return [ types.TextContent( type="text", text=f"Error: Failed to check VEX status: {str(e)}", ) ] # Format the response result = f"π **VEX Status Report: {cve_id}**\n" if product: result += f"π **Product:** {product}\n" result += "\n" # VEX Overview result += "π‘ **What is VEX?**\n" result += "VEX (Vulnerability Exploitability eXchange) communicates the exploitability status of vulnerabilities in specific products.\n\n" result += "π **VEX Status Categories:**\n" result += " β’ π΄ **affected** - Product is vulnerable and exploitable\n" result += ( " β’ π’ **not_affected** - Product is not affected by this vulnerability\n" ) result += " β’ β **fixed** - Vulnerability has been patched/fixed\n" result += " β’ π‘ **under_investigation** - Vendor is investigating impact\n\n" # Vendor Statement Analysis vendor_statements = vex_data.get("nvd_vendor_statements", []) if vendor_statements: result += f"π **Vendor Statements Analysis:** Found {len(vendor_statements)} vendor reference(s)\n\n" # Group by inferred status status_groups = {} for stmt in vendor_statements: status = stmt["inferred_status"] if status not in status_groups: status_groups[status] = [] status_groups[status].append(stmt) for status, statements in status_groups.items(): status_emoji = { "fixed": "β ", "not_affected": "π’", "affected": "π΄", "under_investigation": "π‘", }.get(status, "βͺ") result += f"**{status_emoji} {status.replace('_', ' ').title()}:** {len(statements)} statement(s)\n" for stmt in statements[:3]: # Show first 3 confidence_emoji = { "high": "π₯", "medium": "β‘", "low": "π«", }.get(stmt["confidence"], "β") result += f" β’ {stmt.get('vendor', 'Unknown')} {confidence_emoji}\n" result += f" URL: {stmt.get('url', 'N/A')[:80]}...\n" if len(statements) > 3: result += f" ... and {len(statements) - 3} more\n" result += "\n" else: result += "π **Vendor Statements:** βͺ No vendor statements found in NVD references\n\n" # Product-specific guidance if product: result += f"π― **Product-Specific Guidance for '{product}':**\n" # Try to match product with known vendors product_lower = product.lower() if any( vendor in product_lower for vendor in ["microsoft", "windows", "office", "azure"] ): result += " β’ Check Microsoft Security Response Center (MSRC)\n" result += ( f" β’ URL: https://msrc.microsoft.com/blog/tag/{cve_id.lower()}/\n" ) elif any( vendor in product_lower for vendor in ["redhat", "rhel", "centos", "fedora"] ): result += " β’ Check Red Hat Security Portal\n" result += f" β’ URL: https://access.redhat.com/security/cve/{cve_id}\n" elif any(vendor in product_lower for vendor in ["ubuntu", "canonical"]): result += " β’ Check Ubuntu Security Notices\n" result += f" β’ URL: https://ubuntu.com/security/{cve_id}\n" elif any(vendor in product_lower for vendor in ["debian"]): result += " β’ Check Debian Security Tracker\n" result += ( f" β’ URL: https://security-tracker.debian.org/tracker/{cve_id}\n" ) elif any(vendor in product_lower for vendor in ["apache"]): result += " β’ Check Apache Security Reports\n" result += ( " β’ URL: https://httpd.apache.org/security/vulnerabilities_24.html\n" ) else: result += " β’ Check the vendor's security advisory page\n" result += f" β’ Search for '{cve_id}' on the vendor's website\n" result += "\n" # Manual VEX Check Guidance result += "π **Manual VEX Verification:**\n\n" vex_sources = vex_data.get("recommended_vex_sources", {}) for source, url in vex_sources.items(): result += f"**{source}:**\n" result += f" β’ URL: {url}\n" if source == "CISA": result += f" β’ Check if {cve_id} is in Known Exploited Vulnerabilities Catalog\n" else: result += " β’ Look for VEX statements or vulnerability status\n" result += "\n" # GitHub VEX Search github_data = vex_data.get("github_vex_search", {}) if github_data.get("search_urls"): result += "**π GitHub VEX Document Search:**\n" for url in github_data["search_urls"]: result += f" β’ {url}\n" result += " β’ Look for CSAF/VEX documents mentioning this CVE\n\n" # Creating VEX Statements result += "π **Creating VEX Statements:**\n" result += "If you're a vendor/maintainer, create VEX statements using:\n" result += " β’ **CSAF Format:** Common Security Advisory Framework\n" result += " β’ **OpenVEX:** Simplified VEX format\n" result += " β’ **SARIF:** Static Analysis Results Interchange Format\n\n" result += "π» **VEX Tools:**\n" result += " β’ OpenVEX CLI: https://github.com/openvex/vexctl\n" result += " β’ CSAF Validator: https://github.com/csaf-poc/csaf_distribution\n" result += " β’ VEX Hub: https://vexhub.org/\n\n" # Current VEX Ecosystem Status result += "π **VEX Ecosystem Status:**\n" result += " β’ π **Adoption:** Growing, but still early stage\n" result += ( " β’ π’ **Major Vendors:** Microsoft, Red Hat, Google starting adoption\n" ) result += " β’ π§ **Tools:** Limited but improving tooling ecosystem\n" result += " β’ π **Standards:** CSAF 2.0, OpenVEX gaining traction\n\n" result += "β οΈ **Important Notes:**\n" result += ( " β’ VEX adoption is still developing - many vendors don't provide VEX yet\n" ) result += " β’ Manual verification of vendor advisories is still necessary\n" result += " β’ VEX statements are authoritative only from the product vendor\n" result += " β’ Absence of VEX statement doesn't mean product is affected\n\n" result += f"π **Report Generated:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" return [types.TextContent(type="text", text=result)]
- mcp_simple_tool/server.py:272-289 (registration)Tool registration in list_tools(), including name, description, and input schema defining 'cve_id' as required string and 'product' as optional string.types.Tool( name="get_vex_status", description="Check VEX vulnerability status for specific products", inputSchema={ "type": "object", "required": ["cve_id"], "properties": { "cve_id": { "type": "string", "description": vex_description, }, "product": { "type": "string", "description": "Product name or identifier to check VEX status for (optional). Examples: 'Windows 11', 'RHEL 8', 'Ubuntu 22.04', 'Apache HTTP Server'", }, }, }, ),
- mcp_simple_tool/server.py:148-156 (registration)Dispatch logic in the call_tool handler that validates arguments and invokes the get_vex_status function.elif name == "get_vex_status": if "cve_id" not in arguments: return [ types.TextContent( type="text", text="Error: Missing required argument 'cve_id'" ) ] product = arguments.get("product") # Optional parameter return await get_vex_status(arguments["cve_id"], product)
- mcp_simple_tool/server.py:275-289 (schema)Input schema for the get_vex_status tool, specifying parameters and their types/descriptions.inputSchema={ "type": "object", "required": ["cve_id"], "properties": { "cve_id": { "type": "string", "description": vex_description, }, "product": { "type": "string", "description": "Product name or identifier to check VEX status for (optional). Examples: 'Windows 11', 'RHEL 8', 'Ubuntu 22.04', 'Apache HTTP Server'", }, }, }, ),
- Import and export of the get_vex_status function in the tools package __init__ for easy access.from .vex_status import get_vex_status from .vulnerability_search import search_vulnerabilities from .vulnerability_timeline import get_vulnerability_timeline __all__ = [ "lookup_cve", "check_package_vulnerabilities", "get_epss_score", "calculate_cvss_score", "search_vulnerabilities", "get_exploit_availability", "get_vulnerability_timeline", "get_vex_status", ]