Skip to content

Environmental Metrics Examples

This example demonstrates how to work with CVSS environmental metrics, which allow analysts to customize CVSS scores according to the importance of affected IT assets and the effectiveness of security controls in their specific environment.

Overview

Environmental metrics consist of two categories:

Environmental Requirements:

  • Confidentiality Requirement (CR) - Importance of confidentiality to the organization
  • Integrity Requirement (IR) - Importance of integrity to the organization
  • Availability Requirement (AR) - Importance of availability to the organization

Modified Base Metrics:

  • All base metrics can be modified to reflect environmental factors
  • Prefixed with "M" (e.g., MAV, MAC, MPR, etc.)

Basic Environmental Metrics

Understanding Environmental Impact

go
package main

import (
    "fmt"
    "log"

    "github.com/scagogogo/cvss-parser/pkg/cvss"
    "github.com/scagogogo/cvss-parser/pkg/parser"
)

func main() {
    // Base vector
    baseVector := "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
    
    // Environmental vector with requirements
    envVector := "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H/CR:H/IR:H/AR:H"
    
    // Environmental vector with modified base metrics
    modifiedVector := "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H/CR:H/IR:H/AR:H/MAV:L/MAC:H/MPR:H/MUI:R/MS:C/MC:H/MI:H/MA:H"

    fmt.Println("=== Environmental Metrics Impact ===")
    
    // Calculate base score
    baseParser := parser.NewCvss3xParser(baseVector)
    baseParsed, err := baseParser.Parse()
    if err != nil {
        log.Fatal(err)
    }

    baseCalc := cvss.NewCalculator(baseParsed)
    baseScore, _ := baseCalc.Calculate()

    // Calculate environmental score with requirements only
    envParser := parser.NewCvss3xParser(envVector)
    envParsed, err := envParser.Parse()
    if err != nil {
        log.Fatal(err)
    }

    envCalc := cvss.NewCalculator(envParsed)
    envScore, _ := envCalc.Calculate()

    // Calculate environmental score with modified metrics
    modParser := parser.NewCvss3xParser(modifiedVector)
    modParsed, err := modParser.Parse()
    if err != nil {
        log.Fatal(err)
    }

    modCalc := cvss.NewCalculator(modParsed)
    modScore, _ := modCalc.Calculate()

    fmt.Printf("Base Vector: %s\n", baseVector)
    fmt.Printf("Base Score: %.1f (%s)\n", baseScore, baseCalc.GetSeverityRating(baseScore))
    
    fmt.Printf("\nEnvironmental (Requirements): %s\n", envVector)
    fmt.Printf("Environmental Score: %.1f (%s)\n", envScore, envCalc.GetSeverityRating(envScore))
    fmt.Printf("Score Change: %+.1f points\n", envScore-baseScore)
    
    fmt.Printf("\nEnvironmental (Modified): %s\n", modifiedVector)
    fmt.Printf("Environmental Score: %.1f (%s)\n", modScore, modCalc.GetSeverityRating(modScore))
    fmt.Printf("Score Change: %+.1f points\n", modScore-baseScore)
}

Environmental Metrics Breakdown

go
func analyzeEnvironmentalMetrics(vector *cvss.Cvss3x) {
    if !vector.HasEnvironmental() {
        fmt.Println("No environmental metrics present")
        return
    }

    fmt.Println("=== Environmental Metrics Analysis ===")
    
    env := vector.Cvss3xEnvironmental
    
    // Requirements
    fmt.Println("Requirements:")
    if env.ConfidentialityRequirement != nil {
        fmt.Printf("  Confidentiality Requirement: %s (%c) - %.2f\n",
            env.ConfidentialityRequirement.GetLongValue(),
            env.ConfidentialityRequirement.GetShortValue(),
            env.ConfidentialityRequirement.GetScore())
    }
    
    if env.IntegrityRequirement != nil {
        fmt.Printf("  Integrity Requirement: %s (%c) - %.2f\n",
            env.IntegrityRequirement.GetLongValue(),
            env.IntegrityRequirement.GetShortValue(),
            env.IntegrityRequirement.GetScore())
    }
    
    if env.AvailabilityRequirement != nil {
        fmt.Printf("  Availability Requirement: %s (%c) - %.2f\n",
            env.AvailabilityRequirement.GetLongValue(),
            env.AvailabilityRequirement.GetShortValue(),
            env.AvailabilityRequirement.GetScore())
    }

    // Modified Base Metrics
    fmt.Println("\nModified Base Metrics:")
    if env.ModifiedAttackVector != nil {
        fmt.Printf("  Modified Attack Vector: %s (%c)\n",
            env.ModifiedAttackVector.GetLongValue(),
            env.ModifiedAttackVector.GetShortValue())
    }
    
    if env.ModifiedAttackComplexity != nil {
        fmt.Printf("  Modified Attack Complexity: %s (%c)\n",
            env.ModifiedAttackComplexity.GetLongValue(),
            env.ModifiedAttackComplexity.GetShortValue())
    }
    
    // ... other modified metrics
}

Environmental Requirements

Requirement Levels Impact

go
func demonstrateRequirementLevels() {
    baseVector := "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
    
    requirements := []struct {
        name   string
        suffix string
        desc   string
    }{
        {"Low Requirements", "/CR:L/IR:L/AR:L", "Low importance environment"},
        {"Medium Requirements", "/CR:M/IR:M/AR:M", "Medium importance environment"},
        {"High Requirements", "/CR:H/IR:H/AR:H", "High importance environment"},
        {"Mixed Requirements", "/CR:H/IR:M/AR:L", "Mixed importance levels"},
    }

    fmt.Println("=== Environmental Requirements Impact ===")
    fmt.Printf("Base Vector: %s\n\n", baseVector)

    // Calculate base score
    baseParser := parser.NewCvss3xParser(baseVector)
    baseParsed, _ := baseParser.Parse()
    baseCalc := cvss.NewCalculator(baseParsed)
    baseScore, _ := baseCalc.Calculate()

    fmt.Printf("Base Score: %.1f\n\n", baseScore)

    for _, req := range requirements {
        vectorStr := baseVector + req.suffix
        
        parser := parser.NewCvss3xParser(vectorStr)
        vector, _ := parser.Parse()
        
        calculator := cvss.NewCalculator(vector)
        score, _ := calculator.Calculate()
        severity := calculator.GetSeverityRating(score)
        change := score - baseScore

        fmt.Printf("%-20s: %.1f (%s) [%+.1f]\n", req.name, score, severity, change)
        fmt.Printf("  %s\n", req.desc)
        fmt.Printf("  Vector: %s\n", vectorStr)
        fmt.Println()
    }
}

Organizational Context Examples

go
func demonstrateOrganizationalContexts() {
    baseVector := "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
    
    contexts := []struct {
        organization string
        requirements string
        rationale    string
    }{
        {
            "Financial Institution",
            "/CR:H/IR:H/AR:H",
            "All aspects critical for regulatory compliance and customer trust",
        },
        {
            "E-commerce Platform",
            "/CR:H/IR:H/AR:H",
            "Customer data protection and transaction integrity essential",
        },
        {
            "Internal Development",
            "/CR:M/IR:M/AR:L",
            "Development environment with moderate sensitivity",
        },
        {
            "Public Website",
            "/CR:L/IR:M/AR:H",
            "Public information, but availability is crucial for business",
        },
        {
            "Research Environment",
            "/CR:H/IR:M/AR:L",
            "Sensitive research data, but availability less critical",
        },
    }

    fmt.Println("=== Organizational Context Examples ===")
    fmt.Printf("Base Vector: %s\n\n", baseVector)

    for _, context := range contexts {
        vectorStr := baseVector + context.requirements
        
        parser := parser.NewCvss3xParser(vectorStr)
        vector, _ := parser.Parse()
        
        calculator := cvss.NewCalculator(vector)
        score, _ := calculator.Calculate()
        severity := calculator.GetSeverityRating(score)

        fmt.Printf("Organization: %s\n", context.organization)
        fmt.Printf("  Score: %.1f (%s)\n", score, severity)
        fmt.Printf("  Requirements: %s\n", context.requirements)
        fmt.Printf("  Rationale: %s\n", context.rationale)
        fmt.Println()
    }
}

Modified Base Metrics

Security Controls Impact

go
func demonstrateSecurityControls() {
    baseVector := "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
    
    controls := []struct {
        name     string
        modified string
        desc     string
    }{
        {
            "Network Segmentation",
            "/MAV:L",
            "Network controls limit attack vector to local",
        },
        {
            "Authentication Required",
            "/MPR:H",
            "Strong authentication controls in place",
        },
        {
            "User Training",
            "/MUI:R",
            "User awareness training requires interaction",
        },
        {
            "Data Encryption",
            "/MC:L",
            "Encryption reduces confidentiality impact",
        },
        {
            "Backup Systems",
            "/MA:L",
            "Redundant systems reduce availability impact",
        },
        {
            "Combined Controls",
            "/MAV:L/MPR:H/MUI:R/MC:L/MI:L/MA:L",
            "Multiple security controls implemented",
        },
    }

    fmt.Println("=== Security Controls Impact ===")
    fmt.Printf("Base Vector: %s\n\n", baseVector)

    // Calculate base score
    baseParser := parser.NewCvss3xParser(baseVector)
    baseParsed, _ := baseParser.Parse()
    baseCalc := cvss.NewCalculator(baseParsed)
    baseScore, _ := baseCalc.Calculate()

    fmt.Printf("Base Score: %.1f\n\n", baseScore)

    for _, control := range controls {
        vectorStr := baseVector + "/CR:H/IR:H/AR:H" + control.modified
        
        parser := parser.NewCvss3xParser(vectorStr)
        vector, _ := parser.Parse()
        
        calculator := cvss.NewCalculator(vector)
        score, _ := calculator.Calculate()
        severity := calculator.GetSeverityRating(score)
        reduction := baseScore - score

        fmt.Printf("Control: %s\n", control.name)
        fmt.Printf("  Score: %.1f (%s) [%.1f reduction]\n", score, severity, reduction)
        fmt.Printf("  Modified: %s\n", control.modified)
        fmt.Printf("  Description: %s\n", control.desc)
        fmt.Println()
    }
}

Defense in Depth Analysis

go
func analyzeDefenseInDepth() {
    baseVector := "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
    
    layers := []struct {
        layer    string
        controls string
        desc     string
    }{
        {
            "No Controls",
            "",
            "Baseline vulnerability without controls",
        },
        {
            "Perimeter Security",
            "/MAV:A",
            "Firewall limits access to adjacent network",
        },
        {
            "Access Controls",
            "/MAV:A/MPR:L",
            "Basic authentication required",
        },
        {
            "Enhanced Authentication",
            "/MAV:A/MPR:H",
            "Multi-factor authentication implemented",
        },
        {
            "User Awareness",
            "/MAV:A/MPR:H/MUI:R",
            "User training reduces social engineering",
        },
        {
            "Data Protection",
            "/MAV:A/MPR:H/MUI:R/MC:L/MI:L",
            "Encryption and integrity controls",
        },
        {
            "Full Defense",
            "/MAV:L/MAC:H/MPR:H/MUI:R/MS:U/MC:L/MI:L/MA:L",
            "Comprehensive security controls",
        },
    }

    fmt.Println("=== Defense in Depth Analysis ===")
    fmt.Printf("Base Vector: %s\n\n", baseVector)

    for i, layer := range layers {
        vectorStr := baseVector + "/CR:H/IR:H/AR:H" + layer.controls
        
        parser := parser.NewCvss3xParser(vectorStr)
        vector, _ := parser.Parse()
        
        calculator := cvss.NewCalculator(vector)
        score, _ := calculator.Calculate()
        severity := calculator.GetSeverityRating(score)

        fmt.Printf("Layer %d: %s\n", i+1, layer.layer)
        fmt.Printf("  Score: %.1f (%s)\n", score, severity)
        fmt.Printf("  Controls: %s\n", layer.controls)
        fmt.Printf("  Description: %s\n", layer.desc)
        fmt.Println()
    }
}

Environmental Score Calculation

Detailed Calculation Breakdown

go
func explainEnvironmentalCalculation(vector *cvss.Cvss3x) {
    if !vector.HasEnvironmental() {
        fmt.Println("No environmental metrics to analyze")
        return
    }

    calculator := cvss.NewCalculator(vector)
    
    // Get individual scores
    baseScore, _ := calculator.CalculateBaseScore()
    envScore, _ := calculator.CalculateEnvironmentalScore()

    fmt.Println("=== Environmental Score Calculation ===")
    fmt.Printf("Base Score: %.1f\n", baseScore)
    
    env := vector.Cvss3xEnvironmental
    
    // Show requirement multipliers
    crMultiplier := 1.0
    if env.ConfidentialityRequirement != nil {
        crMultiplier = env.ConfidentialityRequirement.GetScore()
    }
    
    irMultiplier := 1.0
    if env.IntegrityRequirement != nil {
        irMultiplier = env.IntegrityRequirement.GetScore()
    }
    
    arMultiplier := 1.0
    if env.AvailabilityRequirement != nil {
        arMultiplier = env.AvailabilityRequirement.GetScore()
    }

    fmt.Printf("\nRequirement Multipliers:\n")
    fmt.Printf("  Confidentiality Requirement: %.1f\n", crMultiplier)
    fmt.Printf("  Integrity Requirement: %.1f\n", irMultiplier)
    fmt.Printf("  Availability Requirement: %.1f\n", arMultiplier)
    
    // Check for modified base metrics
    hasModified := env.ModifiedAttackVector != nil ||
                   env.ModifiedAttackComplexity != nil ||
                   env.ModifiedPrivilegesRequired != nil ||
                   env.ModifiedUserInteraction != nil ||
                   env.ModifiedScope != nil ||
                   env.ModifiedConfidentialityImpact != nil ||
                   env.ModifiedIntegrityImpact != nil ||
                   env.ModifiedAvailabilityImpact != nil

    if hasModified {
        fmt.Printf("\nModified Base Metrics Present:\n")
        fmt.Printf("  Environmental score calculated using modified metrics\n")
    }
    
    fmt.Printf("\nFinal Environmental Score: %.1f\n", envScore)
}

Step-by-Step Calculation

go
func stepByStepEnvironmentalCalculation() {
    baseVector := "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
    envVector := baseVector + "/CR:H/IR:M/AR:L/MAV:L/MC:L"
    
    fmt.Println("=== Step-by-Step Environmental Calculation ===")
    fmt.Printf("Vector: %s\n\n", envVector)
    
    parser := parser.NewCvss3xParser(envVector)
    vector, _ := parser.Parse()
    
    calculator := cvss.NewCalculator(vector)
    
    // Step 1: Calculate modified base score
    fmt.Println("Step 1: Calculate Modified Base Score")
    fmt.Println("  Using modified metrics where provided:")
    fmt.Println("  - Modified Attack Vector: Local (instead of Network)")
    fmt.Println("  - Modified Confidentiality: Low (instead of High)")
    
    // Step 2: Apply environmental requirements
    fmt.Println("\nStep 2: Apply Environmental Requirements")
    fmt.Println("  - Confidentiality Requirement: High (1.5x)")
    fmt.Println("  - Integrity Requirement: Medium (1.0x)")
    fmt.Println("  - Availability Requirement: Low (0.5x)")
    
    // Step 3: Final calculation
    envScore, _ := calculator.CalculateEnvironmentalScore()
    fmt.Printf("\nStep 3: Final Environmental Score: %.1f\n", envScore)
}

Practical Applications

Risk Assessment by Environment

go
func assessRiskByEnvironment(baseVector string) {
    environments := []struct {
        name         string
        requirements string
        controls     string
        description  string
    }{
        {
            "Production DMZ",
            "/CR:H/IR:H/AR:H",
            "/MAV:A/MPR:L",
            "Internet-facing production with basic controls",
        },
        {
            "Internal Production",
            "/CR:H/IR:H/AR:H", 
            "/MAV:L/MPR:H/MUI:R",
            "Internal production with strong access controls",
        },
        {
            "Development Environment",
            "/CR:M/IR:M/AR:L",
            "/MAV:L/MPR:L",
            "Development environment with test data",
        },
        {
            "Isolated Test Lab",
            "/CR:L/IR:L/AR:L",
            "/MAV:L/MAC:H/MPR:H",
            "Isolated testing environment",
        },
    }

    fmt.Println("=== Risk Assessment by Environment ===")
    fmt.Printf("Base Vector: %s\n\n", baseVector)

    for _, env := range environments {
        vectorStr := baseVector + env.requirements + env.controls
        
        parser := parser.NewCvss3xParser(vectorStr)
        vector, _ := parser.Parse()
        
        calculator := cvss.NewCalculator(vector)
        score, _ := calculator.Calculate()
        severity := calculator.GetSeverityRating(score)

        fmt.Printf("Environment: %s\n", env.name)
        fmt.Printf("  Score: %.1f (%s)\n", score, severity)
        fmt.Printf("  Requirements: %s\n", env.requirements)
        fmt.Printf("  Controls: %s\n", env.controls)
        fmt.Printf("  Description: %s\n", env.description)
        fmt.Println()
    }
}

Control Effectiveness Analysis

go
func analyzeControlEffectiveness(baseVector string) {
    controls := []struct {
        control     string
        investment  string
        reduction   string
        description string
    }{
        {
            "Basic Firewall",
            "Low",
            "/MAV:A",
            "Network perimeter protection",
        },
        {
            "WAF + IPS",
            "Medium",
            "/MAV:A/MAC:H",
            "Web application firewall and intrusion prevention",
        },
        {
            "Zero Trust",
            "High",
            "/MAV:L/MPR:H/MUI:R",
            "Zero trust architecture implementation",
        },
        {
            "Full Security Stack",
            "Very High",
            "/MAV:L/MAC:H/MPR:H/MUI:R/MC:L/MI:L/MA:L",
            "Comprehensive security controls",
        },
    }

    fmt.Println("=== Control Effectiveness Analysis ===")
    fmt.Printf("Base Vector: %s\n\n", baseVector)

    // Calculate base score
    baseParser := parser.NewCvss3xParser(baseVector)
    baseParsed, _ := baseParser.Parse()
    baseCalc := cvss.NewCalculator(baseParsed)
    baseScore, _ := baseCalc.Calculate()

    fmt.Printf("Base Score: %.1f\n\n", baseScore)

    for _, control := range controls {
        vectorStr := baseVector + "/CR:H/IR:H/AR:H" + control.reduction
        
        parser := parser.NewCvss3xParser(vectorStr)
        vector, _ := parser.Parse()
        
        calculator := cvss.NewCalculator(vector)
        score, _ := calculator.Calculate()
        severity := calculator.GetSeverityRating(score)
        reduction := baseScore - score
        effectiveness := (reduction / baseScore) * 100

        fmt.Printf("Control: %s\n", control.control)
        fmt.Printf("  Investment: %s\n", control.investment)
        fmt.Printf("  Score: %.1f (%s)\n", score, severity)
        fmt.Printf("  Reduction: %.1f points (%.1f%% effective)\n", reduction, effectiveness)
        fmt.Printf("  Description: %s\n", control.description)
        fmt.Println()
    }
}

Testing and Validation

Environmental Metrics Validation

go
func validateEnvironmentalMetrics(vector *cvss.Cvss3x) []string {
    var issues []string

    if !vector.HasEnvironmental() {
        return issues
    }

    env := vector.Cvss3xEnvironmental

    // Validate requirement metrics
    if env.ConfidentialityRequirement != nil {
        value := env.ConfidentialityRequirement.GetShortValue()
        if value != 'X' && value != 'L' && value != 'M' && value != 'H' {
            issues = append(issues, fmt.Sprintf("Invalid Confidentiality Requirement: %c", value))
        }
    }

    if env.IntegrityRequirement != nil {
        value := env.IntegrityRequirement.GetShortValue()
        if value != 'X' && value != 'L' && value != 'M' && value != 'H' {
            issues = append(issues, fmt.Sprintf("Invalid Integrity Requirement: %c", value))
        }
    }

    if env.AvailabilityRequirement != nil {
        value := env.AvailabilityRequirement.GetShortValue()
        if value != 'X' && value != 'L' && value != 'M' && value != 'H' {
            issues = append(issues, fmt.Sprintf("Invalid Availability Requirement: %c", value))
        }
    }

    // Validate modified base metrics (similar validation as base metrics)
    // ... additional validation logic

    return issues
}

Environmental Scenarios Testing

go
func testEnvironmentalScenarios() {
    testCases := []struct {
        name        string
        vector      string
        expectError bool
        minScore    float64
        maxScore    float64
    }{
        {
            "High requirements only",
            "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H/CR:H/IR:H/AR:H",
            false,
            9.0,
            10.0,
        },
        {
            "Low requirements only",
            "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H/CR:L/IR:L/AR:L",
            false,
            5.0,
            8.0,
        },
        {
            "Strong controls",
            "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H/CR:H/IR:H/AR:H/MAV:L/MAC:H/MPR:H/MUI:R/MC:L/MI:L/MA:L",
            false,
            2.0,
            5.0,
        },
    }

    fmt.Println("=== Environmental Scenarios Testing ===")

    for _, tc := range testCases {
        fmt.Printf("\nTest: %s\n", tc.name)
        fmt.Printf("Vector: %s\n", tc.vector)

        parser := parser.NewCvss3xParser(tc.vector)
        vector, err := parser.Parse()

        if tc.expectError {
            if err != nil {
                fmt.Printf("✓ Expected error: %v\n", err)
            } else {
                fmt.Printf("✗ Expected error but parsing succeeded\n")
            }
        } else {
            if err != nil {
                fmt.Printf("✗ Unexpected error: %v\n", err)
            } else {
                calculator := cvss.NewCalculator(vector)
                score, _ := calculator.Calculate()
                
                if score >= tc.minScore && score <= tc.maxScore {
                    fmt.Printf("✓ Score %.1f within expected range [%.1f-%.1f]\n", 
                        score, tc.minScore, tc.maxScore)
                } else {
                    fmt.Printf("✗ Score %.1f outside expected range [%.1f-%.1f]\n", 
                        score, tc.minScore, tc.maxScore)
                }
            }
        }
    }
}

Next Steps

After mastering environmental metrics, you can explore:

Released under the MIT License.