Description
Currently, findings generated by Semgrep, OSV-Scanner, and Gitleaks are displayed in the order returned by each scanner. This order does not reflect the actual security risk, forcing users to manually inspect severity values across different scanner formats before deciding which issues to fix first.
This issue introduces the first component of the Machine Learning Tier 1 – Intelligent Triage pipeline by assigning a normalized severity score (0–10) to every finding. Although the initial implementation is deterministic, it establishes the labeled dataset required for future ML-based prioritization models.
Once implemented, every finding will contain a standardized numerical severity score regardless of its originating scanner, enabling consistent sorting, filtering, and downstream ML training.
Problem Statement
Each scanner represents severity differently:
-
OSV-Scanner
- Uses CVSS scores embedded inside vulnerability metadata.
- Example:
{
"severity": [
{
"type": "CVSS_V3",
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
}
]
}
-
Semgrep
- Uses categorical severity labels.
{
"extra": {
"severity": "ERROR"
}
}
-
Gitleaks
- Uses confidence values instead of CVSS.
{
"RuleID": "...",
"Confidence": "HIGH"
}
Because these formats are inconsistent:
- High-risk vulnerabilities may appear below informational findings.
- Users cannot quickly identify the most critical issues.
- Later ML ranking models have no normalized training labels.
- Dashboard sorting becomes unreliable.
Proposed Solution
Create a new ranking module:
backend/
└── app/
└── ml/
└── severity_ranker.py
Expose a public API:
def rank(findings: list[dict]) -> list[dict]:
...
The function should:
- Inspect each finding.
- Detect which scanner produced it.
- Extract the highest-confidence severity metadata.
- Convert it into a normalized float between 0–10.
- Add
to every finding.
Example:
{
"scanner": "semgrep",
"rule_id": "python.lang.security.audit.eval",
"severity_score": 9.0
}
Severity Derivation Priority
The score should be derived using the following priority:
1. OSV Scanner (Highest Priority)
Extract CVSS score from
finding["severity"][0]["score"]
Example:
"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
Use the cvss Python package to parse the vector and obtain the numeric base score.
Example:
2. Semgrep
Read
finding["extra"]["severity"]
Map values:
| Semgrep Severity |
Score |
| ERROR |
9 |
| WARNING |
6 |
| INFO |
3 |
Unknown values should default to 5.
3. Gitleaks
Read
Mapping:
| Confidence |
Score |
| HIGH |
8 |
| MEDIUM |
5 |
| LOW |
2 |
4. Fallback
If none of the above metadata exists:
Database Changes
Extend the findings table:
ALTER TABLE findings
ADD COLUMN severity_score REAL DEFAULT 5.0;
Every persisted finding should include:
API Changes
The following endpoints should return findings ordered by severity:
Sorting:
ORDER BY severity_score DESC
or
sorted(findings,
key=lambda x: x["severity_score"],
reverse=True)
Unit Tests
Create
backend/tests/test_severity_ranker.py
Tests should verify:
✅ OSV CVSS Parsing
Input:
{
"severity":[
{
"score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
}
]
}
Expected:
✅ Semgrep Mapping
ERROR → 9
WARNING → 6
INFO → 3
✅ Gitleaks Mapping
HIGH → 8
MEDIUM → 5
LOW → 2
✅ Fallback
Missing metadata should produce
✅ Sorting
Provide multiple findings and ensure:
is returned in descending order.
Dependencies
Add:
to
backend/requirements-ml.txt
or
depending on project structure.
Acceptance Criteria
Expected Impact
- 📊 Prioritizes critical findings automatically.
- ⚡ Enables users to focus on high-risk vulnerabilities first.
- 🧠 Provides normalized labels for future ML ranking models.
- 📈 Improves dashboard sorting and filtering.
- 🔄 Establishes the foundation for Tier 2 intelligent remediation and recommendation models.
Difficulty
Medium
Estimated Time: 4–6 hours
Skills Required:
- Python
- FastAPI
- SQLite
- Unit Testing (
pytest)
- Basic understanding of CVSS and security scanner outputs
Description
Currently, findings generated by Semgrep, OSV-Scanner, and Gitleaks are displayed in the order returned by each scanner. This order does not reflect the actual security risk, forcing users to manually inspect severity values across different scanner formats before deciding which issues to fix first.
This issue introduces the first component of the Machine Learning Tier 1 – Intelligent Triage pipeline by assigning a normalized severity score (0–10) to every finding. Although the initial implementation is deterministic, it establishes the labeled dataset required for future ML-based prioritization models.
Once implemented, every finding will contain a standardized numerical severity score regardless of its originating scanner, enabling consistent sorting, filtering, and downstream ML training.
Problem Statement
Each scanner represents severity differently:
OSV-Scanner
{ "severity": [ { "type": "CVSS_V3", "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" } ] }Semgrep
{ "extra": { "severity": "ERROR" } }Gitleaks
{ "RuleID": "...", "Confidence": "HIGH" }Because these formats are inconsistent:
Proposed Solution
Create a new ranking module:
Expose a public API:
The function should:
severity_scoreto every finding.
Example:
{ "scanner": "semgrep", "rule_id": "python.lang.security.audit.eval", "severity_score": 9.0 }Severity Derivation Priority
The score should be derived using the following priority:
1. OSV Scanner (Highest Priority)
Extract CVSS score from
Example:
"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"Use the cvss Python package to parse the vector and obtain the numeric base score.
Example:
2. Semgrep
Read
Map values:
Unknown values should default to 5.
3. Gitleaks
Read
Mapping:
4. Fallback
If none of the above metadata exists:
Database Changes
Extend the findings table:
Every persisted finding should include:
API Changes
The following endpoints should return findings ordered by severity:
/scan/scan-urlSorting:
or
Unit Tests
Create
Tests should verify:
✅ OSV CVSS Parsing
Input:
{ "severity":[ { "score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" } ] }Expected:
✅ Semgrep Mapping
✅ Gitleaks Mapping
✅ Fallback
Missing metadata should produce
✅ Sorting
Provide multiple findings and ensure:
is returned in descending order.
Dependencies
Add:
to
or
depending on project structure.
Acceptance Criteria
backend/app/ml/severity_ranker.pyrank(findings: list[dict])cvsspackage5.0severity_scoreto every findingseverity_scorein SQLiteseverity_scoreExpected Impact
Difficulty
Medium
Estimated Time: 4–6 hours
Skills Required:
pytest)