Run2 vulnerability csv reporting
Generate structured CSV security audit reports from Trivy JSON output with severity filtering, deduplication, and proper field mapping.From its SKILL.md
npx -y skills add cxcscmu/SkillLearnBench --skill run2_vulnerability-csv-reportingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
SKILL.md
3.4 KB, 876 tokens by cl100k_base, as published. Nobody here has run it
Vulnerability CSV Reporting (Round 2)
CSV Schema (exact column names required)
Package,Version,CVE_ID,Severity,CVSS_Score,Fixed_Version,Title,Url
Complete, Production-Ready Script
import json, csv, sys
def get_cvss_score(vuln):
"""Extract CVSS v3 score: NVD > GHSA > RedHat > N/A"""
cvss = vuln.get('CVSS', {})
if not isinstance(cvss, dict):
return 'N/A'
for source in ['nvd', 'ghsa', 'redhat']:
entry = cvss.get(source, {})
if isinstance(entry, dict):
score = entry.get('V3Score')
if score is not None and isinstance(score, (int, float)):
return score
return 'N/A'
def generate_csv(json_input, csv_output, severities=('HIGH', 'CRITICAL')):
with open(json_input, encoding='utf-8') as f:
data = json.load(f)
records = []
seen = set() # Deduplicate by (package, version, CVE)
for result in data.get('Results', []):
for vuln in (result.get('Vulnerabilities') or []): # Handle None
severity = vuln.get('Severity', '')
if severity not in severities:
continue
key = (vuln.get('PkgName'), vuln.get('InstalledVersion'), vuln.get('VulnerabilityID'))
if key in seen:
continue
seen.add(key)
records.append({
'Package': vuln.get('PkgName') or 'N/A',
'Version': vuln.get('InstalledVersion') or 'N/A',
'CVE_ID': vuln.get('VulnerabilityID') or 'N/A',
'Severity': severity,
'CVSS_Score': get_cvss_score(vuln),
'Fixed_Version': vuln.get('FixedVersion') or 'N/A', # handles None AND ""
'Title': vuln.get('Title') or 'N/A',
'Url': vuln.get('PrimaryURL') or 'N/A',
})
headers = ['Package', 'Version', 'CVE_ID', 'Severity',
'CVSS_Score', 'Fixed_Version', 'Title', 'Url']
with open(csv_output, 'w', newline='', encoding='utf-8') as f:
writer = csv.DictWriter(f, fieldnames=headers)
writer.writeheader()
writer.writerows(records)
print(f"[+] Wrote {len(records)} HIGH/CRITICAL records to {csv_output}")
return records
if __name__ == '__main__':
generate_csv('/root/trivy_report.json', '/root/security_audit.csv')
Key Improvements Over Round 1
- Deduplication: Use a
seenset to avoid duplicate (pkg, version, CVE) entries - Null safety:
result.get('Vulnerabilities') or []handlesNoneVulnerabilities - Empty string fix:
vuln.get('FixedVersion') or 'N/A'catches bothNoneand"" - Type safety: Added
isinstancechecks in CVSS extraction - Encoding: Always use
encoding='utf-8'for both read and write
Field Mapping Reference
| CSV Column | Trivy JSON Field | Notes |
|---|---|---|
| Package | PkgName | Package name |
| Version | InstalledVersion | Installed version string |
| CVE_ID | VulnerabilityID | CVE/GHSA identifier |
| Severity | Severity | HIGH or CRITICAL (filtered) |
| CVSS_Score | CVSS.{source}.V3Score | Via priority extraction |
| Fixed_Version | FixedVersion | Empty/None → 'N/A' |
| Title | Title | Short description |
| Url | PrimaryURL | AVD/NVD reference link |
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.