Skip to content

CVE Mapping

This example demonstrates how to map CPE names to Common Vulnerabilities and Exposures (CVE) for comprehensive vulnerability management and security assessment.

Overview

CVE mapping allows you to correlate software components identified by CPE names with known security vulnerabilities. This is essential for vulnerability assessment, patch management, and security compliance.

Complete Example

go
package main

import (
    "fmt"
    "log"
    "sort"
    "time"
    "github.com/scagogogo/cpe"
)

func main() {
    fmt.Println("=== CVE Mapping Examples ===")
    
    // Example 1: Basic CPE to CVE Mapping
    fmt.Println("\n1. Basic CPE to CVE Mapping:")
    
    // Initialize CVE database
    cveDB := cpe.NewCVEDatabase()
    
    // Load sample CVE data (in real implementation, this would load from NVD)
    err := loadSampleCVEData(cveDB)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("Loaded %d CVE entries\n", cveDB.Count())
    
    // Test CPEs for vulnerability lookup
    testCPEs := []string{
        "cpe:2.3:a:apache:log4j:2.14.1:*:*:*:*:*:*:*",
        "cpe:2.3:a:apache:tomcat:8.5.0:*:*:*:*:*:*:*",
        "cpe:2.3:a:oracle:java:8.0.291:*:*:*:*:*:*:*",
        "cpe:2.3:o:microsoft:windows:10:*:*:*:*:*:*:*",
        "cpe:2.3:a:nginx:nginx:1.18.0:*:*:*:*:*:*:*",
    }
    
    for _, cpeStr := range testCPEs {
        fmt.Printf("\nCPE: %s\n", cpeStr)
        
        cves := cveDB.FindCVEsForCPE(cpeStr)
        
        if len(cves) == 0 {
            fmt.Println("  ✅ No known vulnerabilities")
        } else {
            fmt.Printf("  ⚠️  Found %d vulnerabilities:\n", len(cves))
            
            for i, cve := range cves[:min(3, len(cves))] { // Show first 3
                fmt.Printf("    %d. %s (CVSS: %.1f)\n", i+1, cve.ID, cve.BaseScore)
                fmt.Printf("       %s\n", truncateString(cve.Description, 60))
            }
            
            if len(cves) > 3 {
                fmt.Printf("    ... and %d more\n", len(cves)-3)
            }
        }
    }
    
    // Example 2: Version Range Vulnerability Mapping
    fmt.Println("\n2. Version Range Vulnerability Mapping:")
    
    // Check vulnerabilities across version ranges
    versionRanges := []struct {
        product string
        vendor  string
        versions []string
    }{
        {
            product: "log4j",
            vendor:  "apache",
            versions: []string{"2.0", "2.10.0", "2.14.1", "2.15.0", "2.16.0"},
        },
        {
            product: "tomcat",
            vendor:  "apache", 
            versions: []string{"8.5.0", "8.5.50", "9.0.0", "9.0.45", "10.0.0"},
        },
    }
    
    for _, vr := range versionRanges {
        fmt.Printf("\n%s %s version vulnerability analysis:\n", vr.vendor, vr.product)
        
        for _, version := range vr.versions {
            cpeStr := fmt.Sprintf("cpe:2.3:a:%s:%s:%s:*:*:*:*:*:*:*", vr.vendor, vr.product, version)
            cves := cveDB.FindCVEsForCPE(cpeStr)
            
            status := "✅"
            riskLevel := "Low"
            
            if len(cves) > 0 {
                maxScore := 0.0
                for _, cve := range cves {
                    if cve.BaseScore > maxScore {
                        maxScore = cve.BaseScore
                    }
                }
                
                switch {
                case maxScore >= 9.0:
                    status = "🔴"
                    riskLevel = "Critical"
                case maxScore >= 7.0:
                    status = "🟠"
                    riskLevel = "High"
                case maxScore >= 4.0:
                    status = "🟡"
                    riskLevel = "Medium"
                default:
                    status = "🟢"
                    riskLevel = "Low"
                }
            }
            
            fmt.Printf("  %s v%s: %d CVEs (%s risk)\n", status, version, len(cves), riskLevel)
        }
    }
    
    // Example 3: System Inventory Vulnerability Assessment
    fmt.Println("\n3. System Inventory Vulnerability Assessment:")
    
    // Define a system inventory
    systemInventory := []struct {
        name string
        cpes []string
    }{
        {
            name: "Web Server",
            cpes: []string{
                "cpe:2.3:o:canonical:ubuntu:20.04:*:*:*:*:*:*:*",
                "cpe:2.3:a:apache:http_server:2.4.41:*:*:*:*:*:*:*",
                "cpe:2.3:a:apache:tomcat:8.5.0:*:*:*:*:*:*:*",
                "cpe:2.3:a:oracle:java:8.0.291:*:*:*:*:*:*:*",
            },
        },
        {
            name: "Application Server",
            cpes: []string{
                "cpe:2.3:o:redhat:enterprise_linux:8:*:*:*:*:*:*:*",
                "cpe:2.3:a:apache:tomcat:9.0.45:*:*:*:*:*:*:*",
                "cpe:2.3:a:oracle:java:11.0.12:*:*:*:*:*:*:*",
                "cpe:2.3:a:apache:log4j:2.14.1:*:*:*:*:*:*:*",
            },
        },
        {
            name: "Desktop Workstation",
            cpes: []string{
                "cpe:2.3:o:microsoft:windows:10:*:*:*:*:*:*:*",
                "cpe:2.3:a:microsoft:office:2019:*:*:*:*:*:*:*",
                "cpe:2.3:a:mozilla:firefox:95.0:*:*:*:*:*:*:*",
                "cpe:2.3:a:adobe:reader:2021.001.20150:*:*:*:*:*:*:*",
            },
        },
    }
    
    fmt.Println("System vulnerability assessment:")
    
    for _, system := range systemInventory {
        fmt.Printf("\n%s:\n", system.name)
        
        totalCVEs := 0
        criticalCVEs := 0
        highCVEs := 0
        maxScore := 0.0
        
        for _, cpeStr := range system.cpes {
            cves := cveDB.FindCVEsForCPE(cpeStr)
            totalCVEs += len(cves)
            
            for _, cve := range cves {
                if cve.BaseScore > maxScore {
                    maxScore = cve.BaseScore
                }
                
                if cve.BaseScore >= 9.0 {
                    criticalCVEs++
                } else if cve.BaseScore >= 7.0 {
                    highCVEs++
                }
            }
        }
        
        riskLevel := calculateRiskLevel(maxScore)
        
        fmt.Printf("  Components: %d\n", len(system.cpes))
        fmt.Printf("  Total CVEs: %d\n", totalCVEs)
        fmt.Printf("  Critical: %d, High: %d\n", criticalCVEs, highCVEs)
        fmt.Printf("  Max CVSS: %.1f\n", maxScore)
        fmt.Printf("  Risk Level: %s\n", riskLevel)
    }
    
    // Example 4: CVE Timeline Analysis
    fmt.Println("\n4. CVE Timeline Analysis:")
    
    targetCPE := "cpe:2.3:a:apache:log4j:2.14.1:*:*:*:*:*:*:*"
    cves := cveDB.FindCVEsForCPE(targetCPE)
    
    fmt.Printf("CVE timeline for %s:\n", targetCPE)
    
    if len(cves) == 0 {
        fmt.Println("  No CVEs found")
    } else {
        // Sort CVEs by publication date
        sort.Slice(cves, func(i, j int) bool {
            return cves[i].PublishedDate.Before(cves[j].PublishedDate)
        })
        
        for _, cve := range cves {
            fmt.Printf("  %s: %s (CVSS: %.1f)\n", 
                cve.PublishedDate.Format("2006-01-02"), cve.ID, cve.BaseScore)
        }
        
        // Calculate vulnerability trend
        if len(cves) > 1 {
            firstCVE := cves[0].PublishedDate
            lastCVE := cves[len(cves)-1].PublishedDate
            timespan := lastCVE.Sub(firstCVE)
            
            fmt.Printf("\nVulnerability trend:\n")
            fmt.Printf("  First CVE: %s\n", firstCVE.Format("2006-01-02"))
            fmt.Printf("  Latest CVE: %s\n", lastCVE.Format("2006-01-02"))
            fmt.Printf("  Timespan: %.0f days\n", timespan.Hours()/24)
            fmt.Printf("  Rate: %.2f CVEs/month\n", float64(len(cves))/(timespan.Hours()/24/30))
        }
    }
    
    // Example 5: Patch Priority Analysis
    fmt.Println("\n5. Patch Priority Analysis:")
    
    // Analyze patch priorities for multiple systems
    patchCandidates := []string{
        "cpe:2.3:a:apache:log4j:2.14.1:*:*:*:*:*:*:*",
        "cpe:2.3:a:apache:tomcat:8.5.0:*:*:*:*:*:*:*",
        "cpe:2.3:a:oracle:java:8.0.291:*:*:*:*:*:*:*",
        "cpe:2.3:a:microsoft:office:2019:*:*:*:*:*:*:*",
    }
    
    type patchPriority struct {
        cpe         string
        cveCount    int
        maxScore    float64
        priority    string
        urgency     string
    }
    
    var priorities []patchPriority
    
    for _, cpeStr := range patchCandidates {
        cves := cveDB.FindCVEsForCPE(cpeStr)
        
        maxScore := 0.0
        for _, cve := range cves {
            if cve.BaseScore > maxScore {
                maxScore = cve.BaseScore
            }
        }
        
        priority := calculatePatchPriority(len(cves), maxScore)
        urgency := calculateUrgency(maxScore, cves)
        
        priorities = append(priorities, patchPriority{
            cpe:      cpeStr,
            cveCount: len(cves),
            maxScore: maxScore,
            priority: priority,
            urgency:  urgency,
        })
    }
    
    // Sort by priority (highest score first)
    sort.Slice(priorities, func(i, j int) bool {
        return priorities[i].maxScore > priorities[j].maxScore
    })
    
    fmt.Println("Patch priority ranking:")
    for i, p := range priorities {
        cpeObj, _ := cpe.ParseCpe23(p.cpe)
        fmt.Printf("  %d. %s %s\n", i+1, cpeObj.Vendor, cpeObj.ProductName)
        fmt.Printf("     CVEs: %d, Max CVSS: %.1f\n", p.cveCount, p.maxScore)
        fmt.Printf("     Priority: %s, Urgency: %s\n", p.priority, p.urgency)
    }
    
    // Example 6: CVE Impact Analysis
    fmt.Println("\n6. CVE Impact Analysis:")
    
    // Analyze the impact of specific CVEs
    impactAnalysis := []string{
        "CVE-2021-44228", // Log4Shell
        "CVE-2021-45046", // Log4j follow-up
        "CVE-2017-5638",  // Apache Struts
    }
    
    for _, cveID := range impactAnalysis {
        fmt.Printf("\n%s Impact Analysis:\n", cveID)
        
        cveInfo := cveDB.GetCVE(cveID)
        if cveInfo == nil {
            fmt.Println("  CVE not found in database")
            continue
        }
        
        fmt.Printf("  CVSS Score: %.1f\n", cveInfo.BaseScore)
        fmt.Printf("  Published: %s\n", cveInfo.PublishedDate.Format("2006-01-02"))
        fmt.Printf("  Description: %s\n", cveInfo.Description)
        
        // Find affected CPEs
        affectedCPEs := cveDB.FindCPEsForCVE(cveID)
        fmt.Printf("  Affected CPEs: %d\n", len(affectedCPEs))
        
        if len(affectedCPEs) > 0 {
            fmt.Println("  Sample affected products:")
            for i, cpeStr := range affectedCPEs[:min(5, len(affectedCPEs))] {
                cpeObj, _ := cpe.ParseCpe23(cpeStr)
                fmt.Printf("    %d. %s %s %s\n", i+1, cpeObj.Vendor, cpeObj.ProductName, cpeObj.Version)
            }
        }
    }
    
    // Example 7: Export CVE Mapping Report
    fmt.Println("\n7. Export CVE Mapping Report:")
    
    // Generate comprehensive report
    report := cpe.NewCVEMappingReport()
    
    for _, system := range systemInventory {
        systemReport := &cpe.SystemVulnerabilityReport{
            SystemName: system.name,
            Components: make([]*cpe.ComponentVulnerability, 0),
        }
        
        for _, cpeStr := range system.cpes {
            cves := cveDB.FindCVEsForCPE(cpeStr)
            
            component := &cpe.ComponentVulnerability{
                CPE:             cpeStr,
                Vulnerabilities: cves,
            }
            
            systemReport.Components = append(systemReport.Components, component)
        }
        
        report.AddSystem(systemReport)
    }
    
    // Export to different formats
    formats := []string{"json", "csv", "html", "pdf"}
    
    for _, format := range formats {
        filename := fmt.Sprintf("cve_mapping_report.%s", format)
        err := report.ExportToFile(filename, format)
        if err != nil {
            log.Printf("Failed to export %s: %v", format, err)
        } else {
            fmt.Printf("✅ CVE mapping report exported to %s\n", filename)
        }
    }
}

// Helper functions
func loadSampleCVEData(db *cpe.CVEDatabase) error {
    sampleCVEs := []*cpe.CVEEntry{
        {
            ID:          "CVE-2021-44228",
            Description: "Apache Log4j2 JNDI features do not protect against attacker controlled LDAP and other JNDI related endpoints.",
            BaseScore:   10.0,
            PublishedDate: time.Date(2021, 12, 10, 0, 0, 0, 0, time.UTC),
            AffectedCPEs: []string{
                "cpe:2.3:a:apache:log4j:2.0:*:*:*:*:*:*:*",
                "cpe:2.3:a:apache:log4j:2.14.1:*:*:*:*:*:*:*",
            },
        },
        {
            ID:          "CVE-2021-25122",
            Description: "When responding to new h2c connection requests, Apache Tomcat could duplicate request headers and a request header could be used to poison the cache.",
            BaseScore:   7.5,
            PublishedDate: time.Date(2021, 3, 1, 0, 0, 0, 0, time.UTC),
            AffectedCPEs: []string{
                "cpe:2.3:a:apache:tomcat:8.5.0:*:*:*:*:*:*:*",
                "cpe:2.3:a:apache:tomcat:9.0.0:*:*:*:*:*:*:*",
            },
        },
    }
    
    for _, cve := range sampleCVEs {
        db.AddCVE(cve)
    }
    
    return nil
}

func calculateRiskLevel(score float64) string {
    switch {
    case score >= 9.0:
        return "🔴 Critical"
    case score >= 7.0:
        return "🟠 High"
    case score >= 4.0:
        return "🟡 Medium"
    case score > 0:
        return "🟢 Low"
    default:
        return "✅ None"
    }
}

func calculatePatchPriority(cveCount int, maxScore float64) string {
    if maxScore >= 9.0 || cveCount >= 5 {
        return "🔴 Critical"
    } else if maxScore >= 7.0 || cveCount >= 3 {
        return "🟠 High"
    } else if maxScore >= 4.0 || cveCount >= 1 {
        return "🟡 Medium"
    }
    return "🟢 Low"
}

func calculateUrgency(maxScore float64, cves []*cpe.CVEEntry) string {
    // Check for recent CVEs (within last 30 days)
    recentCVEs := 0
    thirtyDaysAgo := time.Now().AddDate(0, 0, -30)
    
    for _, cve := range cves {
        if cve.PublishedDate.After(thirtyDaysAgo) {
            recentCVEs++
        }
    }
    
    if maxScore >= 9.0 && recentCVEs > 0 {
        return "🚨 Immediate"
    } else if maxScore >= 7.0 {
        return "⏰ Urgent"
    } else if recentCVEs > 0 {
        return "📅 Soon"
    }
    return "📋 Scheduled"
}

func min(a, b int) int {
    if a < b {
        return a
    }
    return b
}

func truncateString(s string, maxLen int) string {
    if len(s) <= maxLen {
        return s
    }
    return s[:maxLen-3] + "..."
}

Key Concepts

1. CVE Mapping Process

  • CPE Identification: Identify software components using CPE names
  • Vulnerability Lookup: Find CVEs associated with each CPE
  • Impact Assessment: Evaluate severity and risk levels
  • Prioritization: Rank vulnerabilities for remediation

2. Risk Assessment

  • CVSS Scoring: Use Common Vulnerability Scoring System
  • Temporal Factors: Consider age and exploit availability
  • Environmental Context: Factor in system criticality
  • Business Impact: Assess potential business consequences

3. Reporting and Analysis

  • Vulnerability Reports: Generate comprehensive security reports
  • Trend Analysis: Track vulnerability patterns over time
  • Patch Management: Prioritize and schedule updates
  • Compliance: Meet security compliance requirements

Best Practices

  1. Regular Updates: Keep CVE database current
  2. Automated Scanning: Implement automated vulnerability scanning
  3. Risk-Based Prioritization: Focus on highest-risk vulnerabilities first
  4. Documentation: Maintain detailed vulnerability records
  5. Verification: Validate CVE mappings for accuracy

Integration Patterns

  1. CI/CD Integration: Include vulnerability scanning in build pipelines
  2. Asset Management: Link with configuration management databases
  3. Incident Response: Integrate with security incident workflows
  4. Compliance Reporting: Generate regulatory compliance reports

Performance Considerations

  1. Database Optimization: Index CVE data for fast lookups
  2. Caching: Cache frequently accessed vulnerability data
  3. Batch Processing: Process multiple CPEs efficiently
  4. Incremental Updates: Update only changed vulnerability data

Next Steps

Released under the MIT License.