fix(security): parse CVSS v2 fallback and return UNKNOWfix(security): parse CVSS v2 fallback and return UNKNOWN for unscored CVEs #385N for unscored…#450
Conversation
📝 WalkthroughWalkthroughFixes ChangesCVSS Score Severity Parsing
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
internal/analyzer/security_scan_test.go (1)
5-116: ⚡ Quick winAdd regression cases for invalid-v3-with-valid-v2 and explicit 0.0 (
NONE).Current table misses the key edge where
CVSS_V3exists but is unparsable whileCVSS_V2is valid, plus the explicit zero-score path. Adding both would lock in the intended precedence/fallback contract.Suggested additional test rows
{ + name: "Invalid CVSS V3 falls back to valid V2", + vuln: osvVuln{ + Severity: []struct { + Type string `json:"type"` + Score string `json:"score"` + }{ + {Type: "CVSS_V3", Score: "not-a-score"}, + {Type: "CVSS_V2", Score: "9.0"}, + }, + }, + expected: "CRITICAL", + }, + { + name: "Explicit zero score maps to NONE", + vuln: osvVuln{ + Severity: []struct { + Type string `json:"type"` + Score string `json:"score"` + }{ + {Type: "CVSS_V3", Score: "0.0"}, + }, + }, + expected: "NONE", + }, + { name: "No Score Unknown",🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/analyzer/security_scan_test.go` around lines 5 - 116, Add two regression test cases to TestGetSeverity in security_scan_test.go: one named "Invalid V3 with Valid V2" where osvVuln.Severity contains a CVSS_V3 entry with an unparsable Score (e.g., non-numeric) and a valid CVSS_V2 entry (numeric) to verify getSeverity() falls back to CVSS_V2; and one named "Explicit 0.0 NONE" where osvVuln.Severity contains a CVSS_V3 entry with Score "0.0" (or equivalent) to verify getSeverity() returns "NONE" for zero score; place them alongside the other test cases so they exercise getSeverity(osvVuln) behavior and assert the expected strings.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/analyzer/security_scan.go`:
- Around line 171-186: The current logic marks hasV3 purely by seeing s.Type ==
"CVSS_V3" so a malformed/unparseable v3 score (parseCvssScore failing) still
forces the v3 branch and blocks v2 fallback; change the flow in the loop that
handles s.Type to set hasV3/hasV2 only when parseCvssScore actually returns a
valid score (e.g., non-empty/non-NaN/parse-success) and assign v3Score/v2Score
accordingly, and update the selection logic before returning so it prefers v3
only if v3Score was successfully parsed, otherwise falls back to a valid v2Score
(and only return "UNKNOWN" if neither parsed successfully).
---
Nitpick comments:
In `@internal/analyzer/security_scan_test.go`:
- Around line 5-116: Add two regression test cases to TestGetSeverity in
security_scan_test.go: one named "Invalid V3 with Valid V2" where
osvVuln.Severity contains a CVSS_V3 entry with an unparsable Score (e.g.,
non-numeric) and a valid CVSS_V2 entry (numeric) to verify getSeverity() falls
back to CVSS_V2; and one named "Explicit 0.0 NONE" where osvVuln.Severity
contains a CVSS_V3 entry with Score "0.0" (or equivalent) to verify
getSeverity() returns "NONE" for zero score; place them alongside the other test
cases so they exercise getSeverity(osvVuln) behavior and assert the expected
strings.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 29cf3d75-1b8f-43d9-a338-01a559f5f6ed
📒 Files selected for processing (2)
internal/analyzer/security_scan.gointernal/analyzer/security_scan_test.go
Contributed as part of GSSoC '26.
Problem Description
The
getSeverityfunction ininternal/analyzer/security_scan.gopreviously defaulted any un-scored, text-only, or older vulnerability records that lacked a CVSS v3 metrics block directly to"MEDIUM". This silently downgraded older historical CVEs that might be highly critical (9.0+ base score under CVSS v2), leading to skewed risk calculations and potentially exposing users to unmitigated supply chain risks. Fixes #385.Solution Implemented
getSeverityto scan for"CVSS_V2"data schemas when"CVSS_V3"fields are unavailable. If both are found, CVSS v3 dynamically retains precedence.9.0 - 10.0→"CRITICAL"7.0 - 8.9→"HIGH"4.0 - 6.9→"MEDIUM"0.1 - 3.9→"LOW""MEDIUM"fallback with"UNKNOWN"for unscored, un-vectored, or text-only entries.GetSeverityEmojito dynamically include support for the new"UNKNOWN"severity string utilizing a clean, neutral⚪identifier.internal/analyzer/security_scan_test.gochecking all conditions: CVSS v3 parsing, CVSS v2 fallback matching, proper precedence prioritization, and correct resolution of text-only records to"UNKNOWN".Verification & Test Logs
Validated locally via Go's testing toolchain with zero failures:
TestGetSeverity/CVSS_V3_High: PASSEDTestGetSeverity/CVSS_V2_Fallback_High: PASSEDTestGetSeverity/CVSS_V2_Fallback_Medium: PASSEDTestGetSeverity/CVSS_V2_Fallback_Low: PASSEDTestGetSeverity/CVSS_V3_Precedence_over_V2: PASSEDTestGetSeverity/No_Score_Unknown: PASSEDTestGetSeverity/Text-only_record_Unknown: PASSEDSummary by CodeRabbit