Vulnerability Report Skill
When generating vulnerability reports, scan all project dependencies for known CVEs, categorize findings by severity, and produce three separate reports — one for each severity tier. Each report is a standalone document with full context, remediation steps, and priority guidance.
IMPORTANT: Always save THREE markdown files to the project-decisions/ directory:
-
YYYY-MM-DD-vulnerabilities-high.md — Critical and High severity (CVSS ≥ 7.0)
-
YYYY-MM-DD-vulnerabilities-medium.md — Medium severity (CVSS 4.0–6.9)
-
YYYY-MM-DD-vulnerabilities-low.md — Low and Informational (CVSS < 4.0)
- Output Setup
mkdir -p project-decisions
Files will be saved as:
project-decisions/YYYY-MM-DD-vulnerabilities-high.md
project-decisions/YYYY-MM-DD-vulnerabilities-medium.md
project-decisions/YYYY-MM-DD-vulnerabilities-low.md
- Dependency Discovery
Detect Package Ecosystem
Detect all package managers in use
echo "=== Package Ecosystems Detected ==="
Node.js / JavaScript / TypeScript
ls package.json package-lock.json yarn.lock pnpm-lock.yaml bun.lockb 2>/dev/null && echo "→ Node.js detected"
Python
ls requirements.txt Pipfile pyproject.toml poetry.lock setup.py setup.cfg 2>/dev/null && echo "→ Python detected"
Go
ls go.mod go.sum 2>/dev/null && echo "→ Go detected"
Ruby
ls Gemfile Gemfile.lock 2>/dev/null && echo "→ Ruby detected"
PHP
ls composer.json composer.lock 2>/dev/null && echo "→ PHP detected"
Rust
ls Cargo.toml Cargo.lock 2>/dev/null && echo "→ Rust detected"
Java
ls pom.xml build.gradle build.gradle.kts 2>/dev/null && echo "→ Java detected"
.NET
ls *.csproj *.sln packages.config 2>/dev/null && echo "→ .NET detected"
Docker (base image vulnerabilities)
ls Dockerfile Dockerfile.* docker-compose.yml 2>/dev/null && echo "→ Docker detected"
Inventory Dependencies
Node.js — count direct and transitive
echo "=== Node.js Dependencies ===" echo "Direct dependencies: $(cat package.json 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d.get('dependencies',{})))" 2>/dev/null || echo "N/A")" echo "Dev dependencies: $(cat package.json 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d.get('devDependencies',{})))" 2>/dev/null || echo "N/A")" echo "Total installed: $(ls node_modules/ 2>/dev/null | wc -l || echo "N/A")"
Python
echo "=== Python Dependencies ===" pip list --format=columns 2>/dev/null | wc -l || echo "N/A" cat requirements.txt 2>/dev/null | grep -v "^#|^$" | wc -l || echo "N/A"
Go
echo "=== Go Dependencies ===" cat go.sum 2>/dev/null | awk '{print $1}' | sort -u | wc -l || echo "N/A"
Ruby
echo "=== Ruby Dependencies ===" cat Gemfile.lock 2>/dev/null | grep " [a-z]" | wc -l || echo "N/A"
PHP
echo "=== PHP Dependencies ===" cat composer.lock 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d.get('packages',[])))" 2>/dev/null || echo "N/A"
- Vulnerability Scanning
Node.js / npm
Full npm audit with JSON output
npm audit --json 2>/dev/null > /tmp/npm-audit-output.json
Parse audit results
cat /tmp/npm-audit-output.json | python3 -c " import sys, json try: data = json.load(sys.stdin)
# npm v7+ format
if 'vulnerabilities' in data:
vulns = data['vulnerabilities']
for name, info in sorted(vulns.items(), key=lambda x: {'critical':0,'high':1,'moderate':2,'low':3,'info':4}.get(x[1].get('severity','info'), 5)):
severity = info.get('severity', 'unknown')
via = info.get('via', [])
fix = info.get('fixAvailable', False)
range_affected = info.get('range', 'unknown')
# Get CVE details from via
cves = []
if isinstance(via, list):
for v in via:
if isinstance(v, dict):
cves.append({
'title': v.get('title', 'N/A'),
'url': v.get('url', ''),
'severity': v.get('severity', severity),
'cwe': v.get('cwe', []),
'cvss': v.get('cvss', {}).get('score', 'N/A'),
'range': v.get('range', range_affected)
})
print(f'PACKAGE: {name}')
print(f' Severity: {severity.upper()}')
print(f' Affected: {range_affected}')
print(f' Fix Available: {fix}')
for cve in cves:
print(f' CVE Title: {cve[\"title\"]}')
print(f' CVSS Score: {cve[\"cvss\"]}')
print(f' URL: {cve[\"url\"]}')
print(f' CWE: {cve[\"cwe\"]}')
print()
# Summary
metadata = data.get('metadata', {}).get('vulnerabilities', {})
print('=== SUMMARY ===')
print(f'Critical: {metadata.get(\"critical\", 0)}')
print(f'High: {metadata.get(\"high\", 0)}')
print(f'Moderate: {metadata.get(\"moderate\", 0)}')
print(f'Low: {metadata.get(\"low\", 0)}')
print(f'Info: {metadata.get(\"info\", 0)}')
print(f'Total: {metadata.get(\"total\", 0)}')
except Exception as e: print(f'Error parsing: {e}', file=sys.stderr) " 2>/dev/null
Also check with npm audit fix --dry-run to see what's auto-fixable
npm audit fix --dry-run 2>/dev/null | tail -20
Node.js / yarn
Yarn audit
yarn audit --json 2>/dev/null | head -100
Node.js / pnpm
pnpm audit
pnpm audit --json 2>/dev/null | head -100
Python / pip
pip-audit (preferred)
pip install pip-audit --break-system-packages 2>/dev/null pip-audit --format=json 2>/dev/null > /tmp/pip-audit-output.json cat /tmp/pip-audit-output.json | python3 -c " import sys, json try: data = json.load(sys.stdin) for vuln in data: name = vuln.get('name', 'unknown') version = vuln.get('version', 'unknown') vulns = vuln.get('vulns', []) for v in vulns: print(f'PACKAGE: {name}=={version}') print(f' ID: {v.get("id", "N/A")}') print(f' Fix Versions: {v.get("fix_versions", [])}') print(f' Description: {v.get("description", "N/A")[:200]}') print() except Exception as e: print(f'Error: {e}', file=sys.stderr) " 2>/dev/null
Safety check (alternative)
pip install safety --break-system-packages 2>/dev/null safety check --json 2>/dev/null | head -100
Go
govulncheck
go install golang.org/x/vuln/cmd/govulncheck@latest 2>/dev/null govulncheck ./... 2>/dev/null
Ruby
bundler-audit
gem install bundler-audit 2>/dev/null bundle-audit check --update 2>/dev/null
PHP
Composer audit
composer audit --format=json 2>/dev/null | head -100
Docker Base Images
Check Dockerfile base images
echo "=== Docker Base Images ===" grep "^FROM" Dockerfile Dockerfile.* 2>/dev/null
Check if base images are pinned
grep "^FROM" Dockerfile 2>/dev/null | while read line; do image=$(echo "$line" | awk '{print $2}') echo "$image" | grep -q ":" || echo "⚠️ UNPINNED: $image (using :latest implicitly)" echo "$image" | grep -q ":latest" && echo "⚠️ UNPINNED: $image (using :latest explicitly)" echo "$image" | grep -qE ":[0-9]" && echo "✅ PINNED: $image" echo "$image" | grep -qE "@sha256:" && echo "✅ DIGEST PINNED: $image" done
Lockfile Integrity
Check lockfiles exist and are committed
echo "=== Lockfile Status ===" for lockfile in package-lock.json yarn.lock pnpm-lock.yaml Pipfile.lock poetry.lock Gemfile.lock composer.lock Cargo.lock go.sum; do if [ -f "$lockfile" ]; then if git ls-files --error-unmatch "$lockfile" >/dev/null 2>&1; then echo "✅ $lockfile — committed" else echo "⚠️ $lockfile — exists but NOT committed to git" fi fi done
Check for unpinned versions in package.json
echo "" echo "=== Unpinned Versions ===" cat package.json 2>/dev/null | python3 -c " import sys, json data = json.load(sys.stdin) for section in ['dependencies', 'devDependencies']: deps = data.get(section, {}) for name, version in deps.items(): if version.startswith('^') or version.startswith('~') or version == '*' or version == 'latest': print(f' {section}/{name}: {version}') " 2>/dev/null
- Vulnerability Classification
Severity Mapping
Map each finding to a consistent severity:
Source Critical High Medium Low
npm audit critical high moderate low
pip-audit/safety CVSS ≥ 9.0 CVSS 7.0-8.9 CVSS 4.0-6.9 CVSS < 4.0
bundler-audit critical high medium low
govulncheck Map from CVSS Map from CVSS Map from CVSS Map from CVSS
Composer critical high medium low
CVSS v3.1 9.0-10.0 7.0-8.9 4.0-6.9 0.1-3.9
Enrichment Per Vulnerability
For each vulnerability found, gather:
- Package name and installed version
- Vulnerability ID (CVE, GHSA, OSV)
- CVSS score and vector
- CWE classification
- Severity (Critical/High/Medium/Low)
- Description of the vulnerability
- Affected version range
- Fixed version (if available)
- Is it a direct or transitive dependency?
- Is the vulnerable code reachable from our code?
- Exploit availability (PoC exists? actively exploited?)
- Fix available? (auto-fixable with npm audit fix?)
- Remediation steps
Reachability Analysis
Check if vulnerable package is directly imported (higher risk)
vs only a transitive dependency (lower risk)
for pkg in [list-of-vulnerable-packages]; do echo "=== $pkg ==="
Direct dependency?
cat package.json 2>/dev/null | grep ""$pkg"" && echo " → DIRECT dependency"
Imported in source code?
grep -rn "import.$pkg|require.$pkg|from '$pkg'|from "$pkg"" --include=".ts" --include=".js" --include="*.py" src/ app/ 2>/dev/null && echo " → DIRECTLY USED in source code"
Only transitive?
npm ls "$pkg" 2>/dev/null | head -5 done
- Report Generation
Generate THREE separate reports, one for each severity tier:
Report 1: Critical & High Vulnerabilities
File: project-decisions/YYYY-MM-DD-vulnerabilities-high.md
Audience: Security team, engineering leads, management — requires immediate action
🔴 Vulnerability Report: Critical & High Severity
Project: [Project Name] Scan Date: YYYY-MM-DD Scanned By: [Name / Automated] Ecosystems Scanned: [npm, pip, Go, Ruby, PHP, Docker] Action Required: 🔴 IMMEDIATE — Fix within 48 hours
Executive Summary
| Metric | Value |
|---|---|
| Critical vulnerabilities | X |
| High vulnerabilities | X |
| Total in this report | X |
| Auto-fixable | X (Y%) |
| Requires manual fix | X (Y%) |
| No fix available | X (Y%) |
| Direct dependencies affected | X |
| Transitive dependencies affected | X |
Risk Assessment
Overall Risk: [🔴 Critical / 🟠 High]
[2-3 sentences: what's the worst case if these aren't fixed? Are any actively exploited? Is sensitive data at risk?]
Quick Fix Commands
Run these immediately to fix auto-fixable vulnerabilities:
# Node.js — auto-fix what's possible
npm audit fix
# If breaking changes are acceptable
npm audit fix --force
# Python — upgrade to fixed versions
pip install --upgrade [package1] [package2] --break-system-packages
# Ruby
bundle update [gem1] [gem2]
# PHP
composer update [package1] [package2]
After running fixes, re-scan:
npm audit
pip-audit
Detailed Findings
VULN-001: [Package Name] — [Vulnerability Title]
| Field | Value |
|---|---|
| Package | [package-name] |
| Installed Version | X.Y.Z |
| Severity | 🔴 Critical |
| CVSS Score | X.X |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| CVE | CVE-YYYY-XXXXX |
| CWE | CWE-XXX — [Name] |
| GHSA | GHSA-xxxx-xxxx-xxxx |
| Dependency Type | Direct / Transitive |
| Reachable | Yes — imported in src/services/auth.ts / No — transitive only |
| Exploit Available | Yes — PoC published / No known exploit |
| Actively Exploited | Yes — in the wild / No |
| Affected Versions | >= X.Y.Z, < A.B.C |
| Fixed Version | A.B.C |
| Fix Available | ✅ Yes — upgrade to A.B.C / ❌ No fix yet |
| Auto-Fixable | ✅ npm audit fix / ❌ Manual intervention required |
Description: [What the vulnerability allows an attacker to do. How it could be exploited in the context of THIS project.]
Impact on This Project: [Specific to YOUR codebase — is the vulnerable function actually called? Is the attack vector reachable? What data is at risk?]
Dependency Chain:
your-project └── [direct-dependency]@X.Y.Z └── [vulnerable-package]@A.B.C ← VULNERABLE