| name | cve-lookup |
| description | CVE detail lookup from NVD API v2 with CVSS scores, vectors, and affected products |
| license | MIT |
| metadata | {"category":"vuln-analysis","locale":"en","phase":"v1"} |
What this skill does
Queries CVE details via the NIST NVD (National Vulnerability Database) API v2. Parses CVSS v3/v2 scores and vectors, vulnerability descriptions, reference links, and affected product (CPE) lists, then outputs the results in a human-readable report format.
When to use
- When you need to quickly understand the severity and attack vector of a specific CVE
- When validating and prioritizing vulnerabilities found in scan results
- When checking affected product versions to plan a patching strategy
- When you need official CVE information for writing a vulnerability report
Prerequisites
Inputs
| Variable | Required | Description |
|---|
SECSKILL_CVE_ID | Required | CVE ID to look up (e.g. CVE-2024-1234) |
SECSKILL_OUTPUT_DIR | Optional | Directory to save results (default: ./output) |
SECSKILL_NVD_API_KEY | Optional | NVD API key (relaxes rate limits) |
Workflow
Step 1: Environment setup and CVE ID validation
export CVE_ID="${SECSKILL_CVE_ID:?Set the SECSKILL_CVE_ID environment variable (e.g. CVE-2024-1234)}"
export OUTDIR="${SECSKILL_OUTPUT_DIR:-./output}"
export NVD_KEY="${SECSKILL_NVD_API_KEY:-}"
mkdir -p "$OUTDIR"
if ! echo "$CVE_ID" | grep -qE '^CVE-[0-9]{4}-[0-9]{4,}$'; then
echo "[-] Invalid CVE ID format: $CVE_ID (expected format: CVE-YYYY-NNNNN)"
exit 1
fi
echo "[*] Starting CVE lookup: $CVE_ID"
OUTFILE="$OUTDIR/cve_${CVE_ID}.txt"
Step 2: Query the NVD API v2
echo "[*] Querying NVD API..."
NVD_URL="https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=${CVE_ID}"
RAW_JSON="$OUTDIR/cve_raw_${CVE_ID}.json"
API_HEADER=""
[ -n "$NVD_KEY" ] && API_HEADER="-H apiKey:${NVD_KEY}"
HTTP_CODE=$(curl -s -o "$RAW_JSON" -w "%{http_code}" \
--max-time 30 \
--retry 3 \
--retry-delay 6 \
$API_HEADER \
"$NVD_URL")
if [ "$HTTP_CODE" = "404" ]; then
echo "[-] CVE not found: $CVE_ID"
exit 1
elif [ "$HTTP_CODE" != "200" ]; then
echo "[-] NVD API error (HTTP $HTTP_CODE)"
exit 1
fi
TOTAL=$(jq '.totalResults' "$RAW_JSON" 2>/dev/null)
if [ "$TOTAL" = "0" ] || [ -z "$TOTAL" ]; then
echo "[-] No data found for $CVE_ID"
exit 1
fi
echo "[+] CVE data received successfully"
Step 3: Parse basic information
echo "[*] Parsing basic information..."
PUBLISHED=$(jq -r '.vulnerabilities[0].cve.published' "$RAW_JSON")
MODIFIED=$(jq -r '.vulnerabilities[0].cve.lastModified' "$RAW_JSON")
STATUS=$(jq -r '.vulnerabilities[0].cve.vulnStatus' "$RAW_JSON")
DESCRIPTION=$(jq -r '.vulnerabilities[0].cve.descriptions[] | select(.lang=="en") | .value' "$RAW_JSON" | head -1)
cat > "$OUTFILE" << EOF
===================================================
CVE Detail Report: $CVE_ID
===================================================
Published : $PUBLISHED
Last Modified : $MODIFIED
Status : $STATUS
[ Description ]
$DESCRIPTION
EOF
echo "[+] Basic information parsed"
Step 4: Parse CVSS scores and vectors
echo "[*] Parsing CVSS scores..."
CVSS3_SCORE=$(jq -r '.vulnerabilities[0].cve.metrics.cvssMetricV31[0].cvssData.baseScore // .vulnerabilities[0].cve.metrics.cvssMetricV30[0].cvssData.baseScore // "N/A"' "$RAW_JSON")
CVSS3_SEVERITY=$(jq -r '.vulnerabilities[0].cve.metrics.cvssMetricV31[0].cvssData.baseSeverity // .vulnerabilities[0].cve.metrics.cvssMetricV30[0].cvssData.baseSeverity // "N/A"' "$RAW_JSON")
CVSS3_VECTOR=$(jq -r '.vulnerabilities[0].cve.metrics.cvssMetricV31[0].cvssData.vectorString // .vulnerabilities[0].cve.metrics.cvssMetricV30[0].cvssData.vectorString // "N/A"' "$RAW_JSON")
CVSS2_SCORE=$(jq -r '.vulnerabilities[0].cve.metrics.cvssMetricV2[0].cvssData.baseScore // "N/A"' "$RAW_JSON")
CVSS2_SEVERITY=$(jq -r '.vulnerabilities[0].cve.metrics.cvssMetricV2[0].baseSeverity // "N/A"' "$RAW_JSON")
cat >> "$OUTFILE" << EOF
[ CVSS Scores ]
CVSS v3 Base Score : $CVSS3_SCORE ($CVSS3_SEVERITY)
CVSS v3 Vector : $CVSS3_VECTOR
CVSS v2 Base Score : $CVSS2_SCORE ($CVSS2_SEVERITY)
EOF
echo ""
echo " CVSS v3 : $CVSS3_SCORE ($CVSS3_SEVERITY)"
echo " Vector : $CVSS3_VECTOR"
Step 5: Parse CWE and affected products
echo "[*] Parsing CWE and affected products..."
CWE=$(jq -r '.vulnerabilities[0].cve.weaknesses[0].description[0].value // "N/A"' "$RAW_JSON")
echo "[ Vulnerability Type ]" >> "$OUTFILE"
echo "CWE: $CWE" >> "$OUTFILE"
echo "" >> "$OUTFILE"
echo "[ Affected Products (top 20) ]" >> "$OUTFILE"
jq -r '.vulnerabilities[0].cve.configurations[]?.nodes[]?.cpeMatch[]? | select(.vulnerable==true) | .criteria' "$RAW_JSON" 2>/dev/null \
| head -20 \
| sed 's/cpe:2.3://g' \
| tee -a "$OUTFILE"
echo "" >> "$OUTFILE"
Step 6: Parse reference links
echo "[*] Parsing reference links..."
echo "[ Reference Links (top 10) ]" >> "$OUTFILE"
jq -r '.vulnerabilities[0].cve.references[].url' "$RAW_JSON" 2>/dev/null \
| head -10 \
| tee -a "$OUTFILE"
Step 7: Display results
echo ""
echo "===== CVE Lookup Complete ====="
cat "$OUTFILE"
echo ""
echo "Detailed results saved : $OUTFILE"
echo "Raw JSON : $RAW_JSON"
Done when
- NVD API responds successfully (HTTP 200)
- CVSS score and severity are printed
- Vulnerability description is parsed
- Result file is created
Failure modes
| Symptom | Cause | Resolution |
|---|
| HTTP 404 | CVE ID does not exist | Verify the CVE ID spelling |
| HTTP 403/429 | Rate limit hit (5 req/s without key) | Set SECSKILL_NVD_API_KEY or wait 6 seconds |
| CVSS score shows "N/A" | New CVE not yet analyzed | Check directly on the NVD website |
| jq parse error | API response structure changed | Inspect raw response with `cat $RAW_JSON |
Notes
- Works without an NVD API key, but bulk lookups will hit rate limits (5 req/s without key, 50 req/s with key).
- CVSS v3 score ranges: 0.0 (None), 0.1–3.9 (Low), 4.0–6.9 (Medium), 7.0–8.9 (High), 9.0–10.0 (Critical).
- To also check EPSS (Exploit Prediction Scoring System) scores, use
https://api.first.org/data/v1/epss?cve=$CVE_ID.
- Results can be used with the
nuclei-scan skill to help prioritize vulnerability findings.