| name | exploitiq-analyze |
| description | Use when the user wants to analyze a CVE against a source code repository, analyze an SBOM file (SPDX or CycloneDX) for vulnerability exploitability, or analyze a CVE against a specific RPM package using the ExploitIQ service. |
ExploitIQ Analyze
Submit a vulnerability analysis and retrieve results from the ExploitIQ service.
Determine Analysis Type
From the user's input, determine which type of analysis to perform:
Option A: CVE + Source Repo
Required parameters:
cveId — CVE ID (e.g., CVE-2024-1234)
sourceRepo — Git repository URL (must be https://)
commitId — Commit hash or branch/tag reference
If any are missing, ask the user for them.
If the repo is private, ask the user for authentication:
userName — Git username
secretValue — Personal access token or SSH key
Call mcp__exploitiq__analyze_cve with the parameters.
Response: ReportData
{
"reportRequestId": {
"id": "<MongoDB ObjectId — use for retry/delete operations>",
"reportId": "<Scan ID — use for polling with get_cve_report_by_scan_id>"
},
"report": { ... }
}
Display after submission:
- Report ID (ObjectId):
reportRequestId.id
- Scan ID:
reportRequestId.reportId
Option B: SBOM File
Required: a file path to an SBOM file on disk.
- Determine the SBOM format:
- File contains
"spdxVersion" or extension is .spdx.json → SPDX
- File contains
"bomFormat" or extension is .cdx.json → CycloneDX
- If ambiguous, ask the user
- Read the file using the Read tool
- Base64-encode the content using Bash:
base64 -w0 <filepath>
- Call
mcp__exploitiq__analyze_spdx_sbom or mcp__exploitiq__analyze_cyclonedx_sbom with:
fileContent — the base64-encoded string
cveId — (optional) if the user wants to filter to a specific CVE
If the repo referenced in the SBOM is private, ask for userName and secretValue.
CycloneDX Response: ReportData
Same structure as Option A — contains reportRequestId.id and reportRequestId.reportId.
SPDX Response: generic object
The SPDX upload creates a product (multi-component). The response is a generic object — look for an id field which is the Product ID. Use mcp__exploitiq__get_product with that ID to check status, or mcp__exploitiq__list_cve_reports with productId filter to find the individual component reports.
Option C: RPM Package Analysis
Required parameters:
cveId — CVE ID (e.g., CVE-2024-1234), must match CVE-YYYY-NNNN+ format
packageName — RPM package name (e.g., openssl, curl, kernel)
packageVersion — Package version (e.g., 1.1.1k)
packageRelease — Package release string (e.g., 8.el9_9)
Optional parameters:
packageArch — Architecture (default: x86_64). Valid values: x86_64, amd64, aarch64, arm64, ppc64le, s390x
If any required parameter is missing, ask the user for it.
Call mcp__exploitiq__analyze_rpm with the parameters.
This uses the RPM package checker pipeline, which performs a focused two-level investigation:
- Level 1 (Package Code Agent): Analyzes extracted SRPM source to determine if the CVE applies and if patches exist
- Level 2 (Build Agent): If L1 finds the package vulnerable, checks whether the vulnerable code is compiled into the binary and evaluates compiler hardening mitigations
Response: ReportData
Same structure as Option A — contains reportRequestId.id and reportRequestId.reportId.
After Submission
- Display the IDs from the response (see above)
- Ask: "Analysis submitted. Want me to poll for results?"
Polling for Results
If the user says yes:
For CVE / CycloneDX analysis (has a scan ID):
- Wait 30 seconds (use
sleep 30 via Bash)
- Call
mcp__exploitiq__get_cve_report_by_scan_id with the scan ID (reportRequestId.reportId)
- The response is a
ReportWithStatus object:
{
"report": { <FullReport object — see "FullReport Document Structure" below> },
"status": "completed"
}
- Check the
status field:
completed → present results (see "Presenting Results" below)
failed or expired → offer to retry (see "Retry on Failure" below)
- Any other status (
sent, queued, pending) → go back to step 1
- Continue polling for up to 60 minutes. If the user says stop, or 60 minutes have elapsed, stop polling and report the last known status.
For SPDX analysis (has a product ID):
- Wait 30 seconds (use
sleep 30 via Bash)
- Call
mcp__exploitiq__get_product with the product ID
- The response is a
ProductSummary (see exploitiq-products skill for structure)
- Check
summary.productState — when all component reports are done, present the product summary
- To see individual component results, call
mcp__exploitiq__list_cve_reports with productId filter
FullReport Document Structure
The report field inside ReportWithStatus is a raw MongoDB document (Record<string, any>). Fields may be absent depending on analysis state and backend version. Always check for existence before accessing nested fields.
Top-level fields
report._id — MongoDB ObjectId (hex string), use for retry/delete
report.input — Scan and image input data
report.output — Analysis results
report.info — VDB and intel metadata
report.metadata — User-provided metadata (e.g., product_id, environment)
report.error — Present when analysis failed: { message, type }
Input fields (report.input)
report.input.scan.id — Scan ID
report.input.scan.type — "image" or "source"
report.input.scan.started_at — ISO timestamp
report.input.scan.completed_at — ISO timestamp (empty string if not completed)
report.input.scan.vulns[] — Array of vulnerability info:
.vuln_id — CVE ID (e.g., "CVE-2024-1001")
.description — Vulnerability description
.score — CVSS score (number)
.severity — "CRITICAL", "HIGH", "MEDIUM", "LOW"
.published_date — Date string
.last_modified_date — Date string
.url — CVE URL
.package — Package identifier
.package_name — Package name
.package_version — Package version
.package_type — Package ecosystem type (e.g., "npm", "maven")
report.input.image.analysis_type — "image" or "source"
report.input.image.ecosystem — Programming language ecosystem (e.g., "nodejs", "java")
report.input.image.name — Image/repo name
report.input.image.tag — Image tag or commit hash
report.input.image.source_info[] — Array of source info:
.type — "git" or "code"
.git_repo — Repository URL
.ref — Git reference (branch/tag/commit)
Output fields (report.output)
The analysis results are in report.output.analysis[] — an array with one entry per vulnerability analyzed:
report.output.analysis[i].vuln_id — CVE ID for this analysis
report.output.analysis[i].justification — Verdict object:
.status — "TRUE" (vulnerable), "FALSE" (not vulnerable), or "UNKNOWN"
.label — "vulnerable", "not_vulnerable", or "uncertain"
.reason — Explanation of the verdict (markdown text)
report.output.analysis[i].summary — Summary text of the analysis conclusion (markdown)
report.output.analysis[i].checklist[] — Array of checklist items:
.input — The checklist question
.response — The answer/finding
.intermediate_steps — Intermediate analysis steps (string or null)
report.output.analysis[i].cvss — CVSS score info (may be null):
.score — Score as string (e.g., "8.7")
.vector_string — CVSS vector (e.g., "CVSS:3.1/AV:N/AC:H/...")
report.output.analysis[i].intel_score — Intel reliability score (number or null)
report.output.vex — VEX data (object or null)
Info fields (report.info)
report.info.vdb.version — VDB version
report.info.intel — Intel data (array of IntelEntry or legacy { score } object)
Presenting Results
When a report is completed, extract fields from report.output.analysis[i] for each vulnerability and present:
Analysis Result
CVE: report.input.scan.vulns[0].vuln_id
Package: report.input.scan.vulns[0].package_name vreport.input.scan.vulns[0].package_version
Ecosystem: report.input.image.ecosystem
Repository: report.input.image.source_info[0].git_repo
CVSS Score: analysis[i].cvss.score (analysis[i].cvss.vector_string)
Verdict: analysis[i].justification.status — display as Vulnerable (TRUE), Not Vulnerable (FALSE), or Uncertain (UNKNOWN)
Justification
analysis[i].justification.reason
Summary
analysis[i].summary
Checklist
| # | Question | Answer |
|---|
| 1 | checklist[0].input | checklist[0].response |
| ... | ... | ... |
If intermediate_steps is present and non-null for any item, show it below the table under "Investigation Details".
RPM Package Checker Fields
For RPM package analyses (Option C), the report may also contain these fields in each vulnerability result (report.output.analysis[i]):
is_target_package_affected — "yes", "no", or "unknown" — whether the target RPM package is affected by the CVE
is_target_package_fixed — "yes", "no", or "unknown" — whether a fix is in place for the target package
conclusion_reason — detailed explanation of the vulnerability determination
When present, display these after the verdict:
Package Affected: is_target_package_affected
Fix in Place: is_target_package_fixed
Conclusion: conclusion_reason
If any field is missing or empty, note it as "Not available".
If report.error is present, show:
- Error:
report.error.message (report.error.type)
Retry on Failure
If the report status is failed or expired:
- Tell the user: "Analysis failed/expired. Want me to retry?"
- If yes, call
mcp__exploitiq__retry_cve_analysis with the report's MongoDB ObjectId (the _id field from the report document, NOT the scan ID). This is a 24-character hex string.
- The response is a plain string (the new report ID) or null.
- Resume polling with the same scan ID.