// NVD CVE Lookup Routes const express = require('express'); const CVE_ID_PATTERN = /^CVE-\d{4}-\d{4,}$/; function createNvdLookupRouter(db, requireAuth) { const router = express.Router(); // All routes require authentication router.use(requireAuth(db)); // Lookup CVE details from NVD API 2.0 router.get('/lookup/:cveId', async (req, res) => { const { cveId } = req.params; if (!CVE_ID_PATTERN.test(cveId)) { return res.status(400).json({ error: 'Invalid CVE ID format. Expected CVE-YYYY-NNNNN.' }); } const url = `https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=${encodeURIComponent(cveId)}`; const headers = {}; if (process.env.NVD_API_KEY) { headers['apiKey'] = process.env.NVD_API_KEY; } try { const response = await fetch(url, { headers, signal: AbortSignal.timeout(10000) }); if (response.status === 404) { return res.status(404).json({ error: 'CVE not found in NVD.' }); } if (response.status === 429) { return res.status(429).json({ error: 'NVD API rate limit exceeded. Try again later.' }); } if (!response.ok) { return res.status(502).json({ error: `NVD API returned status ${response.status}.` }); } const data = await response.json(); if (!data.vulnerabilities || data.vulnerabilities.length === 0) { return res.status(404).json({ error: 'CVE not found in NVD.' }); } const vuln = data.vulnerabilities[0].cve; // Extract English description const descriptionEntry = vuln.descriptions?.find(d => d.lang === 'en'); const description = descriptionEntry ? descriptionEntry.value : ''; // Extract severity with cascade: CVSS v3.1 → v3.0 → v2.0 let severity = null; const metrics = vuln.metrics || {}; if (metrics.cvssMetricV31 && metrics.cvssMetricV31.length > 0) { severity = metrics.cvssMetricV31[0].cvssData?.baseSeverity; } else if (metrics.cvssMetricV30 && metrics.cvssMetricV30.length > 0) { severity = metrics.cvssMetricV30[0].cvssData?.baseSeverity; } else if (metrics.cvssMetricV2 && metrics.cvssMetricV2.length > 0) { severity = metrics.cvssMetricV2[0].baseSeverity; } // Map NVD severity strings to app levels const severityMap = { 'CRITICAL': 'Critical', 'HIGH': 'High', 'MEDIUM': 'Medium', 'LOW': 'Low' }; severity = severity ? (severityMap[severity.toUpperCase()] || 'Medium') : 'Medium'; // Extract published date (YYYY-MM-DD) const publishedRaw = vuln.published; const published_date = publishedRaw ? publishedRaw.split('T')[0] : ''; res.json({ description, severity, published_date }); } catch (err) { if (err.name === 'TimeoutError' || err.name === 'AbortError') { return res.status(504).json({ error: 'NVD API request timed out.' }); } console.error('NVD lookup error:', err); res.status(502).json({ error: 'Failed to reach NVD API.' }); } }); return router; } module.exports = createNvdLookupRouter;