📊 Score Breakdown
📊 Feature · pkg/cvss
GetScoreBreakdown returns the effective score contributed by every metric on a *Cvss3x, after the context adjustments the spec applies to PR (Scope) and UI (version). Together with AllScores.AsMap, it gives you both a structured per-metric view and a flat map[string]float64 for serialization.
Synopsis
calc := cvss.NewCalculator(cv)
bd, err := calc.GetScoreBreakdown() // each MetricScore has ShortName/LongName/Value/Score
fmt.Println(bd.AttackVector.String()) // AV:N=0.85A MetricScore records the short name (AV), long name (Attack Vector), value (N), and the score that value actually earns in this vector's context. ScoreBreakdown is a plain struct with one MetricScore field per CVSS metric; unset metrics come back as zero-valued MetricScore{} (empty ShortName).
How It Works
GetScoreBreakdown validates the vector, then fills Base metrics directly from each Vector.GetScore() — except PR (adjusted by Scope via GetPrivilegesRequiredScore) and UI (adjusted by version via GetUserInteractionScore). Temporal/Environmental Modified metrics use the same Scope/version-aware helpers against the modified scope.
API Reference
MetricScore
type MetricScore struct {
ShortName string // e.g. "AV"
LongName string // e.g. "Attack Vector"
Value string // e.g. "N"
Score float64 // effective score, context-adjusted for PR/UI
}
func (m MetricScore) String() string // "AV:N=0.85"ScoreBreakdown
type ScoreBreakdown struct {
// Base
AttackVector, AttackComplexity, PrivilegesRequired,
UserInteraction, Scope, Confidentiality, Integrity, Availability MetricScore
// Temporal
ExploitCodeMaturity, RemediationLevel, ReportConfidence MetricScore
// Environmental requirements
ConfidentialityRequirement, IntegrityRequirement, AvailabilityRequirement MetricScore
// Modified metrics
ModifiedAttackVector, ModifiedAttackComplexity, ModifiedPrivilegesRequired,
ModifiedUserInteraction, ModifiedScope, ModifiedConfidentiality,
ModifiedIntegrity, ModifiedAvailability MetricScore
}GetScoreBreakdown
func (c *Calculator) GetScoreBreakdown() (*ScoreBreakdown, error)Returns the breakdown. It first runs cv.Check(), so an incomplete base vector surfaces its error here. The PrivilegesRequired score is computed with vector.GetPrivilegesRequiredScore(pr, scopeChanged) and UserInteraction with vector.GetUserInteractionScore(ui, minorVersion) — the two metrics whose value depends on context.
bd, err := calc.GetScoreBreakdown()
fmt.Printf("PR=%.2f UI=%.2f\n", bd.PrivilegesRequired.Score, bd.UserInteraction.Score)PR and UI are context-adjusted
PR depends on Scope: PR:L is 0.62 under Scope Unchanged but 0.68 under Scope Changed (PR:N is 0.85 regardless). UI:R depends on version: 0.56 in v3.0, 0.62 in v3.1 (UI:N is 0.85 in both). GetScoreBreakdown always returns the value effective for this vector.
AllScores.AsMap
func (s *AllScores) AsMap() map[string]float64Flattens an *AllScores into a map[string]float64 keyed baseScore, impactSubScore, exploitabilitySubScore, plus temporalScore (only when temporal metrics exist) and environmentalScore, modifiedImpactSubScore, modifiedExploitabilitySubScore (only when environmental metrics exist). Convenient for JSON/template rendering.
m := all.AsMap()
// {"baseScore":9.8, "impactSubScore":5.87, "exploitabilitySubScore":3.89}AsMap omits absent keys
temporalScore is absent (not 0) when no temporal metrics are set, and the three modified* keys are absent without environmental metrics. Check presence with the comma-ok form, not against zero.
Example
package main
import (
"encoding/json"
"fmt"
"github.com/scagogogo/cvss-skills/pkg/cvss"
"github.com/scagogogo/cvss-skills/pkg/parser"
)
func main() {
cv, err := parser.ParseString(
"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H")
if err != nil {
panic(err)
}
calc := cvss.NewCalculator(cv)
bd, err := calc.GetScoreBreakdown()
if err != nil {
panic(err)
}
// PR and UI are context-adjusted; AV/AC/C/I/A use the metric's own score.
for _, m := range []cvss.MetricScore{
bd.AttackVector, bd.PrivilegesRequired, bd.UserInteraction, bd.Confidentiality,
} {
fmt.Println(m.String())
}
// AsMap gives a serialization-friendly view of the aggregate scores.
all, err := calc.GetAllScores()
if err != nil {
panic(err)
}
raw, _ := json.MarshalIndent(all.AsMap(), "", " ")
fmt.Println(string(raw))
}Running against CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H, the CLI's score --breakdown reports the same per-metric numbers, e.g. AV:N = 0.85, PR:N = 0.85, UI:N = 0.85, C:H = 0.56.
Related
- Scoring (calculator) —
GetScoreBreakdownlives on*Calculator - Scores —
AllScoresandGetAllScores, the source ofAsMap - Impact & Sensitivity — sensitivity analysis built on per-metric scores
- CLI:
score --breakdownandsubs